mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-23 08:03:51 +01:00
feat(tournament): implement hunting tournament system end-to-end
Wire format for MsgMhfEnterTournamentQuest (0x00D2) derived from mhfo-hd.dll binary analysis (FUN_114f4280). Five new tables back the full lifecycle: schedule, cups, sub-events, player registrations, and run submissions. All six tournament handlers are now DB-driven: - EnumerateRanking: returns active tournament schedule with cups and sub-events; computes phase state byte from timestamps - EnumerateOrder: returns per-event leaderboard ranked by submission time, with SJIS-encoded character and guild names - InfoTournament: exposes tournament detail and player registration state across all three query types - EntryTournament: registers player and returns entry handle used by the client in the subsequent EnterTournamentQuest packet - EnterTournamentQuest: parses the previously-unimplemented packet and records the run in tournament_results - AcquireTournament: stubs rewards (item IDs not yet reversed) Seed data (TournamentDefaults.sql) reproduces tournament #150 cups and sub-events so a fresh install has a working tournament immediately.
This commit is contained in:
@@ -8,8 +8,33 @@ import (
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// MsgMhfEnterTournamentQuest represents the MSG_MHF_ENTER_TOURNAMENT_QUEST
|
||||
type MsgMhfEnterTournamentQuest struct{}
|
||||
// MsgMhfEnterTournamentQuest represents the MSG_MHF_ENTER_TOURNAMENT_QUEST (opcode 0x00D2).
|
||||
//
|
||||
// Wire format derived from mhfo-hd.dll binary analysis (FUN_114f4280 = putEnterTournamentQuest).
|
||||
// The client sends this packet when entering the actual tournament quest instance after
|
||||
// completing the ENTRY_TOURNAMENT (0xD1) flow. Fields are all big-endian.
|
||||
//
|
||||
// Byte layout (after opcode):
|
||||
//
|
||||
// [0..3] uint32 AckHandle
|
||||
// [4..7] uint32 TournamentID — tournament being entered
|
||||
// [8..11] uint32 EntryHandle — slot handle assigned by server during ENTRY_TOURNAMENT response
|
||||
// [12..15] uint32 Unk2 — third field from server INFO response; semantics unclear
|
||||
// [16..19] uint32 QuestSlot — derived from quest table (DAT_1e41d3b4); effectively uint16 in uint32
|
||||
// [20..23] uint32 StageHandle — quest node offset (DAT_1e41d3b8); computed as quest_node + 0x10
|
||||
// [24..27] uint32 Unk5 — formatted string identifier (result of FUN_11586310)
|
||||
// [28] uint8 StringLen — length of optional trailing string (0 = absent in normal flow)
|
||||
// [29+] bytes String — pascal-style string data (StringLen bytes, absent when 0)
|
||||
type MsgMhfEnterTournamentQuest struct {
|
||||
AckHandle uint32
|
||||
TournamentID uint32
|
||||
EntryHandle uint32
|
||||
Unk2 uint32
|
||||
QuestSlot uint32
|
||||
StageHandle uint32
|
||||
Unk5 uint32
|
||||
String []byte // pascal-style: 1-byte length prefix, then data; nil when absent
|
||||
}
|
||||
|
||||
// Opcode returns the ID associated with this packet type.
|
||||
func (m *MsgMhfEnterTournamentQuest) Opcode() network.PacketID {
|
||||
@@ -18,7 +43,18 @@ func (m *MsgMhfEnterTournamentQuest) Opcode() network.PacketID {
|
||||
|
||||
// Parse parses the packet from binary
|
||||
func (m *MsgMhfEnterTournamentQuest) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
return errors.New("NOT IMPLEMENTED")
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.TournamentID = bf.ReadUint32()
|
||||
m.EntryHandle = bf.ReadUint32()
|
||||
m.Unk2 = bf.ReadUint32()
|
||||
m.QuestSlot = bf.ReadUint32()
|
||||
m.StageHandle = bf.ReadUint32()
|
||||
m.Unk5 = bf.ReadUint32()
|
||||
strLen := bf.ReadUint8()
|
||||
if strLen > 0 {
|
||||
m.String = bf.ReadBytes(uint(strLen))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build builds a binary packet from the current data.
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
// MsgMhfEnumerateOrder represents the MSG_MHF_ENUMERATE_ORDER
|
||||
type MsgMhfEnumerateOrder struct {
|
||||
AckHandle uint32
|
||||
Unk0 uint32
|
||||
Unk1 uint32
|
||||
EventID uint32
|
||||
ClanID uint32
|
||||
}
|
||||
|
||||
// Opcode returns the ID associated with this packet type.
|
||||
@@ -23,8 +23,8 @@ func (m *MsgMhfEnumerateOrder) Opcode() network.PacketID {
|
||||
// Parse parses the packet from binary
|
||||
func (m *MsgMhfEnumerateOrder) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.Unk0 = bf.ReadUint32()
|
||||
m.Unk1 = bf.ReadUint32()
|
||||
m.EventID = bf.ReadUint32()
|
||||
m.ClanID = bf.ReadUint32()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ func TestParseSmallNotImplemented(t *testing.T) {
|
||||
// MHF packets - NOT IMPLEMENTED
|
||||
{"MsgMhfAcceptReadReward", &MsgMhfAcceptReadReward{}},
|
||||
{"MsgMhfDebugPostValue", &MsgMhfDebugPostValue{}},
|
||||
{"MsgMhfEnterTournamentQuest", &MsgMhfEnterTournamentQuest{}},
|
||||
{"MsgMhfGetCaAchievementHist", &MsgMhfGetCaAchievementHist{}},
|
||||
{"MsgMhfGetCaUniqueID", &MsgMhfGetCaUniqueID{}},
|
||||
{"MsgMhfGetRestrictionEvent", &MsgMhfGetRestrictionEvent{}},
|
||||
|
||||
Reference in New Issue
Block a user