diff --git a/.gitignore b/.gitignore index 2310f3074..04a9d02ea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ www/tw/ www/jp/ bin/quests/*.bin +bin/scenarios/*.bin +bin/debug/*.bin savedata/ Erupe.exe \ No newline at end of file diff --git a/network/mhfpacket/msg_mhf_info_scenario_counter.go b/network/mhfpacket/msg_mhf_info_scenario_counter.go index 9e38aa353..4a415a9e6 100644 --- a/network/mhfpacket/msg_mhf_info_scenario_counter.go +++ b/network/mhfpacket/msg_mhf_info_scenario_counter.go @@ -6,7 +6,9 @@ import ( ) // MsgMhfInfoScenarioCounter represents the MSG_MHF_INFO_SCENARIO_COUNTER -type MsgMhfInfoScenarioCounter struct{} +type MsgMhfInfoScenarioCounter struct { + AckHandle uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfInfoScenarioCounter) Opcode() network.PacketID { @@ -15,10 +17,11 @@ func (m *MsgMhfInfoScenarioCounter) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfInfoScenarioCounter) Parse(bf *byteframe.ByteFrame) error { - panic("Not implemented") + m.AckHandle = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. func (m *MsgMhfInfoScenarioCounter) Build(bf *byteframe.ByteFrame) error { panic("Not implemented") -} \ No newline at end of file +} diff --git a/network/mhfpacket/msg_sys_get_file.go b/network/mhfpacket/msg_sys_get_file.go index 2d965f1ac..fccb1201b 100644 --- a/network/mhfpacket/msg_sys_get_file.go +++ b/network/mhfpacket/msg_sys_get_file.go @@ -6,10 +6,24 @@ import ( ) type scenarioFileIdentifer struct { - Unk0 uint8 - Unk1 uint32 - Unk2 uint8 - Unk3 uint8 + CategoryID uint8 + MainID uint32 + ChapterID uint8 + /* + Flags represent the following bit flags: + + 11111111 -> Least significant bit on the right. + |||||||| + |||||||0x1: Chunk0-type, recursive chunks, quest name/description + 0x14 byte unk info + ||||||0x2: Chunk1-type, recursive chunks, npc dialog? + 0x2C byte unk info + |||||0x4: UNK NONE FOUND. (Guessing from the following that this might be a chunk2-type) + ||||0x8: Chunk0-type, NO RECURSIVE CHUNKS ([0x1] prefixed?), Episode listing + |||0x10: Chunk1-type, NO RECURSIVE CHUNKS, JKR blob, npc dialog? + ||0x20: Chunk2-type, NO RECURSIVE CHUNKS, JKR blob, Menu options or quest titles? + |0x40: UNK NONE FOUND + 0x80: UNK NONE FOUND + */ + Flags uint8 } // MsgSysGetFile represents the MSG_SYS_GET_FILE @@ -30,6 +44,11 @@ func (m *MsgSysGetFile) Opcode() network.PacketID { func (m *MsgSysGetFile) Parse(bf *byteframe.ByteFrame) error { m.AckHandle = bf.ReadUint32() m.IsScenario = bf.ReadBool() + m.FilenameLength = bf.ReadUint8() + if m.FilenameLength > 0 { + m.Filename = string(bf.ReadBytes(uint(m.FilenameLength))) + } + if m.IsScenario { m.ScenarioIdentifer = scenarioFileIdentifer{ bf.ReadUint8(), @@ -37,9 +56,6 @@ func (m *MsgSysGetFile) Parse(bf *byteframe.ByteFrame) error { bf.ReadUint8(), bf.ReadUint8(), } - } else { - m.FilenameLength = bf.ReadUint8() - m.Filename = string(bf.ReadBytes(uint(m.FilenameLength))) } return nil } diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index d75fbfc02..0b68c15a6 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -249,6 +249,12 @@ func handleMsgSysCastedBinary(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysGetFile) + // Debug print the request. + fmt.Printf("%+v\n", pkt) + if pkt.IsScenario { + fmt.Printf("%+v\n", pkt.ScenarioIdentifer) + } + if !pkt.IsScenario { // Get quest file. data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", stripNullTerminator(pkt.Filename)))) @@ -258,7 +264,34 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { doSizedAckResp(s, pkt.AckHandle, data) } else { - s.logger.Fatal("scenario getfile not implemented.") + + /* + // mhf-fake-client format + filename := fmt.Sprintf( + "%d_%d_%d_%d", + pkt.ScenarioIdentifer.CategoryID, + pkt.ScenarioIdentifer.MainID, + pkt.ScenarioIdentifer.ChapterID, + pkt.ScenarioIdentifer.Flags, + ) + */ + + // Fist's format: + filename := fmt.Sprintf( + "%d_0_0_0_S%d_T%d_C%d", + pkt.ScenarioIdentifer.CategoryID, + pkt.ScenarioIdentifer.MainID, + pkt.ScenarioIdentifer.Flags, // Fist had as "type" and is the "T%d" + pkt.ScenarioIdentifer.ChapterID, + ) + + // Read the scenario file. + data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("scenarios/%s.bin", filename))) + if err != nil { + panic(err) + } + + doSizedAckResp(s, pkt.AckHandle, data) } } @@ -1175,7 +1208,58 @@ func handleMsgMhfPaymentAchievement(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfDisplayedAchievement(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { + + pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter) + + scenarioCounter := []struct { + Unk0 uint32 // Main ID? + Unk1 uint8 + Unk2 uint8 + }{ + { + Unk0: 0x00000000, + Unk1: 1, + Unk2: 4, + }, + { + Unk0: 0x00000001, + Unk1: 1, + Unk2: 4, + }, + { + Unk0: 0x00000002, + Unk1: 1, + Unk2: 4, + }, + { + Unk0: 0x00000003, + Unk1: 1, + Unk2: 4, + }, + } + + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(len(scenarioCounter))) // Entry count + for _, entry := range scenarioCounter { + resp.WriteUint32(entry.Unk0) + resp.WriteUint8(entry.Unk1) + resp.WriteUint8(entry.Unk2) + } + + doSizedAckResp(s, pkt.AckHandle, resp.Data()) + + // DEBUG, DELETE ME! + /* + data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "debug/info_scenario_counter_resp.bin")) + if err != nil { + panic(err) + } + + doSizedAckResp(s, pkt.AckHandle, data) + */ + +} func handleMsgMhfSaveScenarioData(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfSaveScenarioData)