Commit Graph

49 Commits

Author SHA1 Message Date
Houmgaor
dbbfb927f8 feat(guild): separate scout invitations into guild_invites table
Scout invitations were stored in guild_applications with type 'invited',
forcing the scout list response to use charID as the invitation ID — a
known hack that made CancelGuildScout semantically incorrect.

Introduce a dedicated guild_invites table (migration 0012) with a serial
PK. The scout list now returns real invite IDs and actual InvitedAt
timestamps. CancelGuildScout cancels by PK. AcceptInvite and DeclineInvite
operate on guild_invites while player-applied applications remain in
guild_applications unchanged.
2026-03-21 17:59:25 +01:00
Houmgaor
366aad0172 docs(changelog): document Diva Defense system with attribution 2026-03-20 17:55:04 +01:00
Houmgaor
7ff033e36e docs(changelog): remove fix entries already covered by Added section
The rengoku/loadQuestFile fix notes were redundant — the behaviour is
already documented under the JSON loader Added entries.
2026-03-20 17:12:41 +01:00
Houmgaor
fec2793ccc docs: document JSON format support in README and CHANGELOG
Add a JSON Format Support section to the README covering quests,
scenarios, and Hunting Road config. Add two missing CHANGELOG entries
for the rengoku .bin-first fix and the quest event board JSON fallback.
2026-03-20 16:41:36 +01:00
Houmgaor
a1dfdd330a feat(scenario): add JSON scenario support and JKR type-3 compressor
Closes #172. Scenario files in bin/scenarios/ can now be authored as
.json instead of .bin — the server compiles them to wire format on
load, falling back to .bin if no .json is present.

- Add ParseScenarioBinary / CompileScenarioJSON in scenario_json.go;
  supports sub-header format (strings as UTF-8, metadata as base64),
  inline format, and raw JKR blobs.
- Add PackSimple JKR type-3 (LZ77) compressor in jpk_compress.go,
  ported from ReFrontier JPKEncodeLz.cs; round-trip tested against
  UnpackSimple.
- Fix off-by-one in processDecode (jpk.go): last literal byte was
  silently dropped for data that does not end on a back-reference.
- Wire loadScenarioBinary into handleMsgSysGetFile replacing the
  inline os.ReadFile call; mirrors the existing loadQuestBinary pattern.
- Rewrite docs/scenario-format.md with full container/sub-header spec
  and JSON schema examples.
2026-03-20 13:55:40 +01:00
Houmgaor
71b675bf3e docs: rename AUTHORS.md to HISTORY.md and update references
The file documents project lineage and development phases, not just
a flat list of authors — HISTORY.md is a more accurate name and
follows common open-source convention.
2026-03-20 11:56:19 +01:00
Houmgaor
e7180deb77 docs(changelog): reorder Unreleased sections to Added before Fixed 2026-03-20 11:49:27 +01:00
Houmgaor
34f0e89e7b fix(savedata): guard against sub-minimum backup data in recovery
nullcomp's passthrough path returns non-cmp-header data as-is without
error, which is correct for old uncompressed saves. However, a corrupt
backup slot containing garbage shorter than the minimum save layout
(100 bytes) would pass Decompress() and then panic in
updateStructWithSaveData() with a slice-bounds error at the name field
read (offset 88–100).

Add a minSaveSize check after each backup decompresses; skip the slot
if the result is too small. Also document the campaign system and the
fix in CHANGELOG under Unreleased.
2026-03-20 11:46:01 +01:00
Houmgaor
97ef09be64 docs(changelog): add rengoku JSON config to Unreleased 2026-03-20 00:08:48 +01:00
Houmgaor
6139e90968 docs(changelog): add quest JSON feature to Unreleased 2026-03-19 18:23:46 +01:00
Houmgaor
90948bfb71 chore(release): prepare 9.3.0
Promote [Unreleased] to [9.3.0] - 2026-03-19 in CHANGELOG and mark
the bookshelf save pointer fix as Done in improvements.md (it was
applied post-RC1 but the doc still said Pending).
2026-03-19 15:18:33 +01:00
Houmgaor
39d93f6eed docs(changelog): log G-rank Workshop/Cog softlock fix (#180) 2026-03-19 14:37:11 +01:00
Houmgaor
a6025be8b7 fix(festa): filter trials and rewards for Forward.5 compatibility (#156)
Skip trials referencing monsters added after em106 (Odibatorasu, the
last F5 monster) and filter out item 7011 which does not exist before
G1, preventing client crashes on Forward.4/5 servers.

Also logs the pre-existing bookshelf save data pointer fix (already
applied during the savedata refactor) in the CHANGELOG.
2026-03-18 23:19:25 +01:00
Houmgaor
835f97d3c2 fix(shutdown): force-stop on second SIGINT during countdown
A second Ctrl+C/SIGINT while the 10-second shutdown countdown is
running now exits immediately instead of being silently dropped.
The signal channel is buffered to 2 so the second signal is captured,
and the countdown select exits via os.Exit(1) on receipt.
2026-03-18 21:36:24 +01:00
Houmgaor
792dcd5d91 feat(diva): implement Diva Defense point accumulation (#168)
RE'd putAdd_ud_point (FUN_114fd490) and putAdd_ud_tactics_point
(FUN_114fe9c0) from the ZZ client DLL via Ghidra decompilation.

MsgMhfAddUdPoint fields: QuestPoints (sum of 11 category accumulators
earned per quest) and BonusPoints (kiju prayer song multiplier extra).
MsgMhfAddUdTacticsPoint fields: QuestID and TacticsPoints.

Adds diva_points table (migration 0009) for per-character per-event
point tracking, with UPSERT-based atomic accumulation in the handler.
2026-03-18 12:09:44 +01:00
Houmgaor
61d85e749f feat(achievement): add rank-up notifications (#165)
RE'd putDisplayed_achievement from ZZ client DLL via Ghidra: the packet
sends opcode + 1 zero byte with no achievement ID, acting as a blanket
"I saw everything" signal.

Server changes:
- Track per-character last-displayed levels in new displayed_levels
  column (migration 0008)
- GetAchievement compares current vs displayed levels per entry
- DisplayedAchievement snapshots current levels to clear notifications
- Repo, service, mock, and 3 new service tests

Protbot changes:
- New --action achievement: fetches achievements, shows rank-up markers,
  sends DISPLAYED_ACHIEVEMENT, re-fetches to verify notifications clear
- Packet builders for GET/ADD/DISPLAYED_ACHIEVEMENT
2026-03-18 11:35:31 +01:00
Houmgaor
197164bc94 docs: log savedata corruption defense in CHANGELOG
Merge migrations 0007 and 0008 into a single 0007_savedata_integrity
migration since neither has been released yet.
2026-03-17 19:30:43 +01:00
Houmgaor
03adb21e99 fix(channelserver): post-RC1 stabilization sprint
Fix rasta_id=0 overwriting NULL in SaveMercenary, which prevented
game state saving for characters without a mercenary (#163).

Also includes:
- CHANGELOG updated with all 10 post-RC1 commits
- Setup wizard fmt.Printf replaced with zap structured logging
- technical-debt.md updated with 6 newly completed items
- Scenario binary format documented (docs/scenario-format.md)
- Tests: alliance nil-guard (#171), handler dispatch table,
  migrations (sorted/SQL/baseline), setup wizard (10 tests),
  protbot protocol sign/entrance/channel (23 tests)
2026-03-05 16:39:15 +01:00
Houmgaor
5106b905de docs: update changelog for v9.3.0-rc1 release
Backfill key changes from 900 commits since 9.2.0 including
architecture rewrite, game system overhauls, client version
support, and developer tooling. Tag Unreleased as 9.3.0-rc1.
2026-02-28 19:18:11 +01:00
Houmgaor
fa09e4a39c fix(migrations): drop unused data column from distribution table (#169)
The distribution table had a `data bytea NOT NULL` column that was never
read by the Go code — item data is stored in distribution_items instead.
The NOT NULL constraint forced dummy values in seed data and test inserts.

Remove the column from the baseline schema, seed data, and tests, and
add migration 0005 to drop it from existing databases.
2026-02-27 18:19:57 +01:00
Houmgaor
21f9a79b62 fix(channelserver): correct session handler retail mismatches (#167)
Lobby search now returns only quest-bound players (QuestReserved) instead
of all reserved slots, matching retail behavior. The new field is
pre-collected under server lock before stage iteration to respect
Server.Mutex → Stage.RWMutex lock ordering.

Replaced three TODOs with RE documentation from Ghidra decompilation of
mhfo-hd.dll ZZ:
- Log key off-by-one: putRecord_log/putTerminal_log pass size 0 for the
  key field in ZZ, so the stored key is unused beyond issuance
- User search padding: ZZ per-entry parser confirms 40-byte block via
  memcpy(dst, src+8, 0x28); G2 DLL analysis inconclusive (stripped)
- Player count: field at entry offset 0x08 maps to struct param_1[0xe]
2026-02-27 17:29:32 +01:00
Houmgaor
649eebe67c docs: log bookshelf data pointer fix in changelog and technical debt tracker 2026-02-27 16:53:35 +01:00
Houmgaor
7911d84d48 docs: log alliance application toggle fix in changelog 2026-02-27 15:02:30 +01:00
Houmgaor
7ff26f4980 feat(api): add v2 routes, auth middleware, structured errors, and server status endpoint
Introduces incremental API improvements for custom launcher support
(mhf-iel, stratic-dev's Rust launcher):

- Standardize all error responses to JSON envelopes with error/message
- Add Bearer token auth middleware for v2 routes (legacy body-token preserved)
- Add `returning` (>90d inactive) and `courses` fields to auth response
- Add /v2/ route prefix with HTTP method enforcement
- Add GET /v2/server/status for MezFes, featured weapon, and event status
- Add APIEventRepo for read-only event data access

Closes #44
2026-02-27 12:46:23 +01:00
Houmgaor
1f0ea6ac23 docs(changelog): log gacha shop fix for G1–GG clients (#150) 2026-02-26 21:51:52 +01:00
Houmgaor
2f92b4ff62 feat(db): add catch-up migration for partially-patched databases
The migration consolidation (27fb0fa) merged 33 incremental patches
into 0001_init.sql and marks the baseline as applied for any existing
database. Users who only ran some of the 33 patches have schema gaps
that cause runtime errors.

0002_catch_up_patches.sql replays all 33 patches (skipping 15 and 20,
which are destructive data resets) with idempotency guards so it is a
no-op on fresh or fully-patched databases and fills gaps otherwise.
2026-02-24 11:37:37 +01:00
Houmgaor
27fb0faa1e feat(db): add embedded auto-migrating schema system
Replace 4 independent schema management code paths (Docker shell
script, setup wizard pg_restore, test helpers, manual psql) with a
single migration runner embedded in the server binary.

The new server/migrations/ package uses Go embed to bundle all SQL
schemas. On startup, Migrate() creates a schema_version tracking
table, detects existing databases (auto-marks baseline as applied),
and runs pending migrations in transactions.

Key changes:
- Consolidated init.sql + 9.2-update + 33 patches into 0001_init.sql
- Setup wizard simplified to single "Apply schema" checkbox
- Test helpers use migrations.Migrate() instead of pg_restore
- Docker no longer needs schema volume mounts or init script
- Seed data (shops, events, gacha) embedded and applied via API
- Future migrations just add 0002_*.sql files — no manual steps
2026-02-23 21:19:21 +01:00
Houmgaor
6a7db47723 feat(setup): add web-based first-run configuration wizard
When config.json is missing, Erupe now launches a temporary HTTP server
on port 8080 serving a guided setup wizard instead of exiting with a
cryptic error. The wizard walks users through database connection,
schema initialization (pg_restore + SQL migrations), and server settings,
then writes config.json and continues normal startup without restart.
2026-02-23 20:55:56 +01:00
Houmgaor
12f463e03b ci: replace codecov with local coverage threshold check
Codecov requires an account and token to function. Replace it with
a self-contained `go tool cover` step that fails the build if total
coverage drops below 50% (currently ~58%). This catches test
regressions without external service dependencies.
2026-02-23 17:16:09 +01:00
Houmgaor
4c4be1d336 test(channelserver): add unit tests for paper data handler
Covers all DataType branches (0/5/6/gift/>1000/unknown), ACK payload
structure with correct 10-byte header offset, earth succeed entry
counts, timetable content validation, PaperData/PaperGift serialization
round-trips, and paperGiftData table integrity checks.
2026-02-23 17:01:20 +01:00
Houmgaor
e8963ce0cf ci: add release workflow to publish binaries on tag push
Users without a Go toolchain can now download pre-built binaries
directly from GitHub Releases (closes #161). The workflow triggers
on v* tags, builds Linux and Windows amd64 archives, and attaches
them along with SCHEMA.sql to an auto-generated release.

Also fixes the README badge URL (go-improved.yml → go.yml).
2026-02-22 20:08:25 +01:00
Houmgaor
2acbb5d03a feat(channelserver): implement monthly guild item claim tracking
Players could never claim monthly guild items because the handler
always returned 0x01 (claimed). Now tracks per-character per-type
(standard/HLC/EXC) claim timestamps in the stamps table, comparing
against the current month boundary to determine claim eligibility.

Adds MonthStart() to gametime, extends StampRepo with
GetMonthlyClaimed/SetMonthlyClaimed, and includes schema migration
31-monthly-items.sql.
2026-02-22 16:46:57 +01:00
Houmgaor
ad3fcbf908 feat(api): add GET /version endpoint
Returns the server name and configured client mode as JSON,
enabling clients like MHBridge to display server version info.
2026-02-21 00:40:28 +01:00
Houmgaor
263e207ba2 docs: clarify object ID rework descriptions and remove stale comment
Replace vague "Alpelo object system backport" references in CHANGELOG
and AUTHORS with accurate descriptions of the per-session object ID
allocation rework. Remove stale test comment referencing the deleted
NextObjectID method.
2026-02-20 18:42:08 +01:00
Houmgaor
10e09630a6 fix: send failure ack for missing quest/scenario files instead of crashing client
When a quest or scenario file was missing, handleMsgSysGetFile sent nil
data via doAckBufSucceed, which crashed the game client. Now sends
doAckBufFail so the client can handle the missing file gracefully.

Closes #109
2026-02-16 18:35:44 +01:00
Houmgaor
a7b0deaa42 fix: resolve data race in token.RNG global
Wrap *rand.Rand in a mutex-protected SafeRand type to make the global
RNG safe for concurrent use across goroutines. The previous bare
*rand.Rand caused data races detected by go test -race.
2026-02-16 18:19:18 +01:00
Houmgaor
9b69564c49 fix: prevent server crash on unsupported Shift-JIS characters (#116)
UTF8ToSJIS panicked when encountering characters outside the Shift-JIS
range (emoji, Lenny faces, cuneiform, etc.), crashing the server when
such characters were sent via the Discord relay channel.

Replace the panic with graceful filtering that drops unmappable runes
and preserves valid content. Also fix ToNGWord index-out-of-range panic
on empty encoder output.

Closes #116
2026-02-16 18:16:42 +01:00
Houmgaor
2b94eb196d doc: completes history. 2025-11-09 17:02:18 +01:00
Houmgaor
e31a37e0f9 chore: upgrading minimal Go from 1.23 to 1.25. 2025-11-09 16:51:02 +01:00
Houmgaor
0fac429fac fix(transmog): fix transmog issues.
Untested commit.
2025-11-09 11:57:28 +01:00
Houmgaor
36065ce273 fix(plate data): was not save, nor transmog data. 2025-11-01 18:14:30 +01:00
Houmgaor
3da54fade8 chore: adds remaining logging for Hunter Navi and Plate data. 2025-11-01 17:14:05 +01:00
Houmgaor
afc554f1ec fix(save): avoid double-save.
feat(logging): more complete logging data.
2025-11-01 00:37:59 +01:00
Houmgaor
18592c5ded fix(handlers): trying to fix issues with incomplete saves. 2025-10-31 13:10:17 +01:00
Houmgaor
e1a461e892 fix(stage): fix deadlock that was preventing stage change. 2025-10-27 01:13:43 +01:00
Houmgaor
73e874f43f fix: array bound crashes on clans. 2025-10-21 00:21:50 +02:00
Houmgaor
060635e422 fix(stage): fix race condition with stages. 2025-10-21 00:00:08 +02:00
Houmgaor
f79e05c0c9 feat(go): upgrade from go 1.21 to 1.23
BREAKING CHANGE: will not work properly with Go 1.21.
2025-10-19 22:24:48 +02:00
Houmgaor
02d5195611 docs: starting to expand the documentation. 2025-10-19 18:57:10 +02:00