docs(hunting-tournament): document tournament RE gaps and branch status

Add hunting-tournament.md covering the 公式狩猟大会 system: game
context (cups, schedule, rewards), what is already implemented in
develop (handlers_tournament.go is mostly functional), and the four
remaining gaps requiring RE — quest clear time recording, ClanID
leaderboard filtering, AcquireTournament reward delivery, and guild
cup soul attribution to Mezeporta Festival.

Documents why feature/hunting-tournament is not mergeable (duplicate
handlers) and preserves its useful findings: ClanID field name on
EnumerateOrder and the festa timing corrections.

Update unimplemented.md open branches summary accordingly.
This commit is contained in:
Houmgaor
2026-03-22 20:24:09 +01:00
parent 93f8c677d9
commit dca7152656
2 changed files with 191 additions and 0 deletions

190
docs/hunting-tournament.md Normal file
View File

@@ -0,0 +1,190 @@
# Official Hunting Tournament (公式狩猟大会)
Documents the tournament system implementation status, known protocol details, and remaining
reverse-engineering gaps.
The `feature/hunting-tournament` branch (origin) is **not mergeable** — it duplicates handlers
that already exist in `handlers_tournament.go`. Its useful findings are incorporated below.
---
## Game Context
The 公式狩猟大会 (Official Hunting Tournament) was a recurring competitive event numbered
sequentially from the first (late 2007) through at least the 150th before service ended in
December 2019. It ran during the **登録祭** (Registration Festival) — week 1 of each 3-week
Mezeporta Festival (狩人祭) cycle.
### Competition Cups (杯)
| Cup | Group | Type | Description |
|-----|-------|------|-------------|
| **個人 G級韋駄天杯** (Solo speed hunt) | 16 | 7 | Time-attack solo vs. a designated monster. Results ranked per weapon class (EventSubType 013+ map to weapon categories). |
| **猟団対抗韋駄天杯** (Guild speed hunt) | 17 | 7 | Same time-attack concept, up to 4 hunters from the same guild. Guild rankings determine 魂 (souls) payouts to Mezeporta Festival. EventSubType -1 = all weapon classes combined. |
| **巨大魚杯** (Giant fish cup) | 6 | 6 | Fish size competition. Three designated species; largest catch wins. EventSubType maps to fish species. |
### Tournament Schedule
The tournament ran inside each 登録祭 week, and had four phases:
| Phase | State byte | Duration |
|-------|-----------|---------|
| Before start | 0 | Until `StartTime` |
| Registration + hunting | 1 | `StartTime``EntryEnd` (~3 days, Fri 14:00 to Mon 14:00) |
| Scoring / ranking | 2 | `EntryEnd``RankingEnd` (~+8.9 days) |
| Reward distribution | 3 | `RankingEnd``RewardEnd` (+7 days) |
The four Unix timestamps (`StartTime`, `EntryEnd`, `RankingEnd`, `RewardEnd`) are all included in
the `EnumerateRanking` response alongside the current state byte.
### Rewards
| Placement | Reward |
|-----------|--------|
| All participants | カフの素 (Skill Cuff base materials), ネコ珠の素 (Cat Gem base) |
| Top 500 | 匠チケット + ハーフチケット白 |
| Top 100 | 猟団ポイント (Guild points) |
| Top 3 (speed hunt) | 公式のしるし【金/銀/銅】(Official Mark Gold/Silver/Bronze) |
| Top 3 (fish cup) | 魚杯のしるし【金/銀/銅】(Fish Cup Mark Gold/Silver/Bronze) |
| 1st place (from tournament 76+) | 王者のメダル (King's Medal) — crafts exclusive weapons |
| Guild rank 110 | 50,000 魂 to faction + 5,000 to guild (Mezeporta Festival souls) |
| Guild rank 1130 | 20,000 魂 to faction + 2,000 to guild |
---
## Implementation Status in `develop`
The tournament is **substantially implemented** in `handlers_tournament.go` and `repo_tournament.go`
with a full repository pattern and DB schema (`server/migrations/sql/0015_tournament.sql`).
### What Works
| Handler | File | Status |
|---------|------|--------|
| `handleMsgMhfEnumerateRanking` | `handlers_tournament.go` | Full — DB-backed, state machine, cups + sub-events |
| `handleMsgMhfEnumerateOrder` | `handlers_tournament.go` | Partial — returns leaderboard entries, but ranked by submission time (see gaps) |
| `handleMsgMhfInfoTournament` | `handlers_tournament.go` | Partial — type 0 (listing) and type 1 (registration check) work; type 2 (reward structures) returns empty |
| `handleMsgMhfEntryTournament` | `handlers_tournament.go` | Full — registers character, returns `entryID` |
| `handleMsgMhfEnterTournamentQuest` | `handlers_tournament.go` | Partial — records the submission, but clear time is not stored (see gaps) |
| `handleMsgMhfAcquireTournament` | `handlers_tournament.go` | Stub — returns empty reward list |
### Database Schema
Five tables in `0015_tournament.sql`:
```
tournaments — schedule: id, name, start_time, entry_end, ranking_end, reward_end
tournament_cups — per-tournament cup categories (cup_group, cup_type, name, description)
tournament_sub_events — shared event definitions (cup_group, event_sub_type, quest_file_id, name)
tournament_entries — per-character registration (char_id, tournament_id, UNIQUE)
tournament_results — per-submission record (char_id, tournament_id, event_id, quest_slot, stage_handle, submitted_at)
```
Note: `tournament_results` records *when* a submission arrived but not the actual quest clear time.
The leaderboard in `GetLeaderboard` therefore ranks by `submitted_at ASC` (first to submit = rank 1)
which is incorrect — the real server ranked by quest clear time.
---
## Known Gaps (RE Required)
### 1. Ranking by Quest Clear Time
**Impact**: High — the leaderboard is fundamentally wrong.
`handleMsgMhfEnterTournamentQuest` receives `TournamentID`, `EntryHandle`, `Unk2` (likely
`EventID`), `QuestSlot`, and `StageHandle`. None of these fields carry the actual clear time
directly. The clear time likely arrives via a separate packet (possibly `MsgMhfEndQuest` or a
dedicated score submission packet) that is not yet identified. Until it is, ranking by submission
order is a best-effort placeholder.
### 2. Guild Leaderboard Filtering by `ClanID`
**Impact**: Medium — guild cup leaderboard shows all entries instead of filtering by clan.
`MsgMhfEnumerateOrder` sends both `EventID` and `ClanID` (field names confirmed by the
`feature/hunting-tournament` branch). The current `GetLeaderboard` implementation queries only
by `event_id` and ignores `ClanID`. The guild cup (cup_group 17) leaderboard is presumably
filtered to show only that clan's members, or possibly compared against other clans. The exact
filtering semantics are unknown.
### 3. `AcquireTournament` Reward Delivery
**Impact**: High — players cannot receive any tournament rewards.
`handleMsgMhfAcquireTournament` returns an empty `TournamentReward` list. The
`TournamentReward` struct has three `uint16` fields (`Unk0`, `Unk1`, `Unk2`) that are entirely
unknown. It is unclear whether these carry item IDs, quantities, and flags, or whether the reward
delivery uses a different mechanism (e.g. mail). The 王者のメダル and 公式のしるし item IDs are
also unknown.
### 4. `InfoTournament` Type 2 (Reward Structures)
**Impact**: Medium — in-game reward preview is empty.
Query type 2 returns `TournamentInfo21` and `TournamentInfo22` lists — these likely describe
the per-placement reward tiers shown in the UI before a player claims their prize. All fields in
both structs are unknown (`Unk0``Unk4`).
### 5. `TournamentInfo0` Unknown Fields
**Impact**: Low — mostly display metadata.
The `TournamentInfo0` struct (used in `InfoTournament` type 0) has several unknown fields:
`MaxPlayers`, `CurrentPlayers`, `TextColor`, `Unk1``Unk6`, `MinHR`, `MaxHR`, plus two
unknown strings. Currently all written as zero/empty. The HR min/max likely gate tournament
access by hunter rank; `TextColor` likely styles the tournament name in the UI.
### 6. Guild Cup Souls → Mezeporta Festival Attribution
**Impact**: Medium — guild cup placement does not feed into Festa soul pool.
The guild speed hunt cup (cup_group 17) awarded 魂 to the guild's Mezeporta Festival account
based on placement. `handleMsgMhfAcquireTournament` currently delivers no rewards at all, let
alone Festa souls. Even once reward delivery is implemented, the soul injection into the Festa
system (via `FestaRepo.SubmitSouls` or similar) needs to be wired up.
---
## What the `feature/hunting-tournament` Branch Adds
The branch is not mergeable because it adds `handleMsgMhfEnumerateRanking` and
`handleMsgMhfEnumerateOrder` to `handlers_festa.go`, creating duplicate definitions that already
exist in `handlers_tournament.go`. However it contains several useful findings:
**`ClanID` field name on `MsgMhfEnumerateOrder`**
The two unknown fields (`Unk0`, `Unk1`) are identified as `EventID` and `ClanID`. `EventID` was
already used correctly in develop; `ClanID` is the new insight (currently ignored).
**Phase timing constants**
The branch's `generateTournamentTimestamps` debug modes confirm the timestamp offsets:
- `StartTime``EntryEnd`: +259,200 s (3 days)
- `EntryEnd``RankingEnd`: +766,800 s (~8.9 days)
- `RankingEnd``RewardEnd`: +604,800 s (7 days)
These match the real-server cadence and are already reflected in `TournamentDefaults.sql`.
**Festa timing correction (unrelated side effect)**
The branch also modifies `generateFestaTimestamps` in two ways that are not related to the
tournament but should be evaluated independently:
- `RestartAfter` threshold: 2,977,200 s → 3,024,000 s (34.45 days → 35 days)
- New event start time: midnight+24h → midnight+35h (i.e. 11:00 the following morning)
These changes appear to better match the real server schedule but have no test coverage. They
should be assessed against packet captures before merging.
---
## Seed Data Reference
`server/migrations/seed/TournamentDefaults.sql` pre-populates:
- 1 tournament (tournament #150, "第150回公式狩猟大会") with correct phase durations
- 18 sub-events:
- cup_group 16 (individual speed hunt): EventSubType 013 against Brachydios, quest_file_id 60691
- cup_group 17 (guild speed hunt): EventSubType -1, quest_file_id 60690
- cup_group 6 (fish): キレアジ (EventSubType 234), ハリマグロ (237), カクサンデメキン (239)
- 3 cups: 個人 巨大魚杯 (id 569), 猟団 G級韋駄天杯 (id 570), 個人 G級韋駄天杯 (id 571)
The cup descriptions contain hardcoded dates ("2019年11月22日") from the original live event.
These should be templated or made dynamic when reward delivery is implemented.

View File

@@ -191,6 +191,7 @@ that needs no reply). Others are genuine feature gaps.
|--------|:---:|-------------------|
| `feature/enum-event` | 4 | `EnumerateEvent` scheduling only — not mergeable, see `docs/fort-attack-event.md` |
| `feature/conquest` | 4 | Conquest quest handlers — not mergeable, see `docs/conquest-war.md` |
| `feature/hunting-tournament` | 7 | `EnumerateRanking` / `EnumerateOrder` — not mergeable (duplicates handlers_tournament.go), see `docs/hunting-tournament.md` |
| `feature/tower` | 4 | Tower handlers |
---