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)
This commit is contained in:
Houmgaor
2026-03-05 16:39:15 +01:00
parent 10ac803a45
commit 03adb21e99
13 changed files with 1314 additions and 6 deletions

56
docs/scenario-format.md Normal file
View File

@@ -0,0 +1,56 @@
# Scenario Binary Format
> Reference: `network/mhfpacket/msg_sys_get_file.go`, issue [#172](https://github.com/Mezeporta/Erupe/issues/172)
## Overview
Scenario files are binary blobs served by `MSG_SYS_GET_FILE` when `IsScenario` is true. They contain quest descriptions, NPC dialog, episode listings, and menu options for the game's scenario/story system.
## Request Format
When `IsScenario == true`, the client sends a `scenarioFileIdentifier`:
| Offset | Type | Field | Description |
|--------|--------|-------------|-------------|
| 0 | uint8 | CategoryID | Scenario category |
| 1 | uint32 | MainID | Main scenario identifier |
| 5 | uint8 | ChapterID | Chapter within the scenario |
| 6 | uint8 | Flags | Bit flags selecting chunk types (see below) |
## Flags (Chunk Type Selection)
The `Flags` byte is a bitmask that selects which chunk types the client requests:
| Bit | Value | Type | Recursive | Content |
|------|-------|---------|-----------|---------|
| 0 | 0x01 | Chunk0 | Yes | Quest name/description + 0x14 byte info block |
| 1 | 0x02 | Chunk1 | Yes | NPC dialog(?) + 0x2C byte info block |
| 2 | 0x04 | — | — | Unknown (no instances found; possibly Chunk2) |
| 3 | 0x08 | Chunk0 | No | Episode listing (0x1 prefixed?) |
| 4 | 0x10 | Chunk1 | No | JKR-compressed blob, NPC dialog(?) |
| 5 | 0x20 | Chunk2 | No | JKR-compressed blob, menu options or quest titles(?) |
| 6 | 0x40 | — | — | Unknown (no instances found) |
| 7 | 0x80 | — | — | Unknown (no instances found) |
### Chunk Types
- **Chunk0**: Contains text data (quest names, descriptions, episode titles) with an accompanying fixed-size info block.
- **Chunk1**: Contains dialog or narrative text with a larger info block (0x2C bytes).
- **Chunk2**: Contains menu/selection text.
### Recursive vs Non-Recursive
- **Recursive chunks** (flags 0x01, 0x02): The chunk data itself contains nested sub-chunks that must be parsed recursively.
- **Non-recursive chunks** (flags 0x08, 0x10, 0x20): The chunk is a flat binary blob. Flags 0x10 and 0x20 are JKR-compressed and must be decompressed before reading.
## Response Format
The server responds with the scenario file data via `doAckBufSucceed`. The response is the raw binary blob matching the requested chunk types. If the scenario file is not found, the server sends `doAckBufFail` to prevent a client crash.
## Current Implementation
Scenario files are loaded from `quests/scenarios/` on disk. The server currently serves them as opaque binary blobs with no parsing. Issue #172 proposes adding JSON/CSV support for easier editing, which would require implementing a parser/serializer for this format.
## JKR Compression
Chunks with flags 0x10 and 0x20 use JPK compression (magic bytes `0x1A524B4A`). See the ReFrontier tool for decompression utilities.

View File

@@ -1,6 +1,6 @@
# Erupe Technical Debt & Suggested Next Steps
> Last updated: 2026-02-27
> Last updated: 2026-03-05
This document tracks actionable technical debt items discovered during a codebase audit. It complements `anti-patterns.md` (which covers structural patterns) by focusing on specific, fixable items with file paths and line numbers.
@@ -82,6 +82,11 @@ Items resolved since the original audit:
| — | **`db != nil` guard** (`handlers_session.go:322`) | Investigated — this guard is intentional. Test servers run without repos; the guard protects the entire logout path from nil repo dereferences. Not a leaky abstraction. |
| ~~2~~ | **Repo test coverage (17 files)** | All 20 repo source files now have `_test.go` files with mock-based unit tests. |
| — | **Bookshelf data pointer** ([#164](https://github.com/Mezeporta/Erupe/issues/164)) | Corrected `pBookshelfData` offsets for G1Z2 (103928), F4F5 (71928), S6 (23928). Validated via inter-version delta analysis and Ghidra decompilation of ZZ `snj_db_get_housedata`. |
| — | **Guild nil panics** ([#171](https://github.com/Mezeporta/Erupe/issues/171)) | Three fixes merged post-RC1: nil guards for alliance guild lookups (aee5353), variable shadowing fix in scout list (8e79fe6), nil guards in cancel/answer scout handlers (8717fb9). Clan hall softlock resolved. |
| — | **ecdMagic byte order** ([#174](https://github.com/Mezeporta/Erupe/issues/174)) | Corrected constant byte order in `crypt_conn.go` (10ac803). |
| — | **Rengoku caching** | Cached `rengoku_data.bin` at startup to avoid repeated disk reads (5b631d1). |
| — | **rasta_id=0 save issue** ([#163](https://github.com/Mezeporta/Erupe/issues/163)) | `SaveMercenary` now skips rasta_id update when value is 0, preserving NULL for characters without a mercenary. |
| — | **fmt.Printf in setup wizard** | Replaced `fmt.Printf` in `server/setup/setup.go` with structured `zap` logging. |
---
@@ -94,5 +99,5 @@ Based on remaining impact:
3. **Fix achievement rank-up notifications** ([#165](https://github.com/Mezeporta/Erupe/issues/165)) — needs protocol research on `MhfDisplayedAchievement`
4. ~~**Add coverage threshold** to CI~~**Done.** 50% floor enforced via `go tool cover` in CI; Codecov removed.
5. ~~**Fix guild alliance toggle** ([#166](https://github.com/Mezeporta/Erupe/issues/166))~~**Done.** `recruiting` column + `OperateJoint` allow/deny actions + DB toggle
6. **Fix session handler retail mismatches** ([#167](https://github.com/Mezeporta/Erupe/issues/167)) log key off-by-one, version boundary, player count
6. ~~**Fix session handler retail mismatches** ([#167](https://github.com/Mezeporta/Erupe/issues/167))~~**Documented.** RE'd from ZZ DLL; log key off-by-one is benign server-side, player count fixed via `QuestReserved`.
7. **Reverse-engineer MhfAddUdPoint fields** ([#168](https://github.com/Mezeporta/Erupe/issues/168)) — needs packet captures