From a6650bb3927761deb0f8c54d9d53c96da05e26e4 Mon Sep 17 00:00:00 2001 From: straticspaff Date: Mon, 3 Jul 2023 20:29:56 +0100 Subject: [PATCH 01/96] feat: added scenario counter driven by database --- patch-schema/scenarios-counter.sql | 9 + server/channelserver/handlers.go | 754 ++--------------------------- 2 files changed, 46 insertions(+), 717 deletions(-) create mode 100644 patch-schema/scenarios-counter.sql diff --git a/patch-schema/scenarios-counter.sql b/patch-schema/scenarios-counter.sql new file mode 100644 index 000000000..3ea2c65b2 --- /dev/null +++ b/patch-schema/scenarios-counter.sql @@ -0,0 +1,9 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS scenario_counter ( + id serial primary key, + scenario_id numeric not null, + category_id numeric not null +); + +END; \ No newline at end of file diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 4647b8021..f853675a1 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -15,8 +15,9 @@ import ( "crypto/rand" "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" - "go.uber.org/zap" "math/bits" + + "go.uber.org/zap" ) // Temporary function to just return no results for a MSG_MHF_ENUMERATE* packet @@ -776,726 +777,45 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { } func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { + type ScenarioCounterItem struct { + MainID uint32 `db:"scenario_id"` + CategoryID uint8 `db:"category_id"` // 0 = basic, 1 = veteran, 3 = other, 6 = pallone, 7 = diva + } + pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter) - scenarioCounter := []struct { - MainID uint32 - Unk1 uint8 // Bool item exchange? - // 0 = basic, 1 = veteran, 3 = other, 6 = pallone, 7 = diva - CategoryID uint8 - }{ - //000000110000 - { - MainID: 0x00000011, Unk1: 0, CategoryID: 0, - }, - // 0000005D0001 - { - MainID: 0x0000005D, Unk1: 0, CategoryID: 1, - }, - // 0000005C0001 - { - MainID: 0x0000005C, Unk1: 0, CategoryID: 1, - }, - // 000000510001 - { - MainID: 0x00000051, Unk1: 0, CategoryID: 1, - }, - // 0000005B0001 - { - MainID: 0x0000005B, Unk1: 0, CategoryID: 1, - }, - // 0000005A0001 - { - MainID: 0x0000005A, Unk1: 0, CategoryID: 1, - }, - // 000000590001 - { - MainID: 0x00000059, Unk1: 0, CategoryID: 1, - }, - // 000000580001 - { - MainID: 0x00000058, Unk1: 0, CategoryID: 1, - }, - // 000000570001 - { - MainID: 0x00000057, Unk1: 0, CategoryID: 1, - }, - // 000000560001 - { - MainID: 0x00000056, Unk1: 0, CategoryID: 1, - }, - // 000000550001 - { - MainID: 0x00000055, Unk1: 0, CategoryID: 1, - }, - // 000000540001 - { - MainID: 0x00000054, Unk1: 0, CategoryID: 1, - }, - // 000000530001 - { - MainID: 0x00000053, Unk1: 0, CategoryID: 1, - }, - // 000000520001 - { - MainID: 0x00000052, Unk1: 0, CategoryID: 1, - }, - // 000000570103 - { - MainID: 0x00000057, Unk1: 1, CategoryID: 3, - }, - // 000000580103 - { - MainID: 0x00000058, Unk1: 1, CategoryID: 3, - }, - // 000000590103 - { - MainID: 0x00000059, Unk1: 1, CategoryID: 3, - }, - // 0000005A0103 - { - MainID: 0x0000005A, Unk1: 1, CategoryID: 3, - }, - // 0000005B0103 - { - MainID: 0x0000005B, Unk1: 1, CategoryID: 3, - }, - // 0000005C0103 - { - MainID: 0x0000005C, Unk1: 1, CategoryID: 3, - }, - // 000000530103 - { - MainID: 0x00000053, Unk1: 1, CategoryID: 3, - }, - // 000000560103 - { - MainID: 0x00000056, Unk1: 1, CategoryID: 3, - }, - // 0000003C0103 - { - MainID: 0x0000003C, Unk1: 1, CategoryID: 3, - }, - // 0000003A0103 - { - MainID: 0x0000003A, Unk1: 1, CategoryID: 3, - }, - // 0000003B0103 - { - MainID: 0x0000003B, Unk1: 1, CategoryID: 3, - }, - // 0000001B0103 - { - MainID: 0x0000001B, Unk1: 1, CategoryID: 3, - }, - // 000000190103 - { - MainID: 0x00000019, Unk1: 1, CategoryID: 3, - }, - // 0000001A0103 - { - MainID: 0x0000001A, Unk1: 1, CategoryID: 3, - }, - // 000000170103 - { - MainID: 0x00000017, Unk1: 1, CategoryID: 3, - }, - // 000000020103 - { - MainID: 0x00000002, Unk1: 1, CategoryID: 3, - }, - // 000000030103 - { - MainID: 0x00000003, Unk1: 1, CategoryID: 3, - }, - // 000000040103 - { - MainID: 0x00000004, Unk1: 1, CategoryID: 3, - }, - // 0000001F0103 - { - MainID: 0x0000001F, Unk1: 1, CategoryID: 3, - }, - // 000000200103 - { - MainID: 0x00000020, Unk1: 1, CategoryID: 3, - }, - // 000000210103 - { - MainID: 0x00000021, Unk1: 1, CategoryID: 3, - }, - // 000000220103 - { - MainID: 0x00000022, Unk1: 1, CategoryID: 3, - }, - // 000000230103 - { - MainID: 0x00000023, Unk1: 1, CategoryID: 3, - }, - // 000000240103 - { - MainID: 0x00000024, Unk1: 1, CategoryID: 3, - }, - // 000000250103 - { - MainID: 0x00000025, Unk1: 1, CategoryID: 3, - }, - // 000000280103 - { - MainID: 0x00000028, Unk1: 1, CategoryID: 3, - }, - // 000000260103 - { - MainID: 0x00000026, Unk1: 1, CategoryID: 3, - }, - // 000000270103 - { - MainID: 0x00000027, Unk1: 1, CategoryID: 3, - }, - // 000000300103 - { - MainID: 0x00000030, Unk1: 1, CategoryID: 3, - }, - // 0000000C0103 - { - MainID: 0x0000000C, Unk1: 1, CategoryID: 3, - }, - // 0000000D0103 - { - MainID: 0x0000000D, Unk1: 1, CategoryID: 3, - }, - // 0000001E0103 - { - MainID: 0x0000001E, Unk1: 1, CategoryID: 3, - }, - // 0000001D0103 - { - MainID: 0x0000001D, Unk1: 1, CategoryID: 3, - }, - // 0000002E0003 - { - MainID: 0x0000002E, Unk1: 0, CategoryID: 3, - }, - // 000000000004 - { - MainID: 0x00000000, Unk1: 0, CategoryID: 4, - }, - // 000000010004 - { - MainID: 0x00000001, Unk1: 0, CategoryID: 4, - }, - // 000000020004 - { - MainID: 0x00000002, Unk1: 0, CategoryID: 4, - }, - // 000000030004 - { - MainID: 0x00000003, Unk1: 0, CategoryID: 4, - }, - // 000000040004 - { - MainID: 0x00000004, Unk1: 0, CategoryID: 4, - }, - // 000000050004 - { - MainID: 0x00000005, Unk1: 0, CategoryID: 4, - }, - // 000000060004 - { - MainID: 0x00000006, Unk1: 0, CategoryID: 4, - }, - // 000000070004 - { - MainID: 0x00000007, Unk1: 0, CategoryID: 4, - }, - // 000000080004 - { - MainID: 0x00000008, Unk1: 0, CategoryID: 4, - }, - // 000000090004 - { - MainID: 0x00000009, Unk1: 0, CategoryID: 4, - }, - // 0000000A0004 - { - MainID: 0x0000000A, Unk1: 0, CategoryID: 4, - }, - // 0000000B0004 - { - MainID: 0x0000000B, Unk1: 0, CategoryID: 4, - }, - // 0000000C0004 - { - MainID: 0x0000000C, Unk1: 0, CategoryID: 4, - }, - // 0000000D0004 - { - MainID: 0x0000000D, Unk1: 0, CategoryID: 4, - }, - // 0000000E0004 - { - MainID: 0x0000000E, Unk1: 0, CategoryID: 4, - }, - // 000000320005 - { - MainID: 0x00000032, Unk1: 0, CategoryID: 5, - }, - // 000000330005 - { - MainID: 0x00000033, Unk1: 0, CategoryID: 5, - }, - // 000000340005 - { - MainID: 0x00000034, Unk1: 0, CategoryID: 5, - }, - // 000000350005 - { - MainID: 0x00000035, Unk1: 0, CategoryID: 5, - }, - // 000000360005 - { - MainID: 0x00000036, Unk1: 0, CategoryID: 5, - }, - // 000000370005 - { - MainID: 0x00000037, Unk1: 0, CategoryID: 5, - }, - // 000000380005 - { - MainID: 0x00000038, Unk1: 0, CategoryID: 5, - }, - // 0000003A0005 - { - MainID: 0x0000003A, Unk1: 0, CategoryID: 5, - }, - // 0000003F0005 - { - MainID: 0x0000003F, Unk1: 0, CategoryID: 5, - }, - // 000000400005 - { - MainID: 0x00000040, Unk1: 0, CategoryID: 5, - }, - // 000000410005 - { - MainID: 0x00000041, Unk1: 0, CategoryID: 5, - }, - // 000000430005 - { - MainID: 0x00000043, Unk1: 0, CategoryID: 5, - }, - // 000000470005 - { - MainID: 0x00000047, Unk1: 0, CategoryID: 5, - }, - // 0000004B0005 - { - MainID: 0x0000004B, Unk1: 0, CategoryID: 5, - }, - // 0000003D0005 - { - MainID: 0x0000003D, Unk1: 0, CategoryID: 5, - }, - // 000000440005 - { - MainID: 0x00000044, Unk1: 0, CategoryID: 5, - }, - // 000000420005 - { - MainID: 0x00000042, Unk1: 0, CategoryID: 5, - }, - // 0000004C0005 - { - MainID: 0x0000004C, Unk1: 0, CategoryID: 5, - }, - // 000000460005 - { - MainID: 0x00000046, Unk1: 0, CategoryID: 5, - }, - // 0000004D0005 - { - MainID: 0x0000004D, Unk1: 0, CategoryID: 5, - }, - // 000000480005 - { - MainID: 0x00000048, Unk1: 0, CategoryID: 5, - }, - // 0000004A0005 - { - MainID: 0x0000004A, Unk1: 0, CategoryID: 5, - }, - // 000000490005 - { - MainID: 0x00000049, Unk1: 0, CategoryID: 5, - }, - // 0000004E0005 - { - MainID: 0x0000004E, Unk1: 0, CategoryID: 5, - }, - // 000000450005 - { - MainID: 0x00000045, Unk1: 0, CategoryID: 5, - }, - // 0000003E0005 - { - MainID: 0x0000003E, Unk1: 0, CategoryID: 5, - }, - // 0000004F0005 - { - MainID: 0x0000004F, Unk1: 0, CategoryID: 5, - }, - // 000000000106 - { - MainID: 0x00000000, Unk1: 1, CategoryID: 6, - }, - // 000000010106 - { - MainID: 0x00000001, Unk1: 1, CategoryID: 6, - }, - // 000000020106 - { - MainID: 0x00000002, Unk1: 1, CategoryID: 6, - }, - // 000000030106 - { - MainID: 0x00000003, Unk1: 1, CategoryID: 6, - }, - // 000000040106 - { - MainID: 0x00000004, Unk1: 1, CategoryID: 6, - }, - // 000000050106 - { - MainID: 0x00000005, Unk1: 1, CategoryID: 6, - }, - // 000000060106 - { - MainID: 0x00000006, Unk1: 1, CategoryID: 6, - }, - // 000000070106 - { - MainID: 0x00000007, Unk1: 1, CategoryID: 6, - }, - // 000000080106 - { - MainID: 0x00000008, Unk1: 1, CategoryID: 6, - }, - // 000000090106 - { - MainID: 0x00000009, Unk1: 1, CategoryID: 6, - }, - // 000000110106 - { - MainID: 0x00000011, Unk1: 1, CategoryID: 6, - }, - // 0000000A0106 - { - MainID: 0x0000000A, Unk1: 1, CategoryID: 6, - }, - // 0000000B0106 - { - MainID: 0x0000000B, Unk1: 1, CategoryID: 6, - }, - // 0000000C0106 - { - MainID: 0x0000000C, Unk1: 1, CategoryID: 6, - }, - // 0000000D0106 - { - MainID: 0x0000000D, Unk1: 1, CategoryID: 6, - }, - // 0000000E0106 - { - MainID: 0x0000000E, Unk1: 1, CategoryID: 6, - }, - // 0000000F0106 - { - MainID: 0x0000000F, Unk1: 1, CategoryID: 6, - }, - // 000000100106 - { - MainID: 0x00000010, Unk1: 1, CategoryID: 6, - }, - // 000000320107 - { - MainID: 0x00000032, Unk1: 1, CategoryID: 7, - }, - // 000000350107 - { - MainID: 0x00000035, Unk1: 1, CategoryID: 7, - }, - // 0000003E0107 - { - MainID: 0x0000003E, Unk1: 1, CategoryID: 7, - }, - // 000000340107 - { - MainID: 0x00000034, Unk1: 1, CategoryID: 7, - }, - // 000000380107 - { - MainID: 0x00000038, Unk1: 1, CategoryID: 7, - }, - // 000000330107 - { - MainID: 0x00000033, Unk1: 1, CategoryID: 7, - }, - // 000000310107 - { - MainID: 0x00000031, Unk1: 1, CategoryID: 7, - }, - // 000000360107 - { - MainID: 0x00000036, Unk1: 1, CategoryID: 7, - }, - // 000000390107 - { - MainID: 0x00000039, Unk1: 1, CategoryID: 7, - }, - // 000000370107 - { - MainID: 0x00000037, Unk1: 1, CategoryID: 7, - }, - // 0000003D0107 - { - MainID: 0x0000003D, Unk1: 1, CategoryID: 7, - }, - // 0000003A0107 - { - MainID: 0x0000003A, Unk1: 1, CategoryID: 7, - }, - // 0000003C0107 - { - MainID: 0x0000003C, Unk1: 1, CategoryID: 7, - }, - // 0000003B0107 - { - MainID: 0x0000003B, Unk1: 1, CategoryID: 7, - }, - // 0000002A0107 - { - MainID: 0x0000002A, Unk1: 1, CategoryID: 7, - }, - // 000000300107 - { - MainID: 0x00000030, Unk1: 1, CategoryID: 7, - }, - // 000000280107 - { - MainID: 0x00000028, Unk1: 1, CategoryID: 7, - }, - // 000000270107 - { - MainID: 0x00000027, Unk1: 1, CategoryID: 7, - }, - // 0000002B0107 - { - MainID: 0x0000002B, Unk1: 1, CategoryID: 7, - }, - // 0000002E0107 - { - MainID: 0x0000002E, Unk1: 1, CategoryID: 7, - }, - // 000000290107 - { - MainID: 0x00000029, Unk1: 1, CategoryID: 7, - }, - // 0000002C0107 - { - MainID: 0x0000002C, Unk1: 1, CategoryID: 7, - }, - // 0000002D0107 - { - MainID: 0x0000002D, Unk1: 1, CategoryID: 7, - }, - // 0000002F0107 - { - MainID: 0x0000002F, Unk1: 1, CategoryID: 7, - }, - // 000000250107 - { - MainID: 0x00000025, Unk1: 1, CategoryID: 7, - }, - // 000000220107 - { - MainID: 0x00000022, Unk1: 1, CategoryID: 7, - }, - // 000000210107 - { - MainID: 0x00000021, Unk1: 1, CategoryID: 7, - }, - // 000000200107 - { - MainID: 0x00000020, Unk1: 1, CategoryID: 7, - }, - // 0000001C0107 - { - MainID: 0x0000001C, Unk1: 1, CategoryID: 7, - }, - // 0000001A0107 - { - MainID: 0x0000001A, Unk1: 1, CategoryID: 7, - }, - // 000000240107 - { - MainID: 0x00000024, Unk1: 1, CategoryID: 7, - }, - // 000000260107 - { - MainID: 0x00000026, Unk1: 1, CategoryID: 7, - }, - // 000000230107 - { - MainID: 0x00000023, Unk1: 1, CategoryID: 7, - }, - // 0000001B0107 - { - MainID: 0x0000001B, Unk1: 1, CategoryID: 7, - }, - // 0000001E0107 - { - MainID: 0x0000001E, Unk1: 1, CategoryID: 7, - }, - // 0000001F0107 - { - MainID: 0x0000001F, Unk1: 1, CategoryID: 7, - }, - // 0000001D0107 - { - MainID: 0x0000001D, Unk1: 1, CategoryID: 7, - }, - // 000000180107 - { - MainID: 0x00000018, Unk1: 1, CategoryID: 7, - }, - // 000000170107 - { - MainID: 0x00000017, Unk1: 1, CategoryID: 7, - }, - // 000000160107 - { - MainID: 0x00000016, Unk1: 1, CategoryID: 7, - }, - // 000000150107 - // Missing file - // { - // MainID: 0x00000015, Unk1: 1, CategoryID: 7, - // }, - // 000000190107 - { - MainID: 0x00000019, Unk1: 1, CategoryID: 7, - }, - // 000000140107 - // Missing file - // { - // MainID: 0x00000014, Unk1: 1, CategoryID: 7, - // }, - // 000000070107 - // Missing file - // { - // MainID: 0x00000007, Unk1: 1, CategoryID: 7, - // }, - // 000000090107 - // Missing file - // { - // MainID: 0x00000009, Unk1: 1, CategoryID: 7, - // }, - // 0000000D0107 - // Missing file - // { - // MainID: 0x0000000D, Unk1: 1, CategoryID: 7, - // }, - // 000000100107 - // Missing file - // { - // MainID: 0x00000010, Unk1: 1, CategoryID: 7, - // }, - // 0000000C0107 - // Missing file - // { - // MainID: 0x0000000C, Unk1: 1, CategoryID: 7, - // }, - // 0000000E0107 - // Missing file - // { - // MainID: 0x0000000E, Unk1: 1, CategoryID: 7, - // }, - // 0000000F0107 - // Missing file - // { - // MainID: 0x0000000F, Unk1: 1, CategoryID: 7, - // }, - // 000000130107 - // Missing file - // { - // MainID: 0x00000013, Unk1: 1, CategoryID: 7, - // }, - // 0000000A0107 - // Missing file - // { - // MainID: 0x0000000A, Unk1: 1, CategoryID: 7, - // }, - // 000000080107 - // Missing file - // { - // MainID: 0x00000008, Unk1: 1, CategoryID: 7, - // }, - // 0000000B0107 - // Missing file - // { - // MainID: 0x0000000B, Unk1: 1, CategoryID: 7, - // }, - // 000000120107 - // Missing file - // { - // MainID: 0x00000012, Unk1: 1, CategoryID: 7, - // }, - // 000000110107 - // Missing file - // { - // MainID: 0x00000011, Unk1: 1, CategoryID: 7, - // }, - // 000000060107 - // Missing file - // { - // MainID: 0x00000006, Unk1: 1, CategoryID: 7, - // }, - // 000000050107 - // Missing file - // { - // MainID: 0x00000005, Unk1: 1, CategoryID: 7, - // }, - // 000000040107 - // Missing file - // { - // MainID: 0x00000004, Unk1: 1, CategoryID: 7, - // }, - // 000000030107 - { - MainID: 0x00000003, Unk1: 1, CategoryID: 7, - }, - // 000000020107 - { - MainID: 0x00000002, Unk1: 1, CategoryID: 7, - }, - // 000000010107 - { - MainID: 0x00000001, Unk1: 1, CategoryID: 7, - }, - // 000000000107 - { - MainID: 0x00000000, Unk1: 1, CategoryID: 7, - }, + + scenarioData, err := s.server.db.Queryx("SELECT scenario_id, category_id FROM scenario_counter") + if err != nil { + s.logger.Error("Failed to get scenario counter info from db", zap.Error(err)) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + return + } + bf := byteframe.NewByteFrame() + var scenarioCount uint32 + for scenarioData.Next() { + postData := &ScenarioCounterItem{} + err = scenarioData.StructScan(&postData) + if err != nil { + continue + } + scenarioCount++ + bf.WriteUint32(postData.MainID) + // if item exchange + if postData.CategoryID == 3 || postData.CategoryID == 6 || postData.CategoryID == 7 { + bf.WriteUint8(1) + + } else { + bf.WriteUint8(0) + + } + bf.WriteUint8(postData.CategoryID) } - resp := byteframe.NewByteFrame() - resp.WriteUint8(uint8(len(scenarioCounter))) // Entry count - for _, entry := range scenarioCounter { - resp.WriteUint32(entry.MainID) - resp.WriteUint8(entry.Unk1) - resp.WriteUint8(entry.CategoryID) - } + data := byteframe.NewByteFrame() + data.WriteUint8(uint8(scenarioCount)) // Entry count + data.WriteBytes(bf.Data()) + doAckBufSucceed(s, pkt.AckHandle, data.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) { From b46f0354d61c7b015a4ceee6f1ea1b0e0f7932fe Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 8 Jul 2023 00:41:03 +1000 Subject: [PATCH 02/96] typing and formatting review --- server/channelserver/handlers.go | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index f853675a1..bb6aa75b4 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -776,14 +776,13 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } +type ScenarioCounterItem struct { + MainID uint32 `db:"scenario_id"` + CategoryID uint8 `db:"category_id"` // 0 = basic, 1 = veteran, 3 = other, 6 = pallone, 7 = diva +} + func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { - type ScenarioCounterItem struct { - MainID uint32 `db:"scenario_id"` - CategoryID uint8 `db:"category_id"` // 0 = basic, 1 = veteran, 3 = other, 6 = pallone, 7 = diva - } - pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter) - scenarioData, err := s.server.db.Queryx("SELECT scenario_id, category_id FROM scenario_counter") if err != nil { s.logger.Error("Failed to get scenario counter info from db", zap.Error(err)) @@ -791,31 +790,28 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { return } bf := byteframe.NewByteFrame() - var scenarioCount uint32 + var scenarioCount uint8 for scenarioData.Next() { - postData := &ScenarioCounterItem{} - err = scenarioData.StructScan(&postData) + scenario := &ScenarioCounterItem{} + err = scenarioData.StructScan(&scenario) if err != nil { continue } scenarioCount++ - bf.WriteUint32(postData.MainID) + bf.WriteUint32(scenario.MainID) // if item exchange - if postData.CategoryID == 3 || postData.CategoryID == 6 || postData.CategoryID == 7 { - bf.WriteUint8(1) - + if scenario.CategoryID == 3 || scenario.CategoryID == 6 || scenario.CategoryID == 7 { + bf.WriteBool(true) } else { - bf.WriteUint8(0) - + bf.WriteBool(false) } - bf.WriteUint8(postData.CategoryID) + bf.WriteUint8(scenario.CategoryID) } data := byteframe.NewByteFrame() - data.WriteUint8(uint8(scenarioCount)) // Entry count + data.WriteUint8(scenarioCount) data.WriteBytes(bf.Data()) doAckBufSucceed(s, pkt.AckHandle, data.Data()) - } func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) { From 229e9323ba4bfc6579a917cb248984b0445d20da Mon Sep 17 00:00:00 2001 From: straticspaff Date: Fri, 7 Jul 2023 23:38:24 +0100 Subject: [PATCH 03/96] feat: added veteran + beginner scenarios --- bundled-schema/DefaultScenarios.sql | 120 ++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 bundled-schema/DefaultScenarios.sql diff --git a/bundled-schema/DefaultScenarios.sql b/bundled-schema/DefaultScenarios.sql new file mode 100644 index 000000000..d3eb2899a --- /dev/null +++ b/bundled-schema/DefaultScenarios.sql @@ -0,0 +1,120 @@ +BEGIN; + +INSERT INTO public.scenario_counter +(scenario_id, category_id) +VALUES + (0,0), + (1,0), + (2,0), + (3,0), + (4,0), + (5,0), + (6,0), + (7,0), + (8,0), + (9,0), + (10,0), + (11,0), + (12,0), + (13,0), + (14,0), + (15,0), + (16,0), + (17,0), + (18,0), + (19,0), + (0,1), + (1,1), + (2,1), + (3,1), + (4,1), + (5,1), + (6,1), + (7,1), + (8,1), + (9,1), + (10,1), + (11,1), + (12,1), + (13,1), + (16,1), + (17,1), + (19,1), + (21,1), + (22,1), + (23,1), + (27,1), + (28,1), + (29,1), + (30,1), + (31,1), + (32,1), + (33,1), + (34,1), + (35,1), + (36,1), + (37,1), + (38,1), + (39,1), + (41,1), + (42,1), + (43,1), + (46,1), + (47,1), + (48,1), + (49,1), + (58,1), + (59,1), + (60,1), + (61,1), + (62,1), + (63,1), + (64,1), + (65,1), + (66,1), + (67,1), + (68,1), + (69,1), + (70,1), + (77,1), + (79,1), + (81,1), + (82,1), + (83,1), + (84,1), + (85,1), + (86,1), + (87,1), + (88,1), + (89,1), + (90,1), + (92,1), + (93,1), + (13,1), + (14,1), + (15,1), + (18,1), + (20,1), + (24,1), + (25,1), + (26,1), + (40,1), + (50,1), + (51,1), + (52,1), + (53,1), + (54,1), + (55,1), + (56,1), + (57,1), + (71,1), + (72,1), + (73,1), + (74,1), + (75,1), + (76,1), + (78,1), + (80,1), + (91,1); + +END; \ No newline at end of file From 3fc9a6f2ac33d9abcb62afa135215c28e9196346 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Jul 2023 00:34:56 +1000 Subject: [PATCH 04/96] clean up InfoScenarioCounter --- server/channelserver/handlers.go | 43 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index bb6aa75b4..c94003ffb 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -776,42 +776,53 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } -type ScenarioCounterItem struct { - MainID uint32 `db:"scenario_id"` - CategoryID uint8 `db:"category_id"` // 0 = basic, 1 = veteran, 3 = other, 6 = pallone, 7 = diva +type Scenario struct { + MainID uint32 + // 0 = Basic + // 1 = Veteran + // 3 = Other + // 6 = Pallone + // 7 = Diva + CategoryID uint8 } func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfInfoScenarioCounter) + var scenarios []Scenario + var scenario Scenario scenarioData, err := s.server.db.Queryx("SELECT scenario_id, category_id FROM scenario_counter") if err != nil { + scenarioData.Close() s.logger.Error("Failed to get scenario counter info from db", zap.Error(err)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) return } - bf := byteframe.NewByteFrame() - var scenarioCount uint8 for scenarioData.Next() { - scenario := &ScenarioCounterItem{} - err = scenarioData.StructScan(&scenario) + err = scenarioData.Scan(&scenario.MainID, &scenario.CategoryID) if err != nil { continue } - scenarioCount++ + } + + // Trim excess scenarios + if len(scenarios) > 128 { + scenarios = scenarios[:128] + } + + bf := byteframe.NewByteFrame() + bf.WriteUint8(uint8(len(scenarios))) + for _, scenario := range scenarios { bf.WriteUint32(scenario.MainID) - // if item exchange - if scenario.CategoryID == 3 || scenario.CategoryID == 6 || scenario.CategoryID == 7 { + // If item exchange + switch scenario.CategoryID { + case 3, 6, 7: bf.WriteBool(true) - } else { + default: bf.WriteBool(false) } bf.WriteUint8(scenario.CategoryID) } - - data := byteframe.NewByteFrame() - data.WriteUint8(scenarioCount) - data.WriteBytes(bf.Data()) - doAckBufSucceed(s, pkt.AckHandle, data.Data()) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) { From 9886f81b2b62d68cd63fb47931811241c1e790f3 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 9 Jul 2023 01:05:27 +1000 Subject: [PATCH 05/96] fix scenario responses --- server/channelserver/handlers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index c94003ffb..4ff31dab3 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -794,7 +794,7 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { if err != nil { scenarioData.Close() s.logger.Error("Failed to get scenario counter info from db", zap.Error(err)) - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 1)) return } for scenarioData.Next() { @@ -802,6 +802,7 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { if err != nil { continue } + scenarios = append(scenarios, scenario) } // Trim excess scenarios From 478e5230ccf62200c1a87d9ffb4ec5528ffdf0c4 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 23 Jul 2023 16:24:41 +1000 Subject: [PATCH 06/96] rewrite chat commands into args processor --- config.json | 14 +- server/channelserver/handlers_cast_binary.go | 142 ++++++++----------- 2 files changed, 69 insertions(+), 87 deletions(-) diff --git a/config.json b/config.json index e752a93f1..c93e948ca 100644 --- a/config.json +++ b/config.json @@ -70,31 +70,31 @@ { "Name": "Rights", "Enabled": false, - "Prefix": "!rights" + "Prefix": "rights" }, { "Name": "Raviente", "Enabled": true, - "Prefix": "!ravi" + "Prefix": "ravi" }, { "Name": "Teleport", "Enabled": false, - "Prefix": "!tele" + "Prefix": "tele" }, { "Name": "Reload", "Enabled": true, - "Prefix": "!reload" + "Prefix": "reload" }, { "Name": "KeyQuest", "Enabled": false, - "Prefix": "!kqf" + "Prefix": "kqf" }, { "Name": "Course", "Enabled": true, - "Prefix": "!course" + "Prefix": "course" }, { "Name": "PSN", "Enabled": true, - "Prefix": "!psn" + "Prefix": "psn" } ], "Courses": [ diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 3e950657f..977e789da 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -11,6 +11,7 @@ import ( "fmt" "golang.org/x/exp/slices" "math" + "strconv" "strings" "time" @@ -82,23 +83,22 @@ func sendServerChatMessage(s *Session, message string) { } func parseChatCommand(s *Session, command string) { - if strings.HasPrefix(command, commands["PSN"].Prefix) { + args := strings.Split(command[1:], " ") + switch args[0] { + case commands["PSN"].Prefix: if commands["PSN"].Enabled { - var id string - n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%s", commands["PSN"].Prefix), &id) - if err != nil || n != 1 { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNError"], commands["PSN"].Prefix)) - } else { - _, err = s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, id, s.charID) + if len(args) > 1 { + _, err := s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, args[1], s.charID) if err == nil { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNSuccess"], id)) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNSuccess"], args[1])) } + } else { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNError"], commands["PSN"].Prefix)) } + } else { + sendDisabledCommandMessage(s, commands["PSN"]) } - } - - if strings.HasPrefix(command, commands["Reload"].Prefix) { - // Flush all objects and users and reload + case commands["Reload"].Prefix: if commands["Reload"].Enabled { sendServerChatMessage(s, s.server.dict["commandReload"]) var temp mhfpacket.MHFPacket @@ -159,64 +159,53 @@ func parseChatCommand(s *Session, command string) { } else { sendDisabledCommandMessage(s, commands["Reload"]) } - } - - if strings.HasPrefix(command, commands["KeyQuest"].Prefix) { + case commands["KeyQuest"].Prefix: if commands["KeyQuest"].Enabled { - if strings.HasPrefix(command, fmt.Sprintf("%s get", commands["KeyQuest"].Prefix)) { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandKqfGet"], s.kqf)) - } else if strings.HasPrefix(command, fmt.Sprintf("%s set", commands["KeyQuest"].Prefix)) { - var hexs string - n, numerr := fmt.Sscanf(command, fmt.Sprintf("%s set %%s", commands["KeyQuest"].Prefix), &hexs) - if numerr != nil || n != 1 || len(hexs) != 16 { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandKqfSetError"], commands["KeyQuest"].Prefix)) - } else { - hexd, _ := hex.DecodeString(hexs) - s.kqf = hexd - s.kqfOverride = true - sendServerChatMessage(s, s.server.dict["commandKqfSetSuccess"]) + if len(args) > 1 { + if args[1] == "get" { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandKqfGet"], s.kqf)) + } else if args[1] == "set" { + if len(args) > 2 && len(args[2]) == 16 { + hexd, _ := hex.DecodeString(args[2]) + s.kqf = hexd + s.kqfOverride = true + sendServerChatMessage(s, s.server.dict["commandKqfSetSuccess"]) + } else { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandKqfSetError"], commands["KeyQuest"].Prefix)) + } } } } else { sendDisabledCommandMessage(s, commands["KeyQuest"]) } - } - - if strings.HasPrefix(command, commands["Rights"].Prefix) { - // Set account rights + case commands["Rights"].Prefix: if commands["Rights"].Enabled { - var v uint32 - n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%d", commands["Rights"].Prefix), &v) - if err != nil || n != 1 { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRightsError"], commands["Rights"].Prefix)) - } else { - _, err = s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID) + if len(args) > 1 { + v, _ := strconv.Atoi(args[1]) + _, err := s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", v, s.charID) if err == nil { sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRightsSuccess"], v)) + } else { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRightsError"], commands["Rights"].Prefix)) } + } else { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRightsError"], commands["Rights"].Prefix)) } } else { sendDisabledCommandMessage(s, commands["Rights"]) } - } - - if strings.HasPrefix(command, commands["Course"].Prefix) { + case commands["Course"].Prefix: if commands["Course"].Enabled { - var name string - n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%s", commands["Course"].Prefix), &name) - if err != nil || n != 1 { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix)) - } else { - name = strings.ToLower(name) + if len(args) > 1 { for _, course := range mhfcourse.Courses() { for _, alias := range course.Aliases() { - if strings.ToLower(name) == strings.ToLower(alias) { + if strings.ToLower(args[1]) == strings.ToLower(alias) { if slices.Contains(s.server.erupeConfig.Courses, _config.Course{Name: course.Aliases()[0], Enabled: true}) { var delta, rightsInt uint32 if mhfcourse.CourseExists(course.ID, s.courses) { ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool { for _, alias := range c.Aliases() { - if strings.ToLower(name) == strings.ToLower(alias) { + if strings.ToLower(args[1]) == strings.ToLower(alias) { return true } } @@ -230,7 +219,7 @@ func parseChatCommand(s *Session, command string) { delta = uint32(math.Pow(2, float64(course.ID))) sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases()[0])) } - err = s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt) + err := s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt) if err == nil { s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.charID) } @@ -242,21 +231,18 @@ func parseChatCommand(s *Session, command string) { } } } + } else { sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix)) } } else { sendDisabledCommandMessage(s, commands["Course"]) } - } - - if strings.HasPrefix(command, commands["Raviente"].Prefix) { + case commands["Raviente"].Prefix: if commands["Raviente"].Enabled { - if getRaviSemaphore(s.server) != nil { - s.server.raviente.Lock() - if !strings.HasPrefix(command, "!ravi ") { - sendServerChatMessage(s, s.server.dict["commandRaviNoCommand"]) - } else { - if strings.HasPrefix(command, "!ravi start") { + if len(args) > 1 { + if getRaviSemaphore(s.server) != nil { + switch args[1] { + case "start": if s.server.raviente.register.startTime == 0 { s.server.raviente.register.startTime = s.server.raviente.register.postTime sendServerChatMessage(s, s.server.dict["commandRaviStartSuccess"]) @@ -264,60 +250,56 @@ func parseChatCommand(s *Session, command string) { } else { sendServerChatMessage(s, s.server.dict["commandRaviStartError"]) } - } else if strings.HasPrefix(command, "!ravi cm") || strings.HasPrefix(command, "!ravi checkmultiplier") { + case "cm", "check", "checkmultiplier", "multiplier": sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.raviente.GetRaviMultiplier(s.server))) - } else if strings.HasPrefix(command, "!ravi sr") || strings.HasPrefix(command, "!ravi sendres") { + case "sr", "sendres", "resurrection": if s.server.raviente.state.stateData[28] > 0 { sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"]) s.server.raviente.state.stateData[28] = 0 } else { sendServerChatMessage(s, s.server.dict["commandRaviResError"]) } - } else if strings.HasPrefix(command, "!ravi ss") || strings.HasPrefix(command, "!ravi sendsed") { + case "ss", "sendsed": sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"]) // Total BerRavi HP HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4] s.server.raviente.support.supportData[1] = HP - } else if strings.HasPrefix(command, "!ravi rs") || strings.HasPrefix(command, "!ravi reqsed") { + case "rs", "reqsed": sendServerChatMessage(s, s.server.dict["commandRaviRequest"]) // Total BerRavi HP HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4] s.server.raviente.support.supportData[1] = HP + 12 - } else { + default: sendServerChatMessage(s, s.server.dict["commandRaviError"]) } + } else { + sendServerChatMessage(s, s.server.dict["commandRaviNoPlayers"]) } - s.server.raviente.Unlock() } else { - sendServerChatMessage(s, s.server.dict["commandRaviNoPlayers"]) + sendServerChatMessage(s, s.server.dict["commandRaviError"]) } } else { sendDisabledCommandMessage(s, commands["Raviente"]) } - } - - if strings.HasPrefix(command, commands["Teleport"].Prefix) { + case commands["Teleport"].Prefix: if commands["Teleport"].Enabled { - var x, y int16 - n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%d %%d", commands["Teleport"].Prefix), &x, &y) - if err != nil || n != 2 { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandTeleportError"], commands["Teleport"].Prefix)) - } else { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandTeleportSuccess"], x, y)) - - // Make the inside of the casted binary + if len(args) > 2 { + x, _ := strconv.Atoi(args[1]) + y, _ := strconv.Atoi(args[2]) payload := byteframe.NewByteFrame() payload.SetLE() - payload.WriteUint8(2) // SetState type(position == 2) - payload.WriteInt16(x) // X - payload.WriteInt16(y) // Y + payload.WriteUint8(2) // SetState type(position == 2) + payload.WriteInt16(int16(x)) // X + payload.WriteInt16(int16(y)) // Y payloadBytes := payload.Data() - s.QueueSendMHF(&mhfpacket.MsgSysCastedBinary{ CharID: s.charID, MessageType: BinaryMessageTypeState, RawDataPayload: payloadBytes, }) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandTeleportSuccess"], x, y)) + } else { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandTeleportError"], commands["Teleport"].Prefix)) } } else { sendDisabledCommandMessage(s, commands["Teleport"]) From 1685f409e711bfa10aec273921f3cfd5c8dbfb78 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 27 Aug 2023 22:16:51 +1000 Subject: [PATCH 07/96] initial ravi-v3 commit --- network/mhfpacket/msg_sys_load_register.go | 4 +- network/mhfpacket/msg_sys_operate_register.go | 3 +- server/channelserver/handlers_cast_binary.go | 18 +- server/channelserver/handlers_register.go | 281 +++--------------- server/channelserver/sys_channel_server.go | 86 +++--- 5 files changed, 103 insertions(+), 289 deletions(-) diff --git a/network/mhfpacket/msg_sys_load_register.go b/network/mhfpacket/msg_sys_load_register.go index 730616d65..7e1ac5950 100644 --- a/network/mhfpacket/msg_sys_load_register.go +++ b/network/mhfpacket/msg_sys_load_register.go @@ -11,7 +11,7 @@ import ( type MsgSysLoadRegister struct { AckHandle uint32 RegisterID uint32 - Unk1 uint8 + Values uint8 } // Opcode returns the ID associated with this packet type. @@ -23,7 +23,7 @@ func (m *MsgSysLoadRegister) Opcode() network.PacketID { func (m *MsgSysLoadRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.RegisterID = bf.ReadUint32() - m.Unk1 = bf.ReadUint8() + m.Values = bf.ReadUint8() _ = bf.ReadUint8() _ = bf.ReadUint16() return nil diff --git a/network/mhfpacket/msg_sys_operate_register.go b/network/mhfpacket/msg_sys_operate_register.go index 6978609b1..c51a483e3 100644 --- a/network/mhfpacket/msg_sys_operate_register.go +++ b/network/mhfpacket/msg_sys_operate_register.go @@ -25,7 +25,8 @@ func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl m.SemaphoreID = bf.ReadUint32() _ = bf.ReadUint16() dataSize := bf.ReadUint16() - m.RawDataPayload = bf.ReadBytes(uint(dataSize)) + m.RawDataPayload = bf.ReadBytes(uint(dataSize) - 1) + _ = bf.ReadBytes(1) // Null terminator return nil } diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index d93cf1a04..bd6ea053c 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -263,32 +263,32 @@ func parseChatCommand(s *Session, command string) { sendServerChatMessage(s, s.server.dict["commandRaviNoCommand"]) } else { if strings.HasPrefix(command, "!ravi start") { - if s.server.raviente.register.startTime == 0 { - s.server.raviente.register.startTime = s.server.raviente.register.postTime + if s.server.raviente.register[1] == 0 { + s.server.raviente.register[1] = s.server.raviente.register[3] sendServerChatMessage(s, s.server.dict["commandRaviStartSuccess"]) s.notifyRavi() } else { sendServerChatMessage(s, s.server.dict["commandRaviStartError"]) } } else if strings.HasPrefix(command, "!ravi cm") || strings.HasPrefix(command, "!ravi checkmultiplier") { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.raviente.GetRaviMultiplier(s.server))) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.GetRaviMultiplier())) } else if strings.HasPrefix(command, "!ravi sr") || strings.HasPrefix(command, "!ravi sendres") { - if s.server.raviente.state.stateData[28] > 0 { + if s.server.raviente.state[28] > 0 { sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"]) - s.server.raviente.state.stateData[28] = 0 + s.server.raviente.state[28] = 0 } else { sendServerChatMessage(s, s.server.dict["commandRaviResError"]) } } else if strings.HasPrefix(command, "!ravi ss") || strings.HasPrefix(command, "!ravi sendsed") { sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"]) // Total BerRavi HP - HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4] - s.server.raviente.support.supportData[1] = HP + HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] + s.server.raviente.support[1] = HP } else if strings.HasPrefix(command, "!ravi rs") || strings.HasPrefix(command, "!ravi reqsed") { sendServerChatMessage(s, s.server.dict["commandRaviRequest"]) // Total BerRavi HP - HP := s.server.raviente.state.stateData[0] + s.server.raviente.state.stateData[1] + s.server.raviente.state.stateData[2] + s.server.raviente.state.stateData[3] + s.server.raviente.state.stateData[4] - s.server.raviente.support.supportData[1] = HP + 12 + HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] + s.server.raviente.support[1] = HP + 12 } else { sendServerChatMessage(s, s.server.dict["commandRaviError"]) } diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index 33261a94e..be423d206 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -3,243 +3,69 @@ package channelserver import ( "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" + "go.uber.org/zap" "strings" ) +type RaviUpdate struct { + Op uint8 + Dest uint8 + Data uint32 +} + func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysOperateRegister) + + var raviUpdates []RaviUpdate + var raviUpdate RaviUpdate bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) - s.server.raviente.Lock() - switch pkt.SemaphoreID { - case 4: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - ref := &s.server.raviente.state.stateData[dest] - damageMultiplier := s.server.raviente.GetRaviMultiplier(s.server) - switch op { - case 2: - resp.WriteUint32(*ref) - if dest == 28 { // Berserk resurrection tracker - resp.WriteUint32(*ref + data) - *ref += data - } else if dest == 17 { // Berserk poison tracker - if damageMultiplier == 1 { - resp.WriteUint32(*ref + data) - *ref += data - } else { - resp.WriteUint32(*ref) - } - } else { - data = uint32(float64(data) * damageMultiplier) - resp.WriteUint32(*ref + data) - *ref += data - } - case 13: - fallthrough - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 5: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - ref := &s.server.raviente.support.supportData[dest] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - fallthrough - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 6: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - switch dest { - case 0: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.nextTime = data - case 1: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.startTime = data - case 2: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.killedTime = data - case 3: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.postTime = data - case 4: - ref := &s.server.raviente.register.register[0] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 5: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.carveQuest = data - case 6: - ref := &s.server.raviente.register.register[1] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 7: - ref := &s.server.raviente.register.register[2] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 8: - ref := &s.server.raviente.register.register[3] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 9: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.maxPlayers = data - case 10: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.ravienteType = data - case 11: - ref := &s.server.raviente.register.register[4] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + data) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - default: - resp.WriteUint32(0) - resp.WriteUint32(0) - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + for i := len(pkt.RawDataPayload) / 6; i > 0; i-- { + raviUpdate.Op = bf.ReadUint8() + raviUpdate.Dest = bf.ReadUint8() + raviUpdate.Data = bf.ReadUint32() + s.logger.Debug("RaviOps", zap.Uint8s("Op/Dest", []uint8{raviUpdate.Op, raviUpdate.Dest}), zap.Uint32s("Sema/Data", []uint32{pkt.SemaphoreID, raviUpdate.Data})) + raviUpdates = append(raviUpdates, raviUpdate) } + bf = byteframe.NewByteFrame() + + var _old, _new uint32 + s.server.raviente.Lock() + for _, update := range raviUpdates { + switch update.Op { + case 2: + _old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, true) + case 13, 14: + _old, _new = s.server.UpdateRavi(pkt.SemaphoreID, update.Dest, update.Data, false) + } + bf.WriteUint8(1) + bf.WriteUint8(update.Dest) + bf.WriteUint32(_old) + bf.WriteUint32(_new) + } + s.server.raviente.Unlock() + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) + if s.server.erupeConfig.GameplayOptions.LowLatencyRaviente { s.notifyRavi() } - s.server.raviente.Unlock() } func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysLoadRegister) - r := pkt.Unk1 - switch r { - case 12: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(12) - resp.WriteUint32(s.server.raviente.register.nextTime) - resp.WriteUint32(s.server.raviente.register.startTime) - resp.WriteUint32(s.server.raviente.register.killedTime) - resp.WriteUint32(s.server.raviente.register.postTime) - resp.WriteUint32(s.server.raviente.register.register[0]) - resp.WriteUint32(s.server.raviente.register.carveQuest) - resp.WriteUint32(s.server.raviente.register.register[1]) - resp.WriteUint32(s.server.raviente.register.register[2]) - resp.WriteUint32(s.server.raviente.register.register[3]) - resp.WriteUint32(s.server.raviente.register.maxPlayers) - resp.WriteUint32(s.server.raviente.register.ravienteType) - resp.WriteUint32(s.server.raviente.register.register[4]) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 29: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(29) - for _, v := range s.server.raviente.state.stateData { - resp.WriteUint32(v) + bf := byteframe.NewByteFrame() + bf.WriteUint8(0) + bf.WriteUint8(pkt.Values) + for i := uint8(0); i < pkt.Values; i++ { + switch pkt.RegisterID { + case 4: + bf.WriteUint32(s.server.raviente.state[i]) + case 5: + bf.WriteUint32(s.server.raviente.support[i]) + case 6: + bf.WriteUint32(s.server.raviente.register[i]) } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 25: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(25) - for _, v := range s.server.raviente.support.supportData { - resp.WriteUint32(v) - } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func (s *Session) notifyRavi() { @@ -282,18 +108,7 @@ func getRaviSemaphore(s *Server) *Semaphore { } func resetRavi(s *Session) { - s.server.raviente.Lock() - s.server.raviente.register.nextTime = 0 - s.server.raviente.register.startTime = 0 - s.server.raviente.register.killedTime = 0 - s.server.raviente.register.postTime = 0 - s.server.raviente.register.ravienteType = 0 - s.server.raviente.register.maxPlayers = 0 - s.server.raviente.register.carveQuest = 0 - s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0} - s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - s.server.raviente.Unlock() + s.server.raviente = NewRaviente() } func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index cad64bbe4..6273a7939 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -76,61 +76,25 @@ type Server struct { type Raviente struct { sync.Mutex - - register *RavienteRegister - state *RavienteState - support *RavienteSupport + register []uint32 + state []uint32 + support []uint32 } -type RavienteRegister struct { - nextTime uint32 - startTime uint32 - postTime uint32 - killedTime uint32 - ravienteType uint32 - maxPlayers uint32 - carveQuest uint32 - register []uint32 -} - -type RavienteState struct { - stateData []uint32 -} - -type RavienteSupport struct { - supportData []uint32 -} - -// Set up the Raviente variables for the server func NewRaviente() *Raviente { - ravienteRegister := &RavienteRegister{ - nextTime: 0, - startTime: 0, - killedTime: 0, - postTime: 0, - ravienteType: 0, - maxPlayers: 0, - carveQuest: 0, - } - ravienteState := &RavienteState{} - ravienteSupport := &RavienteSupport{} - ravienteRegister.register = []uint32{0, 0, 0, 0, 0} - ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - ravienteSupport.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - raviente := &Raviente{ - register: ravienteRegister, - state: ravienteState, - support: ravienteSupport, + register: make([]uint32, 30), + state: make([]uint32, 30), + support: make([]uint32, 30), } return raviente } -func (r *Raviente) GetRaviMultiplier(s *Server) float64 { +func (s *Server) GetRaviMultiplier() float64 { raviSema := getRaviSemaphore(s) if raviSema != nil { var minPlayers int - if r.register.maxPlayers > 8 { + if s.raviente.register[9] > 8 { minPlayers = 24 } else { minPlayers = 4 @@ -143,6 +107,40 @@ func (r *Raviente) GetRaviMultiplier(s *Server) float64 { return 0 } +func (s *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update bool) (uint32, uint32) { + var prev uint32 + switch semaID { + case 4: + switch index { + case 17, 28: // Ignore res and poison + break + default: + value = uint32(float64(value) * s.GetRaviMultiplier()) + } + prev = s.raviente.state[index] + if prev != 0 && !update { + return prev, prev + } + s.raviente.state[index] += value + return prev, s.raviente.state[index] + case 5: + prev = s.raviente.support[index] + if prev != 0 && !update { + return prev, prev + } + s.raviente.support[index] += value + return prev, s.raviente.support[index] + case 6: + prev = s.raviente.register[index] + if prev != 0 && !update { + return prev, prev + } + s.raviente.register[index] += value + return prev, s.raviente.register[index] + } + return 0, 0 +} + // NewServer creates a new Server type. func NewServer(config *Config) *Server { s := &Server{ From 1590d9c8d6a9ee288ce04e3c13bf679696c6d7d7 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 29 Aug 2023 23:26:10 +1000 Subject: [PATCH 08/96] fix wrong arg --- server/channelserver/handlers_cast_binary.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 97afcc0a8..a0b8b6ca9 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -89,7 +89,7 @@ func parseChatCommand(s *Session, command string) { if commands["PSN"].Enabled { if len(args) > 1 { var exists int - s.server.db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, id).Scan(&exists) + s.server.db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, args[1]).Scan(&exists) if exists == 0 { _, err := s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, args[1], s.charID) if err == nil { From e6f1298935e8554d03ea89ff526059625cffe5e0 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 30 Aug 2023 00:15:52 +1000 Subject: [PATCH 09/96] disable incompatible ravi commands --- server/channelserver/handlers_cast_binary.go | 37 ++++++++++++-------- server/channelserver/sys_language.go | 2 ++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 390a5fc74..6652c748f 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -258,23 +258,30 @@ func parseChatCommand(s *Session, command string) { } case "cm", "check", "checkmultiplier", "multiplier": sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandRaviMultiplier"], s.server.GetRaviMultiplier())) - case "sr", "sendres", "resurrection": - if s.server.raviente.state[28] > 0 { - sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"]) - s.server.raviente.state[28] = 0 + case "sr", "sendres", "resurrection", "ss", "sendsed", "rs", "reqsed": + if s.server.erupeConfig.RealClientMode == _config.ZZ { + switch args[1] { + case "sr", "sendres", "resurrection": + if s.server.raviente.state[28] > 0 { + sendServerChatMessage(s, s.server.dict["commandRaviResSuccess"]) + s.server.raviente.state[28] = 0 + } else { + sendServerChatMessage(s, s.server.dict["commandRaviResError"]) + } + case "ss", "sendsed": + sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"]) + // Total BerRavi HP + HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] + s.server.raviente.support[1] = HP + case "rs", "reqsed": + sendServerChatMessage(s, s.server.dict["commandRaviRequest"]) + // Total BerRavi HP + HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] + s.server.raviente.support[1] = HP + 1 + } } else { - sendServerChatMessage(s, s.server.dict["commandRaviResError"]) + sendServerChatMessage(s, s.server.dict["commandRaviVersion"]) } - case "ss", "sendsed": - sendServerChatMessage(s, s.server.dict["commandRaviSedSuccess"]) - // Total BerRavi HP - HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] - s.server.raviente.support[1] = HP - case "rs", "reqsed": - sendServerChatMessage(s, s.server.dict["commandRaviRequest"]) - // Total BerRavi HP - HP := s.server.raviente.state[0] + s.server.raviente.state[1] + s.server.raviente.state[2] + s.server.raviente.state[3] + s.server.raviente.state[4] - s.server.raviente.support[1] = HP + 1 default: sendServerChatMessage(s, s.server.dict["commandRaviError"]) } diff --git a/server/channelserver/sys_language.go b/server/channelserver/sys_language.go index 418e1cecb..dbd48cfb8 100644 --- a/server/channelserver/sys_language.go +++ b/server/channelserver/sys_language.go @@ -34,6 +34,7 @@ func getLangStrings(s *Server) map[string]string { strings["commandRaviRequest"] = "鎮静支援を要請します" strings["commandRaviError"] = "ラヴィコマンドが認識されません" strings["commandRaviNoPlayers"] = "誰も大討伐に参加していません" + strings["commandRaviVersion"] = "This command is disabled outside of MHFZZ" strings["ravienteBerserk"] = "<大討伐:猛狂期>が開催されました!" strings["ravienteExtreme"] = "<大討伐:猛狂期【極】>が開催されました!" @@ -85,6 +86,7 @@ func getLangStrings(s *Server) map[string]string { strings["commandRaviRequest"] = "Requesting sedation support!" strings["commandRaviError"] = "Raviente command not recognised!" strings["commandRaviNoPlayers"] = "No one has joined the Great Slaying!" + strings["commandRaviVersion"] = "This command is disabled outside of MHFZZ" strings["ravienteBerserk"] = " is being held!" strings["ravienteExtreme"] = " is being held!" From 81e8d21d4b0fabff41ee786e4a2238a57e8ee70f Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 30 Aug 2023 21:08:40 +1000 Subject: [PATCH 10/96] clean up --- network/mhfpacket/msg_sys_operate_register.go | 3 +-- server/channelserver/handlers_register.go | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/network/mhfpacket/msg_sys_operate_register.go b/network/mhfpacket/msg_sys_operate_register.go index c51a483e3..6978609b1 100644 --- a/network/mhfpacket/msg_sys_operate_register.go +++ b/network/mhfpacket/msg_sys_operate_register.go @@ -25,8 +25,7 @@ func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl m.SemaphoreID = bf.ReadUint32() _ = bf.ReadUint16() dataSize := bf.ReadUint16() - m.RawDataPayload = bf.ReadBytes(uint(dataSize) - 1) - _ = bf.ReadBytes(1) // Null terminator + m.RawDataPayload = bf.ReadBytes(uint(dataSize)) return nil } diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index be423d206..f060b664e 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -3,7 +3,6 @@ package channelserver import ( "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" - "go.uber.org/zap" "strings" ) @@ -18,12 +17,12 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { var raviUpdates []RaviUpdate var raviUpdate RaviUpdate - bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) + // Strip null terminator + bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[:len(pkt.RawDataPayload)-1]) for i := len(pkt.RawDataPayload) / 6; i > 0; i-- { raviUpdate.Op = bf.ReadUint8() raviUpdate.Dest = bf.ReadUint8() raviUpdate.Data = bf.ReadUint32() - s.logger.Debug("RaviOps", zap.Uint8s("Op/Dest", []uint8{raviUpdate.Op, raviUpdate.Dest}), zap.Uint32s("Sema/Data", []uint32{pkt.SemaphoreID, raviUpdate.Data})) raviUpdates = append(raviUpdates, raviUpdate) } bf = byteframe.NewByteFrame() From 813a3df6a7043c4697feec1cc643fa57eee7d8ed Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 30 Aug 2023 22:18:37 +1000 Subject: [PATCH 11/96] correctly parse RegisterEvent & move handlers --- network/mhfpacket/msg_mhf_register_event.go | 12 +++--- server/channelserver/handlers_event.go | 38 ------------------- server/channelserver/handlers_register.go | 42 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/network/mhfpacket/msg_mhf_register_event.go b/network/mhfpacket/msg_mhf_register_event.go index aaa5b51a8..956c4a399 100644 --- a/network/mhfpacket/msg_mhf_register_event.go +++ b/network/mhfpacket/msg_mhf_register_event.go @@ -1,20 +1,19 @@ package mhfpacket import ( + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfRegisterEvent represents the MSG_MHF_REGISTER_EVENT type MsgMhfRegisterEvent struct { AckHandle uint32 Unk0 uint16 - Unk1 uint8 - Unk2 uint8 + WorldID uint16 + LandID uint16 Unk3 uint8 Unk4 uint8 - Unk5 uint16 } // Opcode returns the ID associated with this packet type. @@ -26,11 +25,10 @@ func (m *MsgMhfRegisterEvent) Opcode() network.PacketID { func (m *MsgMhfRegisterEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint8() + m.WorldID = bf.ReadUint16() + m.LandID = bf.ReadUint16() m.Unk3 = bf.ReadUint8() m.Unk4 = bf.ReadUint8() - m.Unk5 = bf.ReadUint16() return nil } diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index 74d0cef13..d01f92a3d 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -10,44 +10,6 @@ import ( "erupe-ce/network/mhfpacket" ) -func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfRegisterEvent) - bf := byteframe.NewByteFrame() - bf.WriteUint8(pkt.Unk2) - bf.WriteUint8(pkt.Unk4) - bf.WriteUint16(0x1142) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) -} - -func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfReleaseEvent) - - // Do this ack manually because it uses a non-(0|1) error code - /* - _ACK_SUCCESS = 0 - _ACK_ERROR = 1 - - _ACK_EINPROGRESS = 16 - _ACK_ENOENT = 17 - _ACK_ENOSPC = 18 - _ACK_ETIMEOUT = 19 - - _ACK_EINVALID = 64 - _ACK_EFAILED = 65 - _ACK_ENOMEM = 66 - _ACK_ENOTEXIT = 67 - _ACK_ENOTREADY = 68 - _ACK_EALREADY = 69 - _ACK_DISABLE_WORK = 71 - */ - s.QueueSendMHF(&mhfpacket.MsgSysAck{ - AckHandle: pkt.AckHandle, - IsBufferResponse: false, - ErrorCode: 0x41, - AckData: []byte{0x00, 0x00, 0x00, 0x00}, - }) -} - type Event struct { EventType uint16 Unk1 uint16 diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index f060b664e..911249554 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -6,6 +6,48 @@ import ( "strings" ) +func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfRegisterEvent) + bf := byteframe.NewByteFrame() + if pkt.Unk3 > 0 { + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + return + } + bf.WriteUint8(uint8(pkt.WorldID)) + bf.WriteUint8(uint8(pkt.LandID)) + bf.WriteUint16(0x1142) // Probably random ID + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) +} + +func handleMsgMhfReleaseEvent(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfReleaseEvent) + + // Do this ack manually because it uses a non-(0|1) error code + /* + _ACK_SUCCESS = 0 + _ACK_ERROR = 1 + + _ACK_EINPROGRESS = 16 + _ACK_ENOENT = 17 + _ACK_ENOSPC = 18 + _ACK_ETIMEOUT = 19 + + _ACK_EINVALID = 64 + _ACK_EFAILED = 65 + _ACK_ENOMEM = 66 + _ACK_ENOTEXIT = 67 + _ACK_ENOTREADY = 68 + _ACK_EALREADY = 69 + _ACK_DISABLE_WORK = 71 + */ + s.QueueSendMHF(&mhfpacket.MsgSysAck{ + AckHandle: pkt.AckHandle, + IsBufferResponse: false, + ErrorCode: 0x41, + AckData: []byte{0x00, 0x00, 0x00, 0x00}, + }) +} + type RaviUpdate struct { Op uint8 Dest uint8 From 42abdfb0c7ea7b01b4f52560a9da314a299767d4 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 30 Aug 2023 22:29:49 +1000 Subject: [PATCH 12/96] change getRaviSemaphore scope & handle RegisterEvent --- network/mhfpacket/msg_mhf_release_event.go | 4 ++-- server/channelserver/handlers_cast_binary.go | 4 ++-- server/channelserver/handlers_register.go | 7 ++++--- server/channelserver/sys_channel_server.go | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/network/mhfpacket/msg_mhf_release_event.go b/network/mhfpacket/msg_mhf_release_event.go index 08e507c81..52178279b 100644 --- a/network/mhfpacket/msg_mhf_release_event.go +++ b/network/mhfpacket/msg_mhf_release_event.go @@ -11,7 +11,7 @@ import ( // MsgMhfReleaseEvent represents the MSG_MHF_RELEASE_EVENT type MsgMhfReleaseEvent struct { AckHandle uint32 - Unk0 uint32 + RaviID uint32 Unk1 uint32 } @@ -23,7 +23,7 @@ func (m *MsgMhfReleaseEvent) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfReleaseEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() + m.RaviID = bf.ReadUint32() m.Unk1 = bf.ReadUint32() return nil } diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 6652c748f..ded566268 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -246,7 +246,7 @@ func parseChatCommand(s *Session, command string) { case commands["Raviente"].Prefix: if commands["Raviente"].Enabled { if len(args) > 1 { - if getRaviSemaphore(s.server) != nil { + if s.server.getRaviSemaphore() != nil { switch args[1] { case "start": if s.server.raviente.register[1] == 0 { @@ -420,7 +420,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } case BroadcastTypeServer: if pkt.MessageType == 1 { - if getRaviSemaphore(s.server) != nil { + if s.server.getRaviSemaphore() != nil { s.server.BroadcastMHF(resp, s) } } else { diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index 911249554..57bce3e61 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -9,7 +9,8 @@ import ( func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfRegisterEvent) bf := byteframe.NewByteFrame() - if pkt.Unk3 > 0 { + // Some kind of check if there's already a session + if pkt.Unk3 > 0 && s.server.getRaviSemaphore() == nil { doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) return } @@ -110,7 +111,7 @@ func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) { } func (s *Session) notifyRavi() { - sema := getRaviSemaphore(s.server) + sema := s.server.getRaviSemaphore() if sema == nil { return } @@ -139,7 +140,7 @@ func (s *Session) notifyRavi() { } } -func getRaviSemaphore(s *Server) *Semaphore { +func (s *Server) getRaviSemaphore() *Semaphore { for _, semaphore := range s.semaphore { if strings.HasPrefix(semaphore.id_semaphore, "hs_l0u3B5") && strings.HasSuffix(semaphore.id_semaphore, "3") { return semaphore diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 6273a7939..0de5650c0 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -91,7 +91,7 @@ func NewRaviente() *Raviente { } func (s *Server) GetRaviMultiplier() float64 { - raviSema := getRaviSemaphore(s) + raviSema := s.getRaviSemaphore() if raviSema != nil { var minPlayers int if s.raviente.register[9] > 8 { From 5b5621a3d8455c6dd8753b97ea62fcc759685cbf Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 30 Aug 2023 23:43:56 +1000 Subject: [PATCH 13/96] fix and rework various Raviente ID systems --- server/channelserver/handlers_register.go | 8 ++------ server/channelserver/handlers_semaphore.go | 8 ++++---- server/channelserver/sys_channel_server.go | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index 57bce3e61..2135af6fb 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -16,7 +16,7 @@ func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { } bf.WriteUint8(uint8(pkt.WorldID)) bf.WriteUint8(uint8(pkt.LandID)) - bf.WriteUint16(0x1142) // Probably random ID + bf.WriteUint16(s.server.raviente.id) doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } @@ -142,15 +142,11 @@ func (s *Session) notifyRavi() { func (s *Server) getRaviSemaphore() *Semaphore { for _, semaphore := range s.semaphore { - if strings.HasPrefix(semaphore.id_semaphore, "hs_l0u3B5") && strings.HasSuffix(semaphore.id_semaphore, "3") { + if strings.HasPrefix(semaphore.id_semaphore, "hs_l0") && strings.HasSuffix(semaphore.id_semaphore, "3") { return semaphore } } return nil } -func resetRavi(s *Session) { - s.server.raviente = NewRaviente() -} - func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_semaphore.go b/server/channelserver/handlers_semaphore.go index 503df5110..21b12682e 100644 --- a/server/channelserver/handlers_semaphore.go +++ b/server/channelserver/handlers_semaphore.go @@ -35,7 +35,7 @@ func destructEmptySemaphores(s *Session) { s.server.semaphoreLock.Unlock() delete(s.server.semaphore, id) s.server.semaphoreLock.Lock() - if strings.HasPrefix(id, "hs_l0u3B5") { + if strings.HasPrefix(id, "hs_l0") { releaseRaviSemaphore(s, sema) } s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) @@ -49,7 +49,7 @@ func releaseRaviSemaphore(s *Session, sema *Semaphore) { delete(sema.clients, s) if strings.HasSuffix(sema.id_semaphore, "2") && len(sema.clients) == 0 { s.logger.Debug("Main raviente semaphore is empty, resetting") - resetRavi(s) + s.server.resetRaviente() } } @@ -60,7 +60,7 @@ func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) { s.server.semaphoreLock.Lock() for id, sema := range s.server.semaphore { if sema.id == pkt.SemaphoreID { - if strings.HasPrefix(id, "hs_l0u3B5") { + if strings.HasPrefix(id, "hs_l0") { releaseRaviSemaphore(s, sema) s.server.semaphoreLock.Unlock() return @@ -84,7 +84,7 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { fmt.Printf("Got reserve stage req, StageID: %v\n\n", SemaphoreID) if !exists { s.server.semaphoreLock.Lock() - if strings.HasPrefix(SemaphoreID, "hs_l0u3B5") { + if strings.HasPrefix(SemaphoreID, "hs_l0") { suffix, _ := strconv.Atoi(pkt.SemaphoreID[len(pkt.SemaphoreID)-1:]) s.server.semaphore[SemaphoreID] = &Semaphore{ id_semaphore: pkt.SemaphoreID, diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 0de5650c0..8c0e9fe23 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -76,18 +76,17 @@ type Server struct { type Raviente struct { sync.Mutex + id uint16 register []uint32 state []uint32 support []uint32 } -func NewRaviente() *Raviente { - raviente := &Raviente{ - register: make([]uint32, 30), - state: make([]uint32, 30), - support: make([]uint32, 30), - } - return raviente +func (s *Server) resetRaviente() { + s.raviente.id = s.raviente.id + 1 + s.raviente.register = make([]uint32, 30) + s.raviente.state = make([]uint32, 30) + s.raviente.support = make([]uint32, 30) } func (s *Server) GetRaviMultiplier() float64 { @@ -158,7 +157,11 @@ func NewServer(config *Config) *Server { semaphoreIndex: 7, discordBot: config.DiscordBot, name: config.Name, - raviente: NewRaviente(), + raviente: &Raviente{ + register: make([]uint32, 30), + state: make([]uint32, 30), + support: make([]uint32, 30), + }, } // Mezeporta From 9f76d34e46effe3021c2ac37797463c00f659dac Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 30 Aug 2023 23:58:50 +1000 Subject: [PATCH 14/96] fix Raviente ID --- server/channelserver/sys_channel_server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 8c0e9fe23..dd25db23f 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -158,6 +158,7 @@ func NewServer(config *Config) *Server { discordBot: config.DiscordBot, name: config.Name, raviente: &Raviente{ + id: 1, register: make([]uint32, 30), state: make([]uint32, 30), support: make([]uint32, 30), From 56a32b879c85e132ea4f05a0812adcbc04116a3f Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 31 Aug 2023 00:07:27 +1000 Subject: [PATCH 15/96] fix invalid length tuneValues --- server/channelserver/handlers_quest.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index a549086a8..d9ec2bc08 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -633,24 +633,28 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { offset := uint16(time.Now().Unix()) bf.WriteUint16(offset) + tuneLimit := 770 if _config.ErupeConfig.RealClientMode <= _config.F5 { - tuneValues = tuneValues[:256] + tuneLimit = 256 } else if _config.ErupeConfig.RealClientMode <= _config.G3 { - tuneValues = tuneValues[:283] + tuneLimit = 283 } else if _config.ErupeConfig.RealClientMode <= _config.GG { - tuneValues = tuneValues[:315] + tuneLimit = 315 } else if _config.ErupeConfig.RealClientMode <= _config.G61 { - tuneValues = tuneValues[:332] + tuneLimit = 332 } else if _config.ErupeConfig.RealClientMode <= _config.G7 { - tuneValues = tuneValues[:339] + tuneLimit = 339 } else if _config.ErupeConfig.RealClientMode <= _config.G81 { - tuneValues = tuneValues[:396] + tuneLimit = 396 } else if _config.ErupeConfig.RealClientMode <= _config.G91 { - tuneValues = tuneValues[:694] + tuneLimit = 694 } else if _config.ErupeConfig.RealClientMode <= _config.G101 { - tuneValues = tuneValues[:704] + tuneLimit = 704 } else if _config.ErupeConfig.RealClientMode <= _config.Z2 { - tuneValues = tuneValues[:750] + tuneLimit = 750 + } + if len(tuneValues) > tuneLimit { + tuneValues = tuneValues[:tuneLimit] } bf.WriteUint16(uint16(len(tuneValues))) From e4efb55a038612ac8590b9d2e499791e8d20cae8 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 31 Aug 2023 00:08:03 +1000 Subject: [PATCH 16/96] fix LoadDecoMyset response for G8 and G9 --- server/channelserver/handlers_house.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 52cdb4fa9..4cc53d303 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -250,7 +250,7 @@ func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) { s.logger.Error("Failed to load decomyset", zap.Error(err)) } if len(data) == 0 { - if s.server.erupeConfig.RealClientMode <= _config.G7 { + if s.server.erupeConfig.RealClientMode < _config.G10 { data = []byte{0x00, 0x00} } data = []byte{0x01, 0x00} From 0bdd873336ba84f8adebef4a612bf1bacd349256 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 2 Sep 2023 23:52:15 +1000 Subject: [PATCH 17/96] broadcast Raviente party message correctly --- server/channelserver/handlers_cast_binary.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index ded566268..30a377b82 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -420,8 +420,9 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { } case BroadcastTypeServer: if pkt.MessageType == 1 { - if s.server.getRaviSemaphore() != nil { - s.server.BroadcastMHF(resp, s) + raviSema := s.server.getRaviSemaphore() + if raviSema != nil { + raviSema.BroadcastMHF(resp, s) } } else { s.server.BroadcastMHF(resp, s) From 4a35be488cae3a0c2af6c8d2b396c0bc8742c257 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 3 Sep 2023 00:00:08 +1000 Subject: [PATCH 18/96] rework Semaphores --- server/channelserver/handlers_register.go | 14 ++--- server/channelserver/handlers_semaphore.go | 73 ++++++++-------------- server/channelserver/sys_channel_server.go | 20 ++++-- server/channelserver/sys_semaphore.go | 40 +++--------- 4 files changed, 57 insertions(+), 90 deletions(-) diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index 2135af6fb..6a74358aa 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -99,11 +99,11 @@ func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint8(pkt.Values) for i := uint8(0); i < pkt.Values; i++ { switch pkt.RegisterID { - case 4: + case 0x40000: bf.WriteUint32(s.server.raviente.state[i]) - case 5: + case 0x50000: bf.WriteUint32(s.server.raviente.support[i]) - case 6: + case 0x60000: bf.WriteUint32(s.server.raviente.register[i]) } } @@ -117,13 +117,13 @@ func (s *Session) notifyRavi() { } var temp mhfpacket.MHFPacket raviNotif := byteframe.NewByteFrame() - temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 4} + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x40000} raviNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(raviNotif, s.clientContext) - temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 5} + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x50000} raviNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(raviNotif, s.clientContext) - temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 6} + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: 0x60000} raviNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(raviNotif, s.clientContext) raviNotif.WriteUint16(0x0010) // End it. @@ -142,7 +142,7 @@ func (s *Session) notifyRavi() { func (s *Server) getRaviSemaphore() *Semaphore { for _, semaphore := range s.semaphore { - if strings.HasPrefix(semaphore.id_semaphore, "hs_l0") && strings.HasSuffix(semaphore.id_semaphore, "3") { + if strings.HasPrefix(semaphore.name, "hs_l0") && strings.HasSuffix(semaphore.name, "3") { return semaphore } } diff --git a/server/channelserver/handlers_semaphore.go b/server/channelserver/handlers_semaphore.go index 21b12682e..19925c6d6 100644 --- a/server/channelserver/handlers_semaphore.go +++ b/server/channelserver/handlers_semaphore.go @@ -2,7 +2,6 @@ package channelserver import ( "erupe-ce/common/byteframe" - "fmt" "go.uber.org/zap" "strconv" "strings" @@ -13,9 +12,6 @@ import ( func removeSessionFromSemaphore(s *Session) { s.server.semaphoreLock.Lock() for _, semaphore := range s.server.semaphore { - if _, exists := semaphore.reservedClientSlots[s.charID]; exists { - delete(semaphore.reservedClientSlots, s.charID) - } if _, exists := semaphore.clients[s]; exists { delete(semaphore.clients, s) } @@ -31,48 +27,38 @@ func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) { func destructEmptySemaphores(s *Session) { s.server.semaphoreLock.Lock() for id, sema := range s.server.semaphore { - if len(sema.reservedClientSlots) == 0 && len(sema.clients) == 0 { - s.server.semaphoreLock.Unlock() + if len(sema.clients) == 0 { delete(s.server.semaphore, id) - s.server.semaphoreLock.Lock() if strings.HasPrefix(id, "hs_l0") { - releaseRaviSemaphore(s, sema) + s.server.resetRaviente() } - s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) + s.logger.Debug("Destructed semaphore", zap.String("sema.name", id)) } } s.server.semaphoreLock.Unlock() } -func releaseRaviSemaphore(s *Session, sema *Semaphore) { - delete(sema.reservedClientSlots, s.charID) - delete(sema.clients, s) - if strings.HasSuffix(sema.id_semaphore, "2") && len(sema.clients) == 0 { - s.logger.Debug("Main raviente semaphore is empty, resetting") - s.server.resetRaviente() - } -} - func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysDeleteSemaphore) - if s.server.semaphore != nil { - destructEmptySemaphores(s) - s.server.semaphoreLock.Lock() - for id, sema := range s.server.semaphore { - if sema.id == pkt.SemaphoreID { - if strings.HasPrefix(id, "hs_l0") { - releaseRaviSemaphore(s, sema) - s.server.semaphoreLock.Unlock() - return + destructEmptySemaphores(s) + s.server.semaphoreLock.Lock() + for id, sema := range s.server.semaphore { + if sema.id == pkt.SemaphoreID { + for session := range sema.clients { + if s == session { + delete(sema.clients, s) } - s.server.semaphoreLock.Unlock() + } + if len(sema.clients) == 0 { delete(s.server.semaphore, id) - s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) - return + if strings.HasPrefix(id, "hs_l0") { + s.server.resetRaviente() + } + s.logger.Debug("Destructed semaphore", zap.String("sema.name", id)) } } - s.server.semaphoreLock.Unlock() } + s.server.semaphoreLock.Unlock() } func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { @@ -80,18 +66,15 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { SemaphoreID := pkt.SemaphoreID newSemaphore, exists := s.server.semaphore[SemaphoreID] - - fmt.Printf("Got reserve stage req, StageID: %v\n\n", SemaphoreID) if !exists { s.server.semaphoreLock.Lock() if strings.HasPrefix(SemaphoreID, "hs_l0") { suffix, _ := strconv.Atoi(pkt.SemaphoreID[len(pkt.SemaphoreID)-1:]) s.server.semaphore[SemaphoreID] = &Semaphore{ - id_semaphore: pkt.SemaphoreID, - id: uint32(suffix + 1), - clients: make(map[*Session]uint32), - reservedClientSlots: make(map[uint32]interface{}), - maxPlayers: 127, + name: pkt.SemaphoreID, + id: uint32((suffix + 1) * 0x10000), + clients: make(map[*Session]uint32), + maxPlayers: 127, } } else { s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 1) @@ -102,22 +85,19 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { newSemaphore.Lock() defer newSemaphore.Unlock() - if _, exists := newSemaphore.reservedClientSlots[s.charID]; exists { - bf := byteframe.NewByteFrame() + bf := byteframe.NewByteFrame() + if _, exists := newSemaphore.clients[s]; exists { bf.WriteUint32(newSemaphore.id) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) - } else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers { - newSemaphore.reservedClientSlots[s.charID] = nil + } else if uint16(len(newSemaphore.clients)) < newSemaphore.maxPlayers { newSemaphore.clients[s] = s.charID s.Lock() s.semaphore = newSemaphore s.Unlock() - bf := byteframe.NewByteFrame() bf.WriteUint32(newSemaphore.id) - doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } else { - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + bf.WriteUint32(0) } + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { @@ -130,7 +110,6 @@ func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { } else { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) } - } func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index dd25db23f..5a4b29fe9 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -3,6 +3,7 @@ package channelserver import ( "fmt" "net" + "strings" "sync" "erupe-ce/common/byteframe" @@ -83,6 +84,12 @@ type Raviente struct { } func (s *Server) resetRaviente() { + for _, semaphore := range s.semaphore { + if strings.HasPrefix(semaphore.name, "hs_l0") { + return + } + } + s.logger.Debug("All Raviente Semaphores empty, resetting") s.raviente.id = s.raviente.id + 1 s.raviente.register = make([]uint32, 30) s.raviente.state = make([]uint32, 30) @@ -109,7 +116,7 @@ func (s *Server) GetRaviMultiplier() float64 { func (s *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update bool) (uint32, uint32) { var prev uint32 switch semaID { - case 4: + case 0x40000: switch index { case 17, 28: // Ignore res and poison break @@ -122,14 +129,14 @@ func (s *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update boo } s.raviente.state[index] += value return prev, s.raviente.state[index] - case 5: + case 0x50000: prev = s.raviente.support[index] if prev != 0 && !update { return prev, prev } s.raviente.support[index] += value return prev, s.raviente.support[index] - case 6: + case 0x60000: prev = s.raviente.register[index] if prev != 0 && !update { return prev, prev @@ -395,15 +402,16 @@ func (s *Server) NextSemaphoreID() uint32 { for { exists := false s.semaphoreIndex = s.semaphoreIndex + 1 - if s.semaphoreIndex == 0 { - s.semaphoreIndex = 7 // Skip reserved indexes + if s.semaphoreIndex > 0xFFFF { + s.semaphoreIndex = 1 } for _, semaphore := range s.semaphore { if semaphore.id == s.semaphoreIndex { exists = true + break } } - if exists == false { + if !exists { break } } diff --git a/server/channelserver/sys_semaphore.go b/server/channelserver/sys_semaphore.go index 369e481b6..78ff963b5 100644 --- a/server/channelserver/sys_semaphore.go +++ b/server/channelserver/sys_semaphore.go @@ -7,55 +7,35 @@ import ( "sync" ) -// Stage holds stage-specific information +// Semaphore holds Semaphore-specific information type Semaphore struct { sync.RWMutex - // Stage ID string - id_semaphore string + // Semaphore ID string + name string id uint32 // Map of session -> charID. - // These are clients that are CURRENTLY in the stage + // These are clients that are registered to the Semaphore clients map[*Session]uint32 - // Map of charID -> interface{}, only the key is used, value is always nil. - reservedClientSlots map[uint32]interface{} - // Max Players for Semaphore maxPlayers uint16 } -// NewStage creates a new stage with intialized values. +// NewSemaphore creates a new Semaphore with intialized values func NewSemaphore(s *Server, ID string, MaxPlayers uint16) *Semaphore { sema := &Semaphore{ - id_semaphore: ID, - id: s.NextSemaphoreID(), - clients: make(map[*Session]uint32), - reservedClientSlots: make(map[uint32]interface{}), - maxPlayers: MaxPlayers, + name: ID, + id: s.NextSemaphoreID(), + clients: make(map[*Session]uint32), + maxPlayers: MaxPlayers, } return sema } -func (s *Semaphore) BroadcastRavi(pkt mhfpacket.MHFPacket) { - // Broadcast the data. - for session := range s.clients { - - // Make the header - bf := byteframe.NewByteFrame() - bf.WriteUint16(uint16(pkt.Opcode())) - - // Build the packet onto the byteframe. - pkt.Build(bf, session.clientContext) - - // Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full. - session.QueueSendNonBlocking(bf.Data()) - } -} - -// BroadcastMHF queues a MHFPacket to be sent to all sessions in the stage. +// BroadcastMHF queues a MHFPacket to be sent to all sessions in the Semaphore func (s *Semaphore) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { // Broadcast the data. for session := range s.clients { From 059f1942a9d8fbf06941fb8e91e23d5b72af958c Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 17 Sep 2023 23:45:32 +1000 Subject: [PATCH 19/96] rename instances of gook to goocoo --- network/mhfpacket/msg_mhf_enumerate_guacot.go | 7 +--- network/mhfpacket/msg_mhf_update_guacot.go | 38 ++++++++----------- patch-schema/06-goocoo-rename.sql | 11 ++++++ server/channelserver/handlers.go | 26 +++++++------ 4 files changed, 44 insertions(+), 38 deletions(-) create mode 100644 patch-schema/06-goocoo-rename.sql diff --git a/network/mhfpacket/msg_mhf_enumerate_guacot.go b/network/mhfpacket/msg_mhf_enumerate_guacot.go index 4fcdba523..2f970f938 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guacot.go +++ b/network/mhfpacket/msg_mhf_enumerate_guacot.go @@ -2,7 +2,6 @@ package mhfpacket import ( "errors" - "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" @@ -11,9 +10,8 @@ import ( // MsgMhfEnumerateGuacot represents the MSG_MHF_ENUMERATE_GUACOT type MsgMhfEnumerateGuacot struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 0 in binary + Unk0 uint32 // Hardcoded 0 in binary Unk1 uint16 // Hardcoded 0 in binary - Unk2 uint16 // Hardcoded 0 in binary } // Opcode returns the ID associated with this packet type. @@ -24,9 +22,8 @@ func (m *MsgMhfEnumerateGuacot) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() + m.Unk0 = bf.ReadUint32() m.Unk1 = bf.ReadUint16() - m.Unk2 = bf.ReadUint16() return nil } diff --git a/network/mhfpacket/msg_mhf_update_guacot.go b/network/mhfpacket/msg_mhf_update_guacot.go index 99aa215e2..433854ae3 100644 --- a/network/mhfpacket/msg_mhf_update_guacot.go +++ b/network/mhfpacket/msg_mhf_update_guacot.go @@ -2,27 +2,23 @@ package mhfpacket import ( "errors" - "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" ) -type Gook struct { - Exists bool - Index uint32 - Type uint16 - Data []byte - NameLen uint8 - Name []byte +type Goocoo struct { + Index uint32 + Data1 []uint16 + Data2 []uint32 + Name []byte } // MsgMhfUpdateGuacot represents the MSG_MHF_UPDATE_GUACOT type MsgMhfUpdateGuacot struct { AckHandle uint32 EntryCount uint16 - Unk0 uint16 // Hardcoded 0 in binary - Gooks []Gook + Goocoos []Goocoo } // Opcode returns the ID associated with this packet type. @@ -34,20 +30,18 @@ func (m *MsgMhfUpdateGuacot) Opcode() network.PacketID { func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.EntryCount = bf.ReadUint16() - m.Unk0 = bf.ReadUint16() + _ = bf.ReadUint16() // Zero + var temp Goocoo for i := 0; i < int(m.EntryCount); i++ { - e := Gook{} - e.Index = bf.ReadUint32() - e.Type = bf.ReadUint16() - e.Data = bf.ReadBytes(50) - e.NameLen = bf.ReadUint8() - e.Name = bf.ReadBytes(uint(e.NameLen)) - if e.Type > 0 { - e.Exists = true - } else { - e.Exists = false + temp.Index = bf.ReadUint32() + for j := 0; j < 22; j++ { + temp.Data1 = append(temp.Data1, bf.ReadUint16()) } - m.Gooks = append(m.Gooks, e) + for j := 0; j < 2; j++ { + temp.Data2 = append(temp.Data2, bf.ReadUint32()) + } + temp.Name = bf.ReadBytes(uint(bf.ReadUint8())) + m.Goocoos = append(m.Goocoos, temp) } return nil } diff --git a/patch-schema/06-goocoo-rename.sql b/patch-schema/06-goocoo-rename.sql new file mode 100644 index 000000000..e72585ab3 --- /dev/null +++ b/patch-schema/06-goocoo-rename.sql @@ -0,0 +1,11 @@ +BEGIN; + +ALTER TABLE gook RENAME TO goocoo; + +ALTER TABLE goocoo RENAME COLUMN gook0 TO goocoo0; +ALTER TABLE goocoo RENAME COLUMN gook1 TO goocoo1; +ALTER TABLE goocoo RENAME COLUMN gook2 TO goocoo2; +ALTER TABLE goocoo RENAME COLUMN gook3 TO goocoo3; +ALTER TABLE goocoo RENAME COLUMN gook4 TO goocoo4; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index abc554d06..517da6e6d 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -822,21 +822,25 @@ func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateGuacot) - for _, gook := range pkt.Gooks { - if !gook.Exists { - s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=NULL WHERE id=$1", gook.Index), s.charID) + for _, goocoo := range pkt.Goocoos { + if goocoo.Data1[0] == 0 { + s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.charID) } else { bf := byteframe.NewByteFrame() - bf.WriteUint32(gook.Index) - bf.WriteUint16(gook.Type) - bf.WriteBytes(gook.Data) - bf.WriteUint8(gook.NameLen) - bf.WriteBytes(gook.Name) - s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=$1 WHERE id=$2", gook.Index), bf.Data(), s.charID) - dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", gook.Index)) + bf.WriteUint32(goocoo.Index) + for i := range goocoo.Data1 { + bf.WriteUint16(goocoo.Data1[i]) + } + for i := range goocoo.Data2 { + bf.WriteUint32(goocoo.Data2[i]) + } + bf.WriteUint8(uint8(len(goocoo.Name))) + bf.WriteBytes(goocoo.Name) + s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=$1 WHERE id=$2", goocoo.Index), bf.Data(), s.charID) + dumpSaveData(s, bf.Data(), fmt.Sprintf("goocoo-%d", goocoo.Index)) } } - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) { From 20272382500d79eb0f4889c9b472d047463ac589 Mon Sep 17 00:00:00 2001 From: Samboge Date: Wed, 27 Sep 2023 07:12:27 +0700 Subject: [PATCH 20/96] Fix for Festa Rewards and House Visit MHF-F5 Partial Fix for Forward 5 --- server/channelserver/handlers_character.go | 22 ++++++++++ server/channelserver/handlers_festa.go | 47 +++++++++++++++++----- server/channelserver/handlers_house.go | 5 ++- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index bdbd2f744..e6276e845 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -83,6 +83,17 @@ func getPointers() map[SavePointer]int { pointers[pGardenData] = 106424 pointers[pRP] = 106614 pointers[pKQF] = 110720 + case _config.F5: + pointers[pWeaponID] = 60522 + pointers[pWeaponType] = 60789 + pointers[pHouseTier] = 61900 + pointers[pToreData] = 60550 + pointers[pHRP] = 62550 + pointers[pHouseData] = 62651 + pointers[pBookshelfData] = 71928 + pointers[pGalleryData] = 72064 + pointers[pGardenData] = 74424 + pointers[pRP] = 74614 } return pointers } @@ -206,6 +217,17 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) } save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] + } else if _config.ErupeConfig.RealClientMode < _config.G10 { + save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) + save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] + save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] + save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+2576] + save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748] + save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240] + save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68] + save.WeaponType = save.decompSave[save.Pointers[pWeaponType]] + save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2]) + save.HRP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHRP] : save.Pointers[pHRP]+2]) } } return diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 95cc14e0d..4f3807fa2 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -162,6 +162,14 @@ type FestaReward struct { Unk7 uint8 } +type FestaRewardF5 struct { + Unk0 uint8 + Unk1 uint8 + ItemType uint16 + Quantity uint16 + ItemID uint16 +} + func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfInfoFesta) bf := byteframe.NewByteFrame() @@ -254,18 +262,37 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { {5, 0, 13, 0, 0, 0, 0, 0}, //{5, 0, 1, 0, 0, 0, 0, 0}, } - bf.WriteUint16(uint16(len(rewards))) - for _, reward := range rewards { - bf.WriteUint8(reward.Unk0) - bf.WriteUint8(reward.Unk1) - bf.WriteUint16(reward.ItemType) - bf.WriteUint16(reward.Quantity) - bf.WriteUint16(reward.ItemID) - bf.WriteUint16(reward.Unk5) - bf.WriteUint16(reward.Unk6) - bf.WriteUint8(reward.Unk7) + + rewardsF5 := []FestaRewardF5{ + {1, 0, 7, 250, 1520}, + {1, 0, 12, 250, 0}, + {1, 0, 12, 250, 0}, + {1, 0, 12, 250, 0}, + {1, 0, 12, 250, 0}, } + if _config.ErupeConfig.RealClientMode >= _config.G1 { + bf.WriteUint16(uint16(len(rewards))) + for _, reward := range rewards { + bf.WriteUint8(reward.Unk0) + bf.WriteUint8(reward.Unk1) + bf.WriteUint16(reward.ItemType) + bf.WriteUint16(reward.Quantity) + bf.WriteUint16(reward.ItemID) + bf.WriteUint16(reward.Unk5) + bf.WriteUint16(reward.Unk6) + bf.WriteUint8(reward.Unk7) + } + } else if _config.ErupeConfig.RealClientMode == _config.F5{ + bf.WriteUint16(uint16(len(rewardsF5))) + for _, reward := range rewardsF5 { + bf.WriteUint8(reward.Unk0) + bf.WriteUint8(reward.Unk1) + bf.WriteUint16(reward.ItemType) + bf.WriteUint16(reward.Quantity) + bf.WriteUint16(reward.ItemID) + } + } if _config.ErupeConfig.RealClientMode <= _config.G61 { if s.server.erupeConfig.GameplayOptions.MaximumFP > 0xFFFF { s.server.erupeConfig.GameplayOptions.MaximumFP = 0xFFFF diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 4cc53d303..c00c2be73 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -119,7 +119,10 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint8(0) } bf.WriteUint16(house.HRP) - bf.WriteUint16(house.GR) + //to skip GR for client below G1 + if _config.ErupeConfig.RealClientMode >= _config.G1{ + bf.WriteUint16(house.GR) + } ps.Uint8(bf, house.Name, true) } bf.Seek(0, 0) From 8f1317f49835d3138ad6f9b2a2b9c3064a464d22 Mon Sep 17 00:00:00 2001 From: Samboge Date: Wed, 27 Sep 2023 13:52:29 +0700 Subject: [PATCH 21/96] Fix RP for MHF-F5 forgot to modify updateSaveDataWithStruct() to include forward 5 --- server/channelserver/handlers_character.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index e6276e845..301a17b63 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -190,6 +190,8 @@ func (save *CharacterSaveData) updateSaveDataWithStruct() { if _config.ErupeConfig.RealClientMode >= _config.G10 { copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF) + } else if _config.ErupeConfig.RealClientMode == _config.F5{ + copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) } } From b58eddca854f4130a505ba4300f79620debc5744 Mon Sep 17 00:00:00 2001 From: legayacruise <112596053+legayacruise@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:02:29 -0400 Subject: [PATCH 22/96] Correct instances of "gook" to goocoo Thank you to Samboge for pointing that out. --- server/channelserver/handlers.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 517da6e6d..9450fee43 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -789,20 +789,20 @@ func getGookData(s *Session, cid uint32) (uint16, []byte) { var count uint16 bf := byteframe.NewByteFrame() for i := 0; i < 5; i++ { - err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), cid).Scan(&data) + err := s.server.db.QueryRow(fmt.Sprintf("SELECT goocoo%d FROM goocoo WHERE id=$1", i), cid).Scan(&data) if err != nil { - s.server.db.Exec("INSERT INTO gook (id) VALUES ($1)", s.charID) + s.server.db.Exec("INSERT INTO goocoo (id) VALUES ($1)", s.charID) return 0, bf.Data() } if err == nil && data != nil { count++ if s.charID == cid && count == 1 { - gook := byteframe.NewByteFrameFromBytes(data) - bf.WriteBytes(gook.ReadBytes(4)) - d := gook.ReadBytes(2) + goocoo := byteframe.NewByteFrameFromBytes(data) + bf.WriteBytes(goocoo.ReadBytes(4)) + d := goocoo.ReadBytes(2) bf.WriteBytes(d) bf.WriteBytes(d) - bf.WriteBytes(gook.DataFromCurrent()) + bf.WriteBytes(goocoo.DataFromCurrent()) } else { bf.WriteBytes(data) } From aecb6af9e507a0d2b2c620d58e10cf54339b7bf6 Mon Sep 17 00:00:00 2001 From: Samboge Date: Sun, 1 Oct 2023 08:03:14 +0700 Subject: [PATCH 23/96] My Mission Fix for MHF-F5 Client only sent 322 byte (32 header + 290 byte of data) --- network/mhfpacket/msg_mhf_update_myhouse_info.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/network/mhfpacket/msg_mhf_update_myhouse_info.go b/network/mhfpacket/msg_mhf_update_myhouse_info.go index 469920127..a66bc6aa2 100644 --- a/network/mhfpacket/msg_mhf_update_myhouse_info.go +++ b/network/mhfpacket/msg_mhf_update_myhouse_info.go @@ -6,6 +6,7 @@ import ( "erupe-ce/network/clientctx" "erupe-ce/network" "erupe-ce/common/byteframe" + _config "erupe-ce/config" ) // MsgMhfUpdateMyhouseInfo represents the MSG_MHF_UPDATE_MYHOUSE_INFO @@ -22,7 +23,11 @@ func (m *MsgMhfUpdateMyhouseInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUpdateMyhouseInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadBytes(0x16A) + if _config.ErupeConfig.RealClientMode == _config.F5 { + m.Unk0 = bf.ReadBytes(0x122) + } else { + m.Unk0 = bf.ReadBytes(0x16A) + } return nil } From a6c83141875e8eddbb93f07fafae800604565db7 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 1 Oct 2023 15:54:45 +1100 Subject: [PATCH 24/96] convert some values to decimal --- server/channelserver/handlers_plate.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/channelserver/handlers_plate.go b/server/channelserver/handlers_plate.go index 3f5688184..19fdd84a2 100644 --- a/server/channelserver/handlers_plate.go +++ b/server/channelserver/handlers_plate.go @@ -42,7 +42,7 @@ func handleMsgMhfSavePlateData(s *Session, p mhfpacket.MHFPacket) { } } else { // create empty save if absent - data = make([]byte, 0x1AF20) + data = make([]byte, 140000) } // Perform diff and compress it to write back to db @@ -110,7 +110,7 @@ func handleMsgMhfSavePlateBox(s *Session, p mhfpacket.MHFPacket) { } } else { // create empty save if absent - data = make([]byte, 0x820) + data = make([]byte, 4800) } // Perform diff and compress it to write back to db @@ -147,7 +147,7 @@ func handleMsgMhfLoadPlateMyset(s *Session, p mhfpacket.MHFPacket) { err := s.server.db.QueryRow("SELECT platemyset FROM characters WHERE id = $1", s.charID).Scan(&data) if len(data) == 0 { s.logger.Error("Failed to load platemyset", zap.Error(err)) - data = make([]byte, 0x780) + data = make([]byte, 1920) } doAckBufSucceed(s, pkt.AckHandle, data) } From 1e1790eb845a5bcb681319eb862f48cb5dc3038a Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 1 Oct 2023 23:17:07 +1100 Subject: [PATCH 25/96] fix incorrect case for EnumerateHouse response --- server/channelserver/handlers_house.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index c00c2be73..4676eeb79 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -119,8 +119,7 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint8(0) } bf.WriteUint16(house.HRP) - //to skip GR for client below G1 - if _config.ErupeConfig.RealClientMode >= _config.G1{ + if _config.ErupeConfig.RealClientMode >= _config.G10 { bf.WriteUint16(house.GR) } ps.Uint8(bf, house.Name, true) From 5d4a81a84f4b976f98d85fb08c247a68878dbf9d Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 1 Oct 2023 23:18:23 +1100 Subject: [PATCH 26/96] fix BookshelfData length --- server/channelserver/handlers_character.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 301a17b63..36687b11d 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -19,7 +19,7 @@ const ( pRP // +2 pHouseTier // +5 pHouseData // +195 - pBookshelfData // +5576 + pBookshelfData // +lBookshelfData pGalleryData // +1748 pToreData // +240 pGardenData // +68 @@ -28,6 +28,7 @@ const ( pHRP // +2 pGRP // +4 pKQF // +8 + lBookshelfData ) type CharacterSaveData struct { @@ -55,7 +56,7 @@ type CharacterSaveData struct { } func getPointers() map[SavePointer]int { - pointers := map[SavePointer]int{pGender: 81} + pointers := map[SavePointer]int{pGender: 81, lBookshelfData: 5576} switch _config.ErupeConfig.RealClientMode { case _config.ZZ: pointers[pWeaponID] = 128522 @@ -95,6 +96,11 @@ func getPointers() map[SavePointer]int { pointers[pGardenData] = 74424 pointers[pRP] = 74614 } + if _config.ErupeConfig.RealClientMode == _config.G5 { + pointers[lBookshelfData] = 5548 + } else if _config.ErupeConfig.RealClientMode <= _config.GG { + pointers[lBookshelfData] = 4520 + } return pointers } @@ -190,7 +196,7 @@ func (save *CharacterSaveData) updateSaveDataWithStruct() { if _config.ErupeConfig.RealClientMode >= _config.G10 { copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF) - } else if _config.ErupeConfig.RealClientMode == _config.F5{ + } else if _config.ErupeConfig.RealClientMode == _config.F5 { copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) } } @@ -208,7 +214,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] - save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+5576] + save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+save.Pointers[lBookshelfData]] save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748] save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240] save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68] @@ -219,11 +225,11 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) } save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] - } else if _config.ErupeConfig.RealClientMode < _config.G10 { + } else if _config.ErupeConfig.RealClientMode == _config.F5 { save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] - save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+2576] + save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+save.Pointers[lBookshelfData]] save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748] save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240] save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68] From 2539afb5d34058fae15d5d0a2152bc4c020d0dfe Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 2 Oct 2023 00:45:28 +1100 Subject: [PATCH 27/96] simplify Festa reward data --- server/channelserver/handlers_festa.go | 49 +++++++------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 4f3807fa2..7ca50d9d1 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -162,14 +162,6 @@ type FestaReward struct { Unk7 uint8 } -type FestaRewardF5 struct { - Unk0 uint8 - Unk1 uint8 - ItemType uint16 - Quantity uint16 - ItemID uint16 -} - func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfInfoFesta) bf := byteframe.NewByteFrame() @@ -235,6 +227,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { } // The Winner and Loser Armor IDs are missing + // Item 7011 may not exist in older versions, remove to prevent crashes rewards := []FestaReward{ {1, 0, 7, 350, 1520, 0, 0, 0}, {1, 0, 7, 1000, 7011, 0, 0, 1}, @@ -263,34 +256,18 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { //{5, 0, 1, 0, 0, 0, 0, 0}, } - rewardsF5 := []FestaRewardF5{ - {1, 0, 7, 250, 1520}, - {1, 0, 12, 250, 0}, - {1, 0, 12, 250, 0}, - {1, 0, 12, 250, 0}, - {1, 0, 12, 250, 0}, - } - - if _config.ErupeConfig.RealClientMode >= _config.G1 { - bf.WriteUint16(uint16(len(rewards))) - for _, reward := range rewards { - bf.WriteUint8(reward.Unk0) - bf.WriteUint8(reward.Unk1) - bf.WriteUint16(reward.ItemType) - bf.WriteUint16(reward.Quantity) - bf.WriteUint16(reward.ItemID) - bf.WriteUint16(reward.Unk5) - bf.WriteUint16(reward.Unk6) - bf.WriteUint8(reward.Unk7) - } - } else if _config.ErupeConfig.RealClientMode == _config.F5{ - bf.WriteUint16(uint16(len(rewardsF5))) - for _, reward := range rewardsF5 { - bf.WriteUint8(reward.Unk0) - bf.WriteUint8(reward.Unk1) - bf.WriteUint16(reward.ItemType) - bf.WriteUint16(reward.Quantity) - bf.WriteUint16(reward.ItemID) + bf.WriteUint16(uint16(len(rewards))) + for _, reward := range rewards { + bf.WriteUint8(reward.Unk0) + bf.WriteUint8(reward.Unk1) + bf.WriteUint16(reward.ItemType) + bf.WriteUint16(reward.Quantity) + bf.WriteUint16(reward.ItemID) + // Not confirmed to be G1 but exists in G3 + if _config.ErupeConfig.RealClientMode >= _config.G1 { + bf.WriteUint16(reward.Unk5) + bf.WriteUint16(reward.Unk6) + bf.WriteUint8(reward.Unk7) } } if _config.ErupeConfig.RealClientMode <= _config.G61 { From aa98e89d773eead437bcaa76eadf7be5727ef5bf Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 2 Oct 2023 01:19:56 +1100 Subject: [PATCH 28/96] cover more versions with Hiden savedata --- .../mhfpacket/msg_mhf_update_myhouse_info.go | 21 ++++++++++++------- server/channelserver/handlers_house.go | 4 ++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/network/mhfpacket/msg_mhf_update_myhouse_info.go b/network/mhfpacket/msg_mhf_update_myhouse_info.go index a66bc6aa2..c5bf26d7a 100644 --- a/network/mhfpacket/msg_mhf_update_myhouse_info.go +++ b/network/mhfpacket/msg_mhf_update_myhouse_info.go @@ -1,18 +1,18 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" _config "erupe-ce/config" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfUpdateMyhouseInfo represents the MSG_MHF_UPDATE_MYHOUSE_INFO type MsgMhfUpdateMyhouseInfo struct { AckHandle uint32 - Unk0 []byte + Data []byte } // Opcode returns the ID associated with this packet type. @@ -23,10 +23,15 @@ func (m *MsgMhfUpdateMyhouseInfo) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUpdateMyhouseInfo) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - if _config.ErupeConfig.RealClientMode == _config.F5 { - m.Unk0 = bf.ReadBytes(0x122) + if _config.ErupeConfig.RealClientMode >= _config.G10 { + m.Data = bf.ReadBytes(362) + } else if _config.ErupeConfig.RealClientMode >= _config.GG { + m.Data = bf.ReadBytes(338) + } else if _config.ErupeConfig.RealClientMode >= _config.F5 { + // G1 is a guess + m.Data = bf.ReadBytes(314) } else { - m.Unk0 = bf.ReadBytes(0x16A) + m.Data = bf.ReadBytes(290) } return nil } diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 4676eeb79..560e73ec7 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -240,8 +240,8 @@ func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateMyhouseInfo) - s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Unk0, s.charID) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + s.server.db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", pkt.Data, s.charID) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) { From d389f110a82c22b0e4e68fcccf4afe83073215a0 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 2 Oct 2023 22:09:20 +1100 Subject: [PATCH 29/96] test new pointers --- server/channelserver/handlers_character.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 36687b11d..d4ecd65d6 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -84,14 +84,14 @@ func getPointers() map[SavePointer]int { pointers[pGardenData] = 106424 pointers[pRP] = 106614 pointers[pKQF] = 110720 - case _config.F5: + case _config.F5, _config.F4: pointers[pWeaponID] = 60522 pointers[pWeaponType] = 60789 pointers[pHouseTier] = 61900 - pointers[pToreData] = 60550 + pointers[pToreData] = 62228 pointers[pHRP] = 62550 - pointers[pHouseData] = 62651 - pointers[pBookshelfData] = 71928 + pointers[pHouseData] = 62561 + pointers[pBookshelfData] = 56830 pointers[pGalleryData] = 72064 pointers[pGardenData] = 74424 pointers[pRP] = 74614 @@ -196,7 +196,7 @@ func (save *CharacterSaveData) updateSaveDataWithStruct() { if _config.ErupeConfig.RealClientMode >= _config.G10 { copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) copy(save.decompSave[save.Pointers[pKQF]:save.Pointers[pKQF]+8], save.KQF) - } else if _config.ErupeConfig.RealClientMode == _config.F5 { + } else if _config.ErupeConfig.RealClientMode == _config.F5 || _config.ErupeConfig.RealClientMode == _config.F4 { copy(save.decompSave[save.Pointers[pRP]:save.Pointers[pRP]+2], rpBytes) } } @@ -225,7 +225,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) } save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] - } else if _config.ErupeConfig.RealClientMode == _config.F5 { + } else if _config.ErupeConfig.RealClientMode == _config.F5 || _config.ErupeConfig.RealClientMode == _config.F4 { save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] From 6bc883cc0e7f14328d89f6077b7ba694aaa8a33c Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 2 Oct 2023 23:10:48 +1100 Subject: [PATCH 30/96] update README --- README.md | 115 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index ede542a20..8f17c33ce 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,13 @@ - PlayStation 3 - PlayStation Vita - Wii U (Up to Z2) -### Versions -- ZZ -- Z2 -- Z1 +### Versions (ClientMode) +All versions after HR compression (G10-ZZ) have been tested extensively and have great functionality. +All versions available on Wii U (G3-Z2) have been tested and should have good functionality. +The second oldest found version is Forward.4 (FW.4), this version has basic functionality. +The oldest found version is Season 6.0 (S6.0), however functionality is very limited. + +If you have an **installed** copy of Monster Hunter Frontier on an old hard drive, **please** get in contact so we can archive it! ## Setup @@ -32,50 +35,50 @@ If you want to modify or compile Erupe yourself, please read on. ## Resources - [Quest and Scenario Binary Files](https://files.catbox.moe/xf0l7w.7z) -- [PewPewDojo Discord](https://discord.gg/CFnzbhQ) +- [Mezeporta Square Discord](https://discord.gg/DnwcpXM488) ## Configuration This portion of the documentation goes over the `config.json` file. ### General Configuration -| Variable | Description | Default | Options | -|------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|---------------------------------| -| Host | The IP or host address the server is running from | 127.0.0.1 | | -| BinPath | The bin path folder is where you place files needed for various parts of the game such as scenario and quest files | bin | | -| Language | This is the language the server will run in. Only English `en` and Japanese `ja` are available, if you wish to contribute to tranlation, get in touch | en | en/jp | -| DisableSoftCrash | | false | | -| HideLoginNotice | This hides the notices that appear on login from `LoginNotices` | true | | -| LoginNotices | This is where you place notices for users, you can have multiple notices | | | -| PatchServerManifest | | | | -| PatchServerFile | | | | -| ScreenshotAPIURL | This is the URL you want user sreenshots to go to | | | -| DeleteOnSaveCorruption | This option deletes a users save from the database if they corrupt it, can be used as punishment for cheaters | false | | -| ClientMode | This tells the server what client version it should target | ZZ | Check compatible versions above | -| DevMode | This enables DevModeOptions to be configured | true | | +| Variable | Description | Default | Options | +|------------------------|-----------------------------------------------------------------------------------------------------------------------|-----------|---------------------------------| +| Host | The IP or host address the server is running from | 127.0.0.1 | | +| BinPath | The bin path folder is where you place files needed for various parts of the game such as scenario and quest files | bin | | +| Language | This is the language the server will run in. Only English `en` and Japanese `jp` are available, contributions welcome | en | en/jp | +| DisableSoftCrash | | false | | +| HideLoginNotice | This hides the notices that appear on login from `LoginNotices` | true | | +| LoginNotices | This is where you place notices for users, you can have multiple notices | | | +| PatchServerManifest | | | | +| PatchServerFile | | | | +| ScreenshotAPIURL | This is the URL you want user sreenshots to go to | | | +| DeleteOnSaveCorruption | This option flags a character as deleted if they corrupt it, can be used as punishment for cheaters | false | | +| ClientMode | This tells the server what client version it should target | ZZ | Check compatible versions above | +| DevMode | This enables DevModeOptions to be configured | true | | ### `DevModeOptions` Configuraiton -| Variable | Description | Default | Options | -|----------------------|---------------------------------------------------------------------------------------------|----------|----------------------------------| -| AutoCreateAccount | This allows users that don't exist to auto create there account from initial login | true | | -| CleanDB | This cleans the database down | false | | -| MaxLauncherHR | This sets the launcher value to HR7 to allow you to break World HR requirements | false | | -| LogInboundMessages | This will allow inbound messages to be logged to stdout | false | | -| LogOutboundMessages | This will allow outbound messages to be logged to stdout | false | | -| MaxHexdumpLength | This is the maximum amount of hex bytes that will be dumped to stdout | 0 | | -| DivaEvent | This overrides the Diva event stage in game | 2 | 0/1/2/3/-1 | -| FestaEvent | This overrides the Hunter Festival event stage in game | 2 | 0/1/2/3/-1 | -| TournamentEvent | This overrides the Hunter Tournament event stage in game | 2 | 0/1/2/3/-1 | -| MezFesEvent | Enables whether the MezFes event & World are active | true | | -| MezFesAlt | Switches the multiplayer MezFes event | false | | -| DisableTokenCheck | This disables the random token that is generated at login from being checked, very insecure | false | | -| QuestDebugTools | Enable various quest debug logs | false | | -| EarthStatusOverride | Enables Pallone Fest, Tower and Conquest War events | 0 | 2=Conquest, 11=Pallone, 21=Tower | -| EarthIDOverride | A random event ID | 0 | | -| EarthMonsterOverride | Sets the ID of the monster targeted in the Conquest War | 0 | | -| SaveDumps.Enables | Enables save dumps to a folder that is set at `SaveDumps.OutputDir` | true | | -| SaveDumps.OutputDir | The folder that save dumps are saved to | savedata | | +| Variable | Description | Default | Options | +|----------------------|---------------------------------------------------------------------------------------------|--------------|----------------------------------| +| AutoCreateAccount | This allows users that don't exist to auto create their account from initial login | true | | +| CleanDB | This cleans the database down | false | | +| MaxLauncherHR | This sets the launcher value to HR7 to allow you to break World HR requirements | false | | +| LogInboundMessages | This will allow inbound messages to be logged to stdout | false | | +| LogOutboundMessages | This will allow outbound messages to be logged to stdout | false | | +| MaxHexdumpLength | This is the maximum amount of hex bytes that will be dumped to stdout | 0 | | +| DivaEvent | This overrides the Diva event stage in game | 0 | 0/1/2/3/-1 | +| FestaEvent | This overrides the Hunter Festival event stage in game | -1 | 0/1/2/3/-1 | +| TournamentEvent | This overrides the Hunter Tournament event stage in game | 0 | 0/1/2/3/-1 | +| MezFesEvent | Enables whether the MezFes event & World are active | true | | +| MezFesAlt | Switches the multiplayer MezFes minigame | false | | +| DisableTokenCheck | This disables the random token that is generated at login from being checked, very insecure | false | | +| QuestDebugTools | Enable various quest debug logs | false | | +| EarthStatusOverride | Enables Pallone Fest, Tower and Conquest War events | 0 | 2=Conquest, 11=Pallone, 21=Tower | +| EarthIDOverride | A random event ID | 0 | | +| EarthMonsterOverride | Sets the ID of the monster targeted in the Conquest War | 0 | | +| SaveDumps.Enables | Enables save dumps to a folder that is set at `SaveDumps.OutputDir` | true | | +| SaveDumps.OutputDir | The folder that save dumps are saved to | save-backups | | ### `GameplayOptions` Configuraiton @@ -111,14 +114,14 @@ This may be either be removed or revamped in a future version. ### Commands There are several chat commands that can be turned on and off. Most of them are really for admins or debugging purposes. -| Name | command | Description | Options | -|----------|----------------|--------------------------------------------|---------------------| -| Rights | !rights VALUE | Sets the rights integer for your account | | -| Teleport | !tele X,Y | Teleports user to specific x,y coordinate | | -| Reload | !reload | Reloads all users and character objects | | -| KeyQuest | !kqf FLAGS | Sets the Key Quest Flag for your character | | -| Course | !course OPTION | Enables/Disables a course for your account | HL,EX,Premium,Boost | -| PSN | !psn USERNAME | Links the specified PSN to your account | | +| Name | command | Description | Default | Options | +|----------|----------------|--------------------------------------------|----------|---------------------| +| Rights | !rights VALUE | Sets the rights integer for your account | disabled | | +| Teleport | !tele X,Y | Teleports user to specific x,y coordinate | disabled | | +| Reload | !reload | Reloads all users and character objects | enabled | | +| KeyQuest | !kqf FLAGS | Sets the Key Quest Flag for your character | disabled | | +| Course | !course OPTION | Enables/Disables a course for your account | enabled | HL,EX,Premium,Boost | +| PSN | !psn USERNAME | Links the specified PSN to your account | enabled | | ### Ravi Sub Commands | Name | command | Description | @@ -132,16 +135,16 @@ There are several chat commands that can be turned on and off. Most of them are ## World `Entries` config -| Config Item | Description | Options | -|-------------|------------------|------------------------------------------------------------| -| Type | Server type. | 1=Normal, 2=Cities, 3=Newbie, 4=Tavern, 5=Return, 6=MezFes | -| Season | Server activity. | 0=Green/Breeding, 1=Orange/Warm, 2=Blue/Cold | +| Config Item | Description | Options | +|-------------|---------------|------------------------------------------------------------| +| Type | Server type | 1=Normal, 2=Cities, 3=Newbie, 4=Tavern, 5=Return, 6=MezFes | +| Season | Server season | 0=Green/Breeding, 1=Orange/Warm, 2=Blue/Cold | ### `Recommend` -This sets the types of quest that can be ordered from a world. +This sets the types of Quests that can be ordered from a World. * 0 = All quests -* 1 = Up to 2 star quests -* 2 = Up to 4 star quests +* 1 = Up to 2 star Quests +* 2 = Up to 4 star Quests * 4 = All Quests in HR (Enables G Experience Tab) -* 5 = Only G rank quests -* 6 = Mini games world there is no place to order quests \ No newline at end of file +* 5 = Only G Rank Quests +* 6 = Minigame World \ No newline at end of file From d0431fbc1c9c8f230191ab7f5ee80a9042734b17 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 2 Oct 2023 23:13:19 +1100 Subject: [PATCH 31/96] ignore name-checker if using Season modes --- server/channelserver/handlers_data.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 2d95e97d0..81102b42d 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -2,6 +2,7 @@ package channelserver import ( "erupe-ce/common/stringsupport" + _config "erupe-ce/config" "fmt" "io" "os" @@ -54,7 +55,7 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.Name = characterSaveData.Name } - if characterSaveData.Name == s.Name { + if characterSaveData.Name == s.Name || _config.ErupeConfig.RealClientMode <= _config.S10 { characterSaveData.Save(s) s.logger.Info("Wrote recompressed savedata back to DB.") } else { From 8fbbf1382247e2681893554137983d86c7980e6c Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 3 Oct 2023 00:48:37 +1100 Subject: [PATCH 32/96] use better Bookshelf pointer & simplify pointer assignment --- server/channelserver/handlers_character.go | 26 ++++++++-------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index d4ecd65d6..4c5802293 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -91,7 +91,7 @@ func getPointers() map[SavePointer]int { pointers[pToreData] = 62228 pointers[pHRP] = 62550 pointers[pHouseData] = 62561 - pointers[pBookshelfData] = 56830 + pointers[pBookshelfData] = 57118 // This pointer only half works pointers[pGalleryData] = 72064 pointers[pGardenData] = 74424 pointers[pRP] = 74614 @@ -210,22 +210,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.Gender = false } if !save.IsNewCharacter { - if _config.ErupeConfig.RealClientMode >= _config.G10 { - save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) - save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] - save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] - save.BookshelfData = save.decompSave[save.Pointers[pBookshelfData] : save.Pointers[pBookshelfData]+save.Pointers[lBookshelfData]] - save.GalleryData = save.decompSave[save.Pointers[pGalleryData] : save.Pointers[pGalleryData]+1748] - save.ToreData = save.decompSave[save.Pointers[pToreData] : save.Pointers[pToreData]+240] - save.GardenData = save.decompSave[save.Pointers[pGardenData] : save.Pointers[pGardenData]+68] - save.WeaponType = save.decompSave[save.Pointers[pWeaponType]] - save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2]) - save.HRP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHRP] : save.Pointers[pHRP]+2]) - if save.HRP == uint16(999) { - save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) - } - save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] - } else if _config.ErupeConfig.RealClientMode == _config.F5 || _config.ErupeConfig.RealClientMode == _config.F4 { + if (_config.ErupeConfig.RealClientMode >= _config.F4 && _config.ErupeConfig.RealClientMode <= _config.F5) || _config.ErupeConfig.RealClientMode >= _config.G10 { save.RP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pRP] : save.Pointers[pRP]+2]) save.HouseTier = save.decompSave[save.Pointers[pHouseTier] : save.Pointers[pHouseTier]+5] save.HouseData = save.decompSave[save.Pointers[pHouseData] : save.Pointers[pHouseData]+195] @@ -237,6 +222,13 @@ func (save *CharacterSaveData) updateStructWithSaveData() { save.WeaponID = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pWeaponID] : save.Pointers[pWeaponID]+2]) save.HRP = binary.LittleEndian.Uint16(save.decompSave[save.Pointers[pHRP] : save.Pointers[pHRP]+2]) } + + if _config.ErupeConfig.RealClientMode >= _config.G10 { + save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] + if save.HRP == uint16(999) { + save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) + } + } } return } From 0f2edbf0286d97e74c7359f78df032e31859c7ae Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 3 Oct 2023 23:05:45 +1100 Subject: [PATCH 33/96] simplify & fix UpdateRavi --- server/channelserver/sys_channel_server.go | 31 +++++++++------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 5a4b29fe9..1dfef82d0 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -115,6 +115,7 @@ func (s *Server) GetRaviMultiplier() float64 { func (s *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update bool) (uint32, uint32) { var prev uint32 + var dest *[]uint32 switch semaID { case 0x40000: switch index { @@ -123,28 +124,20 @@ func (s *Server) UpdateRavi(semaID uint32, index uint8, value uint32, update boo default: value = uint32(float64(value) * s.GetRaviMultiplier()) } - prev = s.raviente.state[index] - if prev != 0 && !update { - return prev, prev - } - s.raviente.state[index] += value - return prev, s.raviente.state[index] + dest = &s.raviente.state case 0x50000: - prev = s.raviente.support[index] - if prev != 0 && !update { - return prev, prev - } - s.raviente.support[index] += value - return prev, s.raviente.support[index] + dest = &s.raviente.support case 0x60000: - prev = s.raviente.register[index] - if prev != 0 && !update { - return prev, prev - } - s.raviente.register[index] += value - return prev, s.raviente.register[index] + dest = &s.raviente.register + default: + return 0, 0 } - return 0, 0 + if update { + (*dest)[index] += value + } else { + (*dest)[index] = value + } + return prev, (*dest)[index] } // NewServer creates a new Server type. From 80a2822214d92a48f04b2b56f28540ef97c54b89 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 7 Oct 2023 17:33:40 +1100 Subject: [PATCH 34/96] #74 update file names & default scenarios --- bundled-schema/DefaultScenarios.sql | 120 ------------ bundled-schema/ScenarioDefaults.sql | 178 ++++++++++++++++++ ...s-counter.sql => 07-scenarios-counter.sql} | 0 3 files changed, 178 insertions(+), 120 deletions(-) delete mode 100644 bundled-schema/DefaultScenarios.sql create mode 100644 bundled-schema/ScenarioDefaults.sql rename patch-schema/{scenarios-counter.sql => 07-scenarios-counter.sql} (100%) diff --git a/bundled-schema/DefaultScenarios.sql b/bundled-schema/DefaultScenarios.sql deleted file mode 100644 index d3eb2899a..000000000 --- a/bundled-schema/DefaultScenarios.sql +++ /dev/null @@ -1,120 +0,0 @@ -BEGIN; - -INSERT INTO public.scenario_counter -(scenario_id, category_id) -VALUES - (0,0), - (1,0), - (2,0), - (3,0), - (4,0), - (5,0), - (6,0), - (7,0), - (8,0), - (9,0), - (10,0), - (11,0), - (12,0), - (13,0), - (14,0), - (15,0), - (16,0), - (17,0), - (18,0), - (19,0), - (0,1), - (1,1), - (2,1), - (3,1), - (4,1), - (5,1), - (6,1), - (7,1), - (8,1), - (9,1), - (10,1), - (11,1), - (12,1), - (13,1), - (16,1), - (17,1), - (19,1), - (21,1), - (22,1), - (23,1), - (27,1), - (28,1), - (29,1), - (30,1), - (31,1), - (32,1), - (33,1), - (34,1), - (35,1), - (36,1), - (37,1), - (38,1), - (39,1), - (41,1), - (42,1), - (43,1), - (46,1), - (47,1), - (48,1), - (49,1), - (58,1), - (59,1), - (60,1), - (61,1), - (62,1), - (63,1), - (64,1), - (65,1), - (66,1), - (67,1), - (68,1), - (69,1), - (70,1), - (77,1), - (79,1), - (81,1), - (82,1), - (83,1), - (84,1), - (85,1), - (86,1), - (87,1), - (88,1), - (89,1), - (90,1), - (92,1), - (93,1), - (13,1), - (14,1), - (15,1), - (18,1), - (20,1), - (24,1), - (25,1), - (26,1), - (40,1), - (50,1), - (51,1), - (52,1), - (53,1), - (54,1), - (55,1), - (56,1), - (57,1), - (71,1), - (72,1), - (73,1), - (74,1), - (75,1), - (76,1), - (78,1), - (80,1), - (91,1); - -END; \ No newline at end of file diff --git a/bundled-schema/ScenarioDefaults.sql b/bundled-schema/ScenarioDefaults.sql new file mode 100644 index 000000000..ec7b3d99e --- /dev/null +++ b/bundled-schema/ScenarioDefaults.sql @@ -0,0 +1,178 @@ +BEGIN; + +INSERT INTO public.scenario_counter +(scenario_id, category_id) +VALUES + (17,0), + (93,1), + (92,1), + (81,1), + (91,1), + (90,1), + (89,1), + (88,1), + (87,1), + (86,1), + (85,1), + (84,1), + (83,1), + (82,1), + (87,3), + (88,3), + (89,3), + (90,3), + (91,3), + (92,3), + (83,3), + (86,3), + (60,3), + (58,3), + (59,3), + (27,3), + (25,3), + (26,3), + (23,3), + (2,3), + (3,3), + (4,3), + (31,3), + (32,3), + (33,3), + (34,3), + (35,3), + (36,3), + (37,3), + (40,3), + (38,3), + (39,3), + (48,3), + (12,3), + (13,3), + (30,3), + (29,3), + (46,3), + (0,4), + (1,4), + (2,4), + (3,4), + (4,4), + (5,4), + (6,4), + (7,4), + (8,4), + (9,4), + (10,4), + (11,4), + (12,4), + (13,4), + (14,4), + (50,5), + (51,5), + (52,5), + (53,5), + (54,5), + (55,5), + (56,5), + (58,5), + (63,5), + (64,5), + (65,5), + (67,5), + (71,5), + (75,5), + (61,5), + (68,5), + (66,5), + (76,5), + (70,5), + (77,5), + (72,5), + (74,5), + (73,5), + (78,5), + (69,5), + (62,5), + (79,5), + (0,6), + (1,6), + (2,6), + (3,6), + (4,6), + (5,6), + (6,6), + (7,6), + (8,6), + (9,6), + (17,6), + (10,6), + (11,6), + (12,6), + (13,6), + (14,6), + (15,6), + (16,6), + (50,7), + (53,7), + (62,7), + (52,7), + (56,7), + (51,7), + (49,7), + (54,7), + (57,7), + (55,7), + (61,7), + (58,7), + (60,7), + (59,7), + (42,7), + (48,7), + (40,7), + (39,7), + (43,7), + (46,7), + (41,7), + (44,7), + (45,7), + (47,7), + (37,7), + (34,7), + (33,7), + (32,7), + (28,7), + (26,7), + (36,7), + (38,7), + (35,7), + (27,7), + (30,7), + (31,7), + (29,7), + (24,7), + (23,7), + (22,7), + (21,7), + (25,7), + (20,7), + (7,7), + (9,7), + (13,7), + (16,7), + (12,7), + (14,7), + (15,7), + (19,7), + (10,7), + (8,7), + (11,7), + (18,7), + (17,7), + (6,7), + (5,7), + (4,7), + (3,7), + (2,7), + (1,7), + (0,7); + +END; \ No newline at end of file diff --git a/patch-schema/scenarios-counter.sql b/patch-schema/07-scenarios-counter.sql similarity index 100% rename from patch-schema/scenarios-counter.sql rename to patch-schema/07-scenarios-counter.sql From 8e27617727341ac747ae655ca68c6e4497b2a845 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 7 Oct 2023 19:58:49 +1100 Subject: [PATCH 35/96] convert Guild Missions to struct --- server/channelserver/handlers_guild.go | 50 +++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 5fdd2dac1..d578f5b7b 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -4,7 +4,6 @@ import ( "database/sql" "database/sql/driver" "encoding/binary" - "encoding/hex" "encoding/json" "errors" _config "erupe-ce/config" @@ -1723,16 +1722,51 @@ func handleMsgMhfReadGuildcard(s *Session, p mhfpacket.MHFPacket) { doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } +type GuildMission struct { + ID uint32 + Unk uint32 + Type uint16 + Goal uint16 + Quantity uint16 + SkipTickets uint16 + GR bool + RewardType uint16 + RewardLevel uint16 +} + func handleMsgMhfGetGuildMissionList(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildMissionList) - - decoded, err := hex.DecodeString("000694610000023E000112990023000100000200015DDD232100069462000002F30000005F000C000200000300025DDD232100069463000002EA0000005F0006000100000100015DDD23210006946400000245000000530010000200000400025DDD232100069465000002B60001129B0019000100000200015DDD232100069466000003DC0000001B0010000100000600015DDD232100069467000002DA000112A00019000100000400015DDD232100069468000002A800010DEF0032000200000200025DDD2321000694690000045500000022003C000200000600025DDD23210006946A00000080000122D90046000200000300025DDD23210006946B000001960000003B000A000100000100015DDD23210006946C0000049200000046005A000300000600035DDD23210006946D000000A4000000260018000200000600025DDD23210006946E0000017A00010DE40096000300000100035DDD23210006946F000001BE0000005E0014000200000400025DDD2355000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - - if err != nil { - panic(err) + bf := byteframe.NewByteFrame() + missions := []GuildMission{ + {431201, 574, 1, 4761, 35, 1, false, 2, 1}, + {431202, 755, 0, 95, 12, 2, false, 3, 2}, + {431203, 746, 0, 95, 6, 1, false, 1, 1}, + {431204, 581, 0, 83, 16, 2, false, 4, 2}, + {431205, 694, 1, 4763, 25, 1, false, 2, 1}, + {431206, 988, 0, 27, 16, 1, false, 6, 1}, + {431207, 730, 1, 4768, 25, 1, false, 4, 1}, + {431208, 680, 1, 3567, 50, 2, false, 2, 2}, + {431209, 1109, 0, 34, 60, 2, false, 6, 2}, + {431210, 128, 1, 8921, 70, 2, false, 3, 2}, + {431211, 406, 0, 59, 10, 1, false, 1, 1}, + {431212, 1170, 0, 70, 90, 3, false, 6, 3}, + {431213, 164, 0, 38, 24, 2, false, 6, 2}, + {431214, 378, 1, 3556, 150, 3, false, 1, 3}, + {431215, 446, 0, 94, 20, 2, false, 4, 2}, } - - doAckBufSucceed(s, pkt.AckHandle, decoded) + for _, mission := range missions { + bf.WriteUint32(mission.ID) + bf.WriteUint32(mission.Unk) + bf.WriteUint16(mission.Type) + bf.WriteUint16(mission.Goal) + bf.WriteUint16(mission.Quantity) + bf.WriteUint16(mission.SkipTickets) + bf.WriteBool(mission.GR) + bf.WriteUint16(mission.RewardType) + bf.WriteUint16(mission.RewardLevel) + bf.WriteUint32(uint32(TimeAdjusted().Unix())) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfGetGuildMissionRecord(s *Session, p mhfpacket.MHFPacket) { From f37915bcae365bb3f8ab69ec1f3c291c284f8c3d Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 7 Oct 2023 19:59:37 +1100 Subject: [PATCH 36/96] simplify Guild Huntdata & decimal conversions --- server/channelserver/handlers_guild.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index d578f5b7b..6ef507b84 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1851,14 +1851,14 @@ func handleMsgMhfGetGuildWeeklyBonusMaster(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildWeeklyBonusMaster) // Values taken from brand new guild capture - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 0x28)) + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 40)) } func handleMsgMhfGetGuildWeeklyBonusActiveCount(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildWeeklyBonusActiveCount) bf := byteframe.NewByteFrame() - bf.WriteUint8(0x3C) // Active count - bf.WriteUint8(0x3C) // Current active count - bf.WriteUint8(0x00) // New active count + bf.WriteUint8(60) // Active count + bf.WriteUint8(60) // Current active count + bf.WriteUint8(0) // New active count doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } @@ -1866,18 +1866,18 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGuildHuntdata) bf := byteframe.NewByteFrame() switch pkt.Operation { - case 0: // Unk - doAckBufSucceed(s, pkt.AckHandle, []byte{}) - case 1: // Get Huntdata + case 0: // Acquire + // Probably mark everything as claimed + case 1: // Enumerate bf.WriteUint8(0) // Entries /* Entry format uint32 UnkID uint32 MonID */ - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - case 2: // Unk, controls glow - doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00}) + case 2: // Check + bf.WriteBool(false) } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } type MessageBoardPost struct { From 641032f862d7354c605f6800c6126e6efc05402c Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 8 Oct 2023 19:25:48 +1100 Subject: [PATCH 37/96] implement hunt data logging (partial #82) --- common/mhfmon/mhfmon.go | 366 ++++++++++++++++++++++++ network/mhfpacket/msg_sys_record_log.go | 26 +- patch-schema/08-kill-counts.sql | 12 + server/channelserver/handlers.go | 14 +- server/channelserver/handlers_guild.go | 48 +++- 5 files changed, 445 insertions(+), 21 deletions(-) create mode 100644 common/mhfmon/mhfmon.go create mode 100644 patch-schema/08-kill-counts.sql diff --git a/common/mhfmon/mhfmon.go b/common/mhfmon/mhfmon.go new file mode 100644 index 000000000..183a75bd8 --- /dev/null +++ b/common/mhfmon/mhfmon.go @@ -0,0 +1,366 @@ +package mhfmon + +const ( + Mon0 = iota + Rathian + Fatalis + Kelbi + Mosswine + Bullfango + YianKutKu + LaoShanLung + Cephadrome + Felyne + VeggieElder + Rathalos + Aptonoth + Genprey + Diablos + Khezu + Velociprey + Gravios + Mon18 + Vespoid + Gypceros + Plesioth + Basarios + Melynx + Hornetaur + Apceros + Monoblos + Velocidrome + Gendrome + Mon29 + Ioprey + Iodrome + Mon32 + Kirin + Cephalos + Giaprey + CrimsonFatalis + PinkRathian + BlueYianKutKu + PurpleGypceros + YianGaruga + SilverRathalos + GoldRathian + BlackDiablos + WhiteMonoblos + RedKhezu + GreenPlesioth + BlackGravios + DaimyoHermitaur + AzureRathalos + AshenLaoShanLung + Blangonga + Congalala + Rajang + KushalaDaora + ShenGaoren + GreatThunderbug + Shakalaka + YamaTsukami + Chameleos + RustedKushalaDaora + Blango + Conga + Remobra + Lunastra + Teostra + Hermitaur + ShogunCeanataur + Bulldrome + Anteka + Popo + WhiteFatalis + Mon72 + Ceanataur + Hypnocatrice + Lavasioth + Tigrex + Akantor + BrightHypnoc + RedLavasioth + Espinas + OrangeEspinas + WhiteHypnoc + AqraVashimu + AqraJebia + Berukyurosu + Mon86 + Mon87 + Mon88 + Pariapuria + WhiteEspinas + KamuOrugaron + NonoOrugaron + Raviente + Dyuragaua + Doragyurosu + Gurenzeburu + Burukku + Erupe + Rukodiora + Unknown + Gogomoa + Kokomoa + TaikunZamuza + Abiorugu + Kuarusepusu + Odibatorasu + Disufiroa + Rebidiora + Anorupatisu + Hyujikiki + Midogaron + Giaorugu + MiRu + Farunokku + Pokaradon + Shantien + Pokara + Mon118 + Goruganosu + Aruganosu + Baruragaru + Zerureusu + Gougarf + Uruki + Forokururu + Meraginasu + Diorex + GarubaDaora + Inagami + Varusaburosu + Poborubarumu + Block1Duremudira + Mon133 + Mon134 + Mon135 + Mon136 + Mon137 + Mon138 + Gureadomosu + Harudomerugu + Toridcless + Gasurabazura + Kusubami + YamaKurai + Block2Duremudira + Zinogre + Deviljho + Brachydios + BerserkRaviente + ToaTesukatora + Barioth + Uragaan + StygianZinogre + Guanzorumu + SavageDeviljho + Mon156 + Egyurasu + Voljang + Nargacuga + Keoaruboru + Zenaserisu + GoreMagala + BlinkingNargacuga + ShagaruMagala + Amatsu + Eruzerion + MusouDuremudira + Mon168 + Seregios + Bogabadorumu + Mon171 + MusouBogabadorumu + CostumedUruki + MusouZerureusu + Rappy + KingShakalaka +) + +type Monster struct { + Name string + Large bool +} + +var Monsters = []Monster{ + {"Mon0", false}, + {"Rathian", true}, + {"Fatalis", true}, + {"Kelbi", false}, + {"Mosswine", false}, + {"Bullfango", false}, + {"Yian Kut-Ku", true}, + {"Lao-Shan Lung", true}, + {"Cephadrome", true}, + {"Felyne", false}, + {"Veggie Elder", false}, + {"Rathalos", true}, + {"Aptonoth", false}, + {"Genprey", false}, + {"Diablos", true}, + {"Khezu", true}, + {"Velociprey", false}, + {"Gravios", true}, + {"Mon18", false}, + {"Vespoid", false}, + {"Gypceros", true}, + {"Plesioth", true}, + {"Basarios", true}, + {"Melynx", false}, + {"Hornetaur", false}, + {"Apceros", false}, + {"Monoblos", true}, + {"Velocidrome", true}, + {"Gendrome", true}, + {"Mon29", false}, + {"Ioprey", false}, + {"Iodrome", true}, + {"Mon32", false}, + {"Kirin", true}, + {"Cephalos", false}, + {"Giaprey", false}, + {"Crimson Fatalis", true}, + {"Pink Rathian", true}, + {"Blue Yian Kut-Ku", true}, + {"Purple Gypceros", true}, + {"Yian Garuga", true}, + {"Silver Rathalos", true}, + {"Gold Rathian", true}, + {"Black Diablos", true}, + {"White Monoblos", true}, + {"Red Khezu", true}, + {"Green Plesioth", true}, + {"Black Gravios", true}, + {"Daimyo Hermitaur", true}, + {"Azure Rathalos", true}, + {"Ashen Lao-Shan Lung", true}, + {"Blangonga", true}, + {"Congalala", true}, + {"Rajang", true}, + {"Kushala Daora", true}, + {"Shen Gaoren", true}, + {"Great Thunderbug", false}, + {"Shakalaka", false}, + {"Yama Tsukami", true}, + {"Chameleos", true}, + {"Rusted Kushala Daora", true}, + {"Blango", false}, + {"Conga", false}, + {"Remobra", false}, + {"Lunastra", true}, + {"Teostra", true}, + {"Hermitaur", false}, + {"Shogun Ceanataur", true}, + {"Bulldrome", true}, + {"Anteka", false}, + {"Popo", false}, + {"White Fatalis", true}, + {"Mon72", false}, + {"Ceanataur", false}, + {"Hypnocatrice", true}, + {"Lavasioth", true}, + {"Tigrex", true}, + {"Akantor", true}, + {"Bright Hypnocatrice", true}, + {"Red Lavasioth", true}, + {"Espinas", true}, + {"Orange Espinas", true}, + {"White Hypnocatrice", true}, + {"Aqra Vashimu", true}, + {"Aqra Jebia", true}, + {"Berukyurosu", true}, + {"Mon86", false}, + {"Mon87", false}, + {"Mon88", false}, + {"Pariapuria", true}, + {"White Espinas", true}, + {"Kamu Orugaron", true}, + {"Nono Orugaron", true}, + {"Raviente", true}, // + Violent + {"Dyuragaua", true}, + {"Doragyurosu", true}, + {"Gurenzeburu", true}, + {"Burukku", false}, + {"Erupe", false}, + {"Rukodiora", true}, + {"Unknown", true}, + {"Gogomoa", true}, + {"Kokomoa", false}, + {"Taikun Zamuza", true}, + {"Abiorugu", true}, + {"Kuarusepusu", true}, + {"Odibatorasu", true}, + {"Disufiroa", true}, + {"Rebidiora", true}, + {"Anorupatisu", true}, + {"Hyujikiki", true}, + {"Midogaron", true}, + {"Giaorugu", true}, + {"Mi-Ru", true}, // + Musou + {"Farunokku", true}, + {"Pokaradon", true}, + {"Shantien", true}, + {"Pokara", false}, + {"Mon118", false}, + {"Goruganosu", true}, + {"Aruganosu", true}, + {"Baruragaru", true}, + {"Zerureusu", true}, + {"Gougarf", true}, // Both + {"Uruki", false}, + {"Forokururu", true}, + {"Meraginasu", true}, + {"Diorex", true}, + {"Garuba Daora", true}, + {"Inagami", true}, + {"Varusablos", true}, + {"Poborubarumu", true}, + {"1st Block Duremudira", true}, + {"Mon133", false}, + {"Mon134", false}, + {"Mon135", false}, + {"Mon136", false}, + {"Mon137", false}, + {"Mon138", false}, + {"Gureadomosu", true}, + {"Harudomerugu", true}, + {"Toridcless", true}, + {"Gasurabazura", true}, + {"Kusubami", false}, + {"Yama Kurai", true}, + {"2nd Block Duremudira", true}, + {"Zinogre", true}, + {"Deviljho", true}, + {"Brachydios", true}, + {"Berserk Raviente", true}, + {"Toa Tesukatora", true}, + {"Barioth", true}, + {"Uragaan", true}, + {"Stygian Zinogre", true}, + {"Guanzorumu", true}, + {"Savage Deviljho", true}, // + Starving/Heavenly + {"Mon156", false}, + {"Egyurasu", false}, + {"Voljang", true}, + {"Nargacuga", true}, + {"Keoaruboru", true}, + {"Zenaserisu", true}, + {"Gore Magala", true}, + {"Blinking Nargacuga", true}, + {"Shagaru Magala", true}, + {"Amatsu", true}, + {"Eruzerion", true}, // + Musou + {"Musou Duremudira", true}, + {"Mon168", false}, + {"Seregios", true}, + {"Bogabadorumu", true}, + {"Mon171", false}, + {"Musou Bogabadorumu", true}, + {"Costumed Uruki", false}, + {"Musou Zerureusu", true}, + {"Rappy", false}, + {"King Shakalaka", false}, +} diff --git a/network/mhfpacket/msg_sys_record_log.go b/network/mhfpacket/msg_sys_record_log.go index 4266ec774..dcdf3e5a2 100644 --- a/network/mhfpacket/msg_sys_record_log.go +++ b/network/mhfpacket/msg_sys_record_log.go @@ -1,21 +1,19 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysRecordLog represents the MSG_SYS_RECORD_LOG type MsgSysRecordLog struct { - AckHandle uint32 - Unk0 uint32 - Unk1 uint16 // Hardcoded 0 - HardcodedDataSize uint16 // Hardcoded 0x4AC - Unk3 uint32 // Some shared ID with MSG_MHF_GET_SEIBATTLE. World ID?? - DataBuf []byte + AckHandle uint32 + Unk0 uint32 + Unk1 uint32 + Data []byte } // Opcode returns the ID associated with this packet type. @@ -27,10 +25,10 @@ func (m *MsgSysRecordLog) Opcode() network.PacketID { func (m *MsgSysRecordLog) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint32() - m.Unk1 = bf.ReadUint16() - m.HardcodedDataSize = bf.ReadUint16() - m.Unk3 = bf.ReadUint32() - m.DataBuf = bf.ReadBytes(uint(m.HardcodedDataSize)) + bf.ReadUint16() // Zeroed + size := bf.ReadUint16() + m.Unk1 = bf.ReadUint32() + m.Data = bf.ReadBytes(uint(size)) return nil } diff --git a/patch-schema/08-kill-counts.sql b/patch-schema/08-kill-counts.sql new file mode 100644 index 000000000..1c170cedd --- /dev/null +++ b/patch-schema/08-kill-counts.sql @@ -0,0 +1,12 @@ +CREATE TABLE public.kill_logs +( + id serial, + character_id integer NOT NULL, + monster integer NOT NULL, + quantity integer NOT NULL, + timestamp timestamp with time zone NOT NULL, + PRIMARY KEY (id) +); + +ALTER TABLE IF EXISTS public.guild_characters + ADD COLUMN box_claimed timestamp with time zone DEFAULT now(); \ No newline at end of file diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 6af061b13..e39942671 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "encoding/hex" "erupe-ce/common/mhfcourse" + "erupe-ce/common/mhfmon" ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" _config "erupe-ce/config" @@ -305,9 +306,20 @@ func handleMsgSysIssueLogkey(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysRecordLog) + if _config.ErupeConfig.RealClientMode == _config.ZZ { + bf := byteframe.NewByteFrameFromBytes(pkt.Data) + bf.Seek(32, 0) + var val uint8 + for i := 0; i < 176; i++ { + val = bf.ReadUint8() + if val > 0 && mhfmon.Monsters[i].Large { + s.server.db.Exec(`INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, $2, $3, $4)`, s.charID, i, val, TimeAdjusted()) + } + } + } // remove a client returning to town from reserved slots to make sure the stage is hidden from board delete(s.stage.reservedClientSlots, s.charID) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgSysEcho(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 6ef507b84..a1b4eb397 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1867,15 +1867,51 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() switch pkt.Operation { case 0: // Acquire - // Probably mark everything as claimed + s.server.db.Exec(`UPDATE guild_characters SET box_claimed=$1 WHERE character_id=$2`, TimeAdjusted(), s.charID) case 1: // Enumerate bf.WriteUint8(0) // Entries - /* Entry format - uint32 UnkID - uint32 MonID - */ + rows, err := s.server.db.Query(`SELECT kl.id, kl.monster FROM kill_logs kl + INNER JOIN guild_characters gc ON kl.character_id = gc.character_id + WHERE gc.guild_id=$1 + AND kl.timestamp >= (SELECT box_claimed FROM guild_characters WHERE character_id=$2) + `, pkt.GuildID, s.charID) + if err == nil { + var count uint8 + var huntID, monID uint32 + for rows.Next() { + err = rows.Scan(&huntID, &monID) + if err != nil { + continue + } + count++ + if count > 255 { + count = 255 + rows.Close() + break + } + bf.WriteUint32(huntID) + bf.WriteUint32(monID) + } + bf.Seek(0, 0) + bf.WriteUint8(count) + } case 2: // Check - bf.WriteBool(false) + guild, err := GetGuildInfoByCharacterId(s, s.charID) + if err == nil { + var count uint8 + err = s.server.db.QueryRow(`SELECT COUNT(*) FROM kill_logs kl + INNER JOIN guild_characters gc ON kl.character_id = gc.character_id + WHERE gc.guild_id=$1 + AND kl.timestamp >= (SELECT box_claimed FROM guild_characters WHERE character_id=$2) + `, guild.ID, s.charID).Scan(&count) + if err == nil && count > 0 { + bf.WriteBool(true) + } else { + bf.WriteBool(false) + } + } else { + bf.WriteBool(false) + } } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 6f9969852560375cecaf1f76e3519a83f70f336a Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 8 Oct 2023 20:37:04 +1100 Subject: [PATCH 38/96] fix indentation --- server/channelserver/handlers_guild.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index a1b4eb397..b8c7c04f6 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1900,10 +1900,10 @@ func handleMsgMhfGuildHuntdata(s *Session, p mhfpacket.MHFPacket) { if err == nil { var count uint8 err = s.server.db.QueryRow(`SELECT COUNT(*) FROM kill_logs kl - INNER JOIN guild_characters gc ON kl.character_id = gc.character_id - WHERE gc.guild_id=$1 - AND kl.timestamp >= (SELECT box_claimed FROM guild_characters WHERE character_id=$2) - `, guild.ID, s.charID).Scan(&count) + INNER JOIN guild_characters gc ON kl.character_id = gc.character_id + WHERE gc.guild_id=$1 + AND kl.timestamp >= (SELECT box_claimed FROM guild_characters WHERE character_id=$2) + `, guild.ID, s.charID).Scan(&count) if err == nil && count > 0 { bf.WriteBool(true) } else { From dd26fc73c3a0f08e066141d54280bdfcf8e19294 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 12 Oct 2023 23:25:35 +1100 Subject: [PATCH 39/96] adjust GUrgentRate definition --- config.json | 2 +- config/config.go | 2 +- server/channelserver/handlers_quest.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index 5ed2ab9fd..bd943d43b 100644 --- a/config.json +++ b/config.json @@ -54,7 +54,7 @@ "BerserkRavienteMaxPlayers": 32, "ExtremeRavienteMaxPlayers": 32, "SmallBerserkRavienteMaxPlayers": 8, - "GUrgentRate": 10, + "GUrgentRate": 0.10, "GCPMultiplier": 1.00, "GRPMultiplier": 1.00, "GSRPMultiplier": 1.00, diff --git a/config/config.go b/config/config.go index b5afc6798..713b08a90 100644 --- a/config/config.go +++ b/config/config.go @@ -139,7 +139,7 @@ type GameplayOptions struct { BerserkRavienteMaxPlayers uint8 ExtremeRavienteMaxPlayers uint8 SmallBerserkRavienteMaxPlayers uint8 - GUrgentRate uint16 // Adjusts the rate of G Urgent quests spawning + GUrgentRate float32 // Adjusts the rate of G Urgent quests spawning GCPMultiplier float32 // Adjusts the multiplier of GCP rewarded for quest completion GRPMultiplier float32 // Adjusts the multiplier of G Rank Points rewarded for quest completion GSRPMultiplier float32 // Adjusts the multiplier of G Skill Rank Points rewarded for quest completion diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index d9ec2bc08..803509f45 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -565,7 +565,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { tuneValues = append(tuneValues, tuneValue{1020, uint16(s.server.erupeConfig.GameplayOptions.GCPMultiplier * 100)}) - tuneValues = append(tuneValues, tuneValue{1029, s.server.erupeConfig.GameplayOptions.GUrgentRate}) + tuneValues = append(tuneValues, tuneValue{1029, uint16(s.server.erupeConfig.GameplayOptions.GUrgentRate * 100)}) if s.server.erupeConfig.GameplayOptions.DisableHunterNavi { tuneValues = append(tuneValues, tuneValue{1037, 1}) From 0de15e84400f20b6ae5849336cd76337deeedcad Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 12 Oct 2023 23:26:12 +1100 Subject: [PATCH 40/96] rewrite ReadMercenaryW parser --- network/mhfpacket/msg_mhf_read_mercenary_w.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/network/mhfpacket/msg_mhf_read_mercenary_w.go b/network/mhfpacket/msg_mhf_read_mercenary_w.go index 3aa9597d9..d70ef4f38 100644 --- a/network/mhfpacket/msg_mhf_read_mercenary_w.go +++ b/network/mhfpacket/msg_mhf_read_mercenary_w.go @@ -13,7 +13,6 @@ type MsgMhfReadMercenaryW struct { AckHandle uint32 Op uint8 Unk1 uint8 - Unk2 uint16 // Hardcoded 0 in the binary } // Opcode returns the ID associated with this packet type. @@ -25,8 +24,9 @@ func (m *MsgMhfReadMercenaryW) Opcode() network.PacketID { func (m *MsgMhfReadMercenaryW) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Op = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() + m.Unk1 = bf.ReadUint8() // Supposed to be 0 or 1, but always 1 + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } From 94f9174afad22413b453e078c7ccee473c37e799 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 12 Oct 2023 23:27:54 +1100 Subject: [PATCH 41/96] change Airou struct definition & remove airoulist.bin --- .../channelserver/handlers_guild_tresure.go | 4 +- server/channelserver/handlers_mercenary.go | 52 +++++++------------ 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/server/channelserver/handlers_guild_tresure.go b/server/channelserver/handlers_guild_tresure.go index 3d0918a84..981d8d258 100644 --- a/server/channelserver/handlers_guild_tresure.go +++ b/server/channelserver/handlers_guild_tresure.go @@ -92,8 +92,8 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { if catID > 0 { catsUsed = stringsupport.CSVAdd(catsUsed, int(catID)) for _, cat := range guildCats { - if cat.CatID == catID { - huntData.WriteBytes(cat.CatName) + if cat.ID == catID { + huntData.WriteBytes(cat.Name) break } } diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index 810786751..25e4e3edc 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -9,8 +9,6 @@ import ( "erupe-ce/server/channelserver/compression/nullcomp" "go.uber.org/zap" "io" - "os" - "path/filepath" "time" ) @@ -299,18 +297,12 @@ func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateAiroulist) resp := byteframe.NewByteFrame() - if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin")); err == nil { - data, _ := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin")) - resp.WriteBytes(data) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - return - } airouList := getGuildAirouList(s) resp.WriteUint16(uint16(len(airouList))) resp.WriteUint16(uint16(len(airouList))) for _, cat := range airouList { - resp.WriteUint32(cat.CatID) - resp.WriteBytes(cat.CatName) + resp.WriteUint32(cat.ID) + resp.WriteBytes(cat.Name) resp.WriteUint32(cat.Experience) resp.WriteUint8(cat.Personality) resp.WriteUint8(cat.Class) @@ -321,11 +313,10 @@ func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) { doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } -// CatDefinition holds values needed to populate the guild cat list -type CatDefinition struct { - CatID uint32 - CatName []byte - CurrentTask uint8 +type Airou struct { + ID uint32 + Name []byte + Task uint8 Personality uint8 Class uint8 Experience uint32 @@ -333,10 +324,10 @@ type CatDefinition struct { WeaponID uint16 } -func getGuildAirouList(s *Session) []CatDefinition { +func getGuildAirouList(s *Session) []Airou { var guild *Guild var err error - var guildCats []CatDefinition + var guildCats []Airou // returning 0 cats on any guild issues // can probably optimise all of the guild queries pretty heavily @@ -365,7 +356,6 @@ func getGuildAirouList(s *Session) []CatDefinition { } } - // ellie's GetGuildMembers didn't seem to pull leader? rows, err = s.server.db.Query(`SELECT c.otomoairou FROM characters c INNER JOIN guild_characters gc @@ -381,11 +371,7 @@ func getGuildAirouList(s *Session) []CatDefinition { for rows.Next() { var data []byte err = rows.Scan(&data) - if err != nil { - s.logger.Warn("select failure", zap.Error(err)) - continue - } else if len(data) == 0 { - // non extant cats that aren't null in DB + if err != nil || len(data) == 0 { continue } // first byte has cat existence in general, can skip if 0 @@ -396,10 +382,10 @@ func getGuildAirouList(s *Session) []CatDefinition { continue } bf := byteframe.NewByteFrameFromBytes(decomp) - cats := GetCatDetails(bf) + cats := GetAirouDetails(bf) for _, cat := range cats { - _, exists := bannedCats[cat.CatID] - if cat.CurrentTask == 4 && !exists { + _, exists := bannedCats[cat.ID] + if cat.Task == 4 && !exists { guildCats = append(guildCats, cat) } } @@ -408,20 +394,20 @@ func getGuildAirouList(s *Session) []CatDefinition { return guildCats } -func GetCatDetails(bf *byteframe.ByteFrame) []CatDefinition { +func GetAirouDetails(bf *byteframe.ByteFrame) []Airou { catCount := bf.ReadUint8() - cats := make([]CatDefinition, catCount) + cats := make([]Airou, catCount) for x := 0; x < int(catCount); x++ { - var catDef CatDefinition + var catDef Airou // cat sometimes has additional bytes for whatever reason, gift items? timestamp? // until actual variance is known we can just seek to end based on start catDefLen := bf.ReadUint32() catStart, _ := bf.Seek(0, io.SeekCurrent) - catDef.CatID = bf.ReadUint32() - bf.Seek(1, io.SeekCurrent) // unknown value, probably a bool - catDef.CatName = bf.ReadBytes(18) // always 18 len, reads first null terminated string out of section and discards rest - catDef.CurrentTask = bf.ReadUint8() + catDef.ID = bf.ReadUint32() + bf.Seek(1, io.SeekCurrent) // unknown value, probably a bool + catDef.Name = bf.ReadBytes(18) // always 18 len, reads first null terminated string out of section and discards rest + catDef.Task = bf.ReadUint8() bf.Seek(16, io.SeekCurrent) // appearance data and what is seemingly null bytes catDef.Personality = bf.ReadUint8() catDef.Class = bf.ReadUint8() From 7194cdbc0740ffff3fde1a77b7fe4d1fad79d039 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 12 Oct 2023 23:54:35 +1100 Subject: [PATCH 42/96] optimise GuildTresure handlers --- config.json | 1 + config/config.go | 1 + .../channelserver/handlers_guild_tresure.go | 117 +++++++++--------- 3 files changed, 58 insertions(+), 61 deletions(-) diff --git a/config.json b/config.json index bd943d43b..31629b894 100644 --- a/config.json +++ b/config.json @@ -40,6 +40,7 @@ "MaximumNP": 100000, "MaximumRP": 50000, "MaximumFP": 120000, + "TreasureHuntExpiry": 604800, "DisableLoginBoost": false, "DisableBoostTime": false, "BoostTimeDuration": 120, diff --git a/config/config.go b/config/config.go index 713b08a90..25ac45313 100644 --- a/config/config.go +++ b/config/config.go @@ -125,6 +125,7 @@ type GameplayOptions struct { MaximumNP int // Maximum number of NP held by a player MaximumRP uint16 // Maximum number of RP held by a player MaximumFP uint32 // Maximum number of FP held by a player + TreasureHuntExpiry uint32 // Seconds until a Clan Treasure Hunt will expire DisableLoginBoost bool // Disables the Login Boost system DisableBoostTime bool // Disables the daily NetCafe Boost Time BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for diff --git a/server/channelserver/handlers_guild_tresure.go b/server/channelserver/handlers_guild_tresure.go index 981d8d258..b856293ab 100644 --- a/server/channelserver/handlers_guild_tresure.go +++ b/server/channelserver/handlers_guild_tresure.go @@ -22,54 +22,54 @@ type TreasureHunt struct { func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateGuildTresure) guild, err := GetGuildInfoByCharacterId(s, s.charID) - if err != nil { - panic(err) + if err != nil || guild == nil { + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + return + } + var hunts []TreasureHunt + var hunt TreasureHunt + rows, err := s.server.db.Queryx(`SELECT id, host_id, destination, level, return, acquired, claimed, hunters, treasure, hunt_data FROM guild_hunts WHERE guild_id=$1 AND $2 < return+$3 + `, guild.ID, TimeAdjusted().Unix(), s.server.erupeConfig.GameplayOptions.TreasureHuntExpiry) + if err != nil { + rows.Close() + return } - bf := byteframe.NewByteFrame() - hunts := 0 - rows, _ := s.server.db.Queryx("SELECT id, host_id, destination, level, return, acquired, claimed, hunters, treasure, hunt_data FROM guild_hunts WHERE guild_id=$1 AND $2 < return+604800", guild.ID, TimeAdjusted().Unix()) for rows.Next() { - hunt := &TreasureHunt{} err = rows.StructScan(&hunt) + if err != nil { + continue + } // Remove self from other hunter count hunt.Hunters = stringsupport.CSVRemove(hunt.Hunters, int(s.charID)) - if err != nil { - panic(err) - } if pkt.MaxHunts == 1 { if hunt.HostID != s.charID || hunt.Acquired { continue } - hunts++ - bf.WriteUint32(hunt.HuntID) - bf.WriteUint32(hunt.Destination) - bf.WriteUint32(hunt.Level) - bf.WriteUint32(uint32(stringsupport.CSVLength(hunt.Hunters))) - bf.WriteUint32(hunt.Return) - bf.WriteBool(false) - bf.WriteBool(false) - bf.WriteBytes(hunt.HuntData) + hunt.Claimed = false + hunt.Treasure = "" + hunts = append(hunts, hunt) break } else if pkt.MaxHunts == 30 && hunt.Acquired && hunt.Level == 2 { - if hunts == 30 { - break - } - hunts++ - bf.WriteUint32(hunt.HuntID) - bf.WriteUint32(hunt.Destination) - bf.WriteUint32(hunt.Level) - bf.WriteUint32(uint32(stringsupport.CSVLength(hunt.Hunters))) - bf.WriteUint32(hunt.Return) - bf.WriteBool(hunt.Claimed) - bf.WriteBool(stringsupport.CSVContains(hunt.Treasure, int(s.charID))) - bf.WriteBytes(hunt.HuntData) + hunts = append(hunts, hunt) } } - resp := byteframe.NewByteFrame() - resp.WriteUint16(uint16(hunts)) - resp.WriteUint16(uint16(hunts)) - resp.WriteBytes(bf.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + if len(hunts) > 30 { + hunts = hunts[:30] + } + bf := byteframe.NewByteFrame() + bf.WriteUint16(uint16(len(hunts))) + bf.WriteUint16(uint16(len(hunts))) + for _, h := range hunts { + bf.WriteUint32(h.HuntID) + bf.WriteUint32(h.Destination) + bf.WriteUint32(h.Level) + bf.WriteUint32(uint32(stringsupport.CSVLength(h.Hunters))) + bf.WriteUint32(h.Return) + bf.WriteBool(h.Claimed) + bf.WriteBool(stringsupport.CSVContains(h.Treasure, int(s.charID))) + bf.WriteBytes(h.HuntData) + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { @@ -77,8 +77,9 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrameFromBytes(pkt.Data) huntData := byteframe.NewByteFrame() guild, err := GetGuildInfoByCharacterId(s, s.charID) - if err != nil { - panic(err) + if err != nil || guild == nil { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return } guildCats := getGuildAirouList(s) destination := bf.ReadUint32() @@ -100,20 +101,14 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { huntData.WriteBytes(bf.ReadBytes(9)) } } - _, err = s.server.db.Exec("INSERT INTO guild_hunts (guild_id, host_id, destination, level, return, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6, $7)", - guild.ID, s.charID, destination, level, TimeAdjusted().Unix(), huntData.Data(), catsUsed) - if err != nil { - panic(err) - } + s.server.db.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, return, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6, $7) + `, guild.ID, s.charID, destination, level, TimeAdjusted().Unix(), huntData.Data(), catsUsed) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresure) - _, err := s.server.db.Exec("UPDATE guild_hunts SET acquired=true WHERE id=$1", pkt.HuntID) - if err != nil { - panic(err) - } + s.server.db.Exec("UPDATE guild_hunts SET acquired=true WHERE id=$1", pkt.HuntID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } @@ -126,6 +121,7 @@ func treasureHuntUnregister(s *Session) { var hunters string rows, err := s.server.db.Queryx("SELECT id, hunters FROM guild_hunts WHERE guild_id=$1", guild.ID) if err != nil { + rows.Close() return } for rows.Next() { @@ -138,41 +134,40 @@ func treasureHuntUnregister(s *Session) { func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfOperateGuildTresureReport) var csv string - if pkt.State == 0 { // Report registration + switch pkt.State { + case 0: // Report registration // Unregister from all other hunts treasureHuntUnregister(s) if pkt.HuntID != 0 { // Register to selected hunt err := s.server.db.QueryRow("SELECT hunters FROM guild_hunts WHERE id=$1", pkt.HuntID).Scan(&csv) if err != nil { - panic(err) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + return } csv = stringsupport.CSVAdd(csv, int(s.charID)) - _, err = s.server.db.Exec("UPDATE guild_hunts SET hunters=$1 WHERE id=$2", csv, pkt.HuntID) - if err != nil { - panic(err) - } + s.server.db.Exec("UPDATE guild_hunts SET hunters=$1 WHERE id=$2", csv, pkt.HuntID) } - } else if pkt.State == 1 { // Collected by hunter + case 1: // Collected by hunter s.server.db.Exec("UPDATE guild_hunts SET hunters='', claimed=true WHERE id=$1", pkt.HuntID) - } else if pkt.State == 2 { // Claim treasure + case 2: // Claim treasure err := s.server.db.QueryRow("SELECT treasure FROM guild_hunts WHERE id=$1", pkt.HuntID).Scan(&csv) if err != nil { - panic(err) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + return } csv = stringsupport.CSVAdd(csv, int(s.charID)) - _, err = s.server.db.Exec("UPDATE guild_hunts SET treasure=$1 WHERE id=$2", csv, pkt.HuntID) - if err != nil { - panic(err) - } + s.server.db.Exec("UPDATE guild_hunts SET treasure=$1 WHERE id=$2", csv, pkt.HuntID) } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildTresureSouvenir) - - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 6)) + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) + bf.WriteUint16(0) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfAcquireGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) { From bf44944884f2ad8b720121b8960d8627a913f0f2 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 14 Oct 2023 14:14:28 +1100 Subject: [PATCH 43/96] more GuildTresure optimisation --- patch-schema/09-fix-guild-treasure.sql | 8 ++++ server/channelserver/handlers.go | 2 +- .../channelserver/handlers_guild_tresure.go | 46 +++---------------- 3 files changed, 16 insertions(+), 40 deletions(-) create mode 100644 patch-schema/09-fix-guild-treasure.sql diff --git a/patch-schema/09-fix-guild-treasure.sql b/patch-schema/09-fix-guild-treasure.sql new file mode 100644 index 000000000..5abfe3271 --- /dev/null +++ b/patch-schema/09-fix-guild-treasure.sql @@ -0,0 +1,8 @@ +BEGIN; + +ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS hunters; + +ALTER TABLE IF EXISTS public.guild_characters + ADD COLUMN treasure_hunt integer; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index e39942671..211fcaf79 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -233,7 +233,7 @@ func logoutPlayer(s *Session) { s.server.db.Exec("UPDATE characters SET time_played = $1 WHERE id = $2", timePlayed, s.charID) - treasureHuntUnregister(s) + s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE character_id=$1`, s.charID) if s.stage == nil { return diff --git a/server/channelserver/handlers_guild_tresure.go b/server/channelserver/handlers_guild_tresure.go index b856293ab..e34e36d23 100644 --- a/server/channelserver/handlers_guild_tresure.go +++ b/server/channelserver/handlers_guild_tresure.go @@ -108,56 +108,24 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireGuildTresure) - s.server.db.Exec("UPDATE guild_hunts SET acquired=true WHERE id=$1", pkt.HuntID) + s.server.db.Exec(`UPDATE guild_hunts SET acquired=true WHERE id=$1`, pkt.HuntID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } -func treasureHuntUnregister(s *Session) { - guild, err := GetGuildInfoByCharacterId(s, s.charID) - if err != nil || guild == nil { - return - } - var huntID int - var hunters string - rows, err := s.server.db.Queryx("SELECT id, hunters FROM guild_hunts WHERE guild_id=$1", guild.ID) - if err != nil { - rows.Close() - return - } - for rows.Next() { - rows.Scan(&huntID, &hunters) - hunters = stringsupport.CSVRemove(hunters, int(s.charID)) - s.server.db.Exec("UPDATE guild_hunts SET hunters=$1 WHERE id=$2", hunters, huntID) - } -} - func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfOperateGuildTresureReport) var csv string switch pkt.State { case 0: // Report registration - // Unregister from all other hunts - treasureHuntUnregister(s) - if pkt.HuntID != 0 { - // Register to selected hunt - err := s.server.db.QueryRow("SELECT hunters FROM guild_hunts WHERE id=$1", pkt.HuntID).Scan(&csv) - if err != nil { - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) - return - } - csv = stringsupport.CSVAdd(csv, int(s.charID)) - s.server.db.Exec("UPDATE guild_hunts SET hunters=$1 WHERE id=$2", csv, pkt.HuntID) - } + s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=$1 WHERE character_id=$2`, pkt.HuntID, s.charID) case 1: // Collected by hunter - s.server.db.Exec("UPDATE guild_hunts SET hunters='', claimed=true WHERE id=$1", pkt.HuntID) + s.server.db.Exec(`UPDATE guild_hunts SET claimed=true WHERE id=$1;UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID) case 2: // Claim treasure - err := s.server.db.QueryRow("SELECT treasure FROM guild_hunts WHERE id=$1", pkt.HuntID).Scan(&csv) - if err != nil { - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) - return + err := s.server.db.QueryRow(`SELECT treasure FROM guild_hunts WHERE id=$1`, pkt.HuntID).Scan(&csv) + if err == nil { + csv = stringsupport.CSVAdd(csv, int(s.charID)) + s.server.db.Exec(`UPDATE guild_hunts SET treasure=$1 WHERE id=$2`, csv, pkt.HuntID) } - csv = stringsupport.CSVAdd(csv, int(s.charID)) - s.server.db.Exec("UPDATE guild_hunts SET treasure=$1 WHERE id=$2", csv, pkt.HuntID) } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } From e688fdf3c5ad49a16cab6fb05f9ec0d1b9e9a3c7 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 17 Oct 2023 00:35:06 +1100 Subject: [PATCH 44/96] more GuildTresure optimisation --- network/mhfpacket/msg_mhf_enumerate_guild_tresure.go | 8 ++++---- server/channelserver/handlers_guild_tresure.go | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/network/mhfpacket/msg_mhf_enumerate_guild_tresure.go b/network/mhfpacket/msg_mhf_enumerate_guild_tresure.go index 61475d655..f03202bd4 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild_tresure.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild_tresure.go @@ -12,7 +12,8 @@ import ( type MsgMhfEnumerateGuildTresure struct { AckHandle uint32 MaxHunts uint16 - Unk uint32 + Unk0 uint16 + Unk1 uint16 } // Opcode returns the ID associated with this packet type. @@ -24,9 +25,8 @@ func (m *MsgMhfEnumerateGuildTresure) Opcode() network.PacketID { func (m *MsgMhfEnumerateGuildTresure) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.MaxHunts = bf.ReadUint16() - // Changes with MaxHunts - // 0 if MaxHunts = 1, 1 if MaxHunts = 30 - m.Unk = bf.ReadUint32() + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint16() return nil } diff --git a/server/channelserver/handlers_guild_tresure.go b/server/channelserver/handlers_guild_tresure.go index e34e36d23..516991595 100644 --- a/server/channelserver/handlers_guild_tresure.go +++ b/server/channelserver/handlers_guild_tresure.go @@ -14,7 +14,7 @@ type TreasureHunt struct { Return uint32 `db:"return"` Acquired bool `db:"acquired"` Claimed bool `db:"claimed"` - Hunters string `db:"hunters"` + Hunters uint32 `db:"hunters"` Treasure string `db:"treasure"` HuntData []byte `db:"hunt_data"` } @@ -28,8 +28,10 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { } var hunts []TreasureHunt var hunt TreasureHunt - rows, err := s.server.db.Queryx(`SELECT id, host_id, destination, level, return, acquired, claimed, hunters, treasure, hunt_data FROM guild_hunts WHERE guild_id=$1 AND $2 < return+$3 - `, guild.ID, TimeAdjusted().Unix(), s.server.erupeConfig.GameplayOptions.TreasureHuntExpiry) + rows, err := s.server.db.Queryx(`SELECT gh.id, gh.host_id, gh.destination, gh.level, gh.return, gh.acquired, gh.claimed, gh.treasure, gh.hunt_data, + (SELECT COUNT(*) FROM guild_characters gc WHERE gc.treasure_hunt = gh.id AND gc.character_id <> $1) AS hunters + FROM guild_hunts gh WHERE gh.guild_id=$2 AND $3 < gh.return+$4 + `, s.charID, guild.ID, TimeAdjusted().Unix(), s.server.erupeConfig.GameplayOptions.TreasureHuntExpiry) if err != nil { rows.Close() return @@ -39,8 +41,6 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { if err != nil { continue } - // Remove self from other hunter count - hunt.Hunters = stringsupport.CSVRemove(hunt.Hunters, int(s.charID)) if pkt.MaxHunts == 1 { if hunt.HostID != s.charID || hunt.Acquired { continue @@ -63,7 +63,7 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(h.HuntID) bf.WriteUint32(h.Destination) bf.WriteUint32(h.Level) - bf.WriteUint32(uint32(stringsupport.CSVLength(h.Hunters))) + bf.WriteUint32(h.Hunters) bf.WriteUint32(h.Return) bf.WriteBool(h.Claimed) bf.WriteBool(stringsupport.CSVContains(h.Treasure, int(s.charID))) From c4e8cd59992f7e450afbfce77ff1c0705584f950 Mon Sep 17 00:00:00 2001 From: stratic-dev Date: Tue, 24 Oct 2023 01:48:20 +0100 Subject: [PATCH 45/96] Added paxes fix and missing fields to db --- patch-schema/03-event_quests.sql | 6 ++- server/channelserver/handlers_quest.go | 63 ++++++++++++-------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/patch-schema/03-event_quests.sql b/patch-schema/03-event_quests.sql index 94aac0c65..b54758ffe 100644 --- a/patch-schema/03-event_quests.sql +++ b/patch-schema/03-event_quests.sql @@ -3,10 +3,14 @@ BEGIN; create table if not exists event_quests ( id serial primary key, + index_value integer, max_players integer, quest_type integer not null, quest_id integer not null, - mark integer + mark integer, + quest_option integer not null, + + ); ALTER TABLE IF EXISTS public.servers DROP COLUMN IF EXISTS season; diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 803509f45..f0995170a 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -47,10 +47,6 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { ) } - if s.server.erupeConfig.GameplayOptions.SeasonOverride { - pkt.Filename = seasonConversion(s, pkt.Filename) - } - data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) @@ -62,28 +58,6 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { } } -func questSuffix(s *Session) string { - // Determine the letter to append for day / night - var timeSet string - if TimeGameAbsolute() > 2880 { - timeSet = "d" - } else { - timeSet = "n" - } - return fmt.Sprintf("%s%d", timeSet, s.server.Season()) -} - -func seasonConversion(s *Session, questFile string) string { - filename := fmt.Sprintf("%s%s", questFile[:5], questSuffix(s)) - - // Return original file if file doesn't exist - if _, err := os.Stat(filename); err == nil { - return filename - } else { - return questFile - } -} - func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest) var data []byte @@ -145,8 +119,9 @@ func loadQuestFile(s *Session, questId int) []byte { func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { var id, mark uint32 var questId int - var maxPlayers, questType uint8 - rows.Scan(&id, &maxPlayers, &questType, &questId, &mark) + var indexValue, maxPlayers, questType uint8 + var questOption uint16 + rows.Scan(&id, &indexValue, &maxPlayers, &questType, &questId, &mark, &questOption) data := loadQuestFile(s, questId) if data == nil { @@ -155,8 +130,8 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { bf := byteframe.NewByteFrame() bf.WriteUint32(id) - bf.WriteUint32(0) - bf.WriteUint8(0) // Indexer + bf.WriteUint32(0) //unk + bf.WriteUint8(indexValue) // Indexer switch questType { case 16: bf.WriteUint8(s.server.erupeConfig.GameplayOptions.RegularRavienteMaxPlayers) @@ -177,16 +152,36 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { } else { bf.WriteBool(true) } - bf.WriteUint16(0) + bf.WriteUint16(0) //unk counter id possibly? if _config.ErupeConfig.RealClientMode >= _config.G1 { bf.WriteUint32(mark) } - bf.WriteUint16(0) + bf.WriteUint16(0) //possible padding bf.WriteUint16(uint16(len(data))) bf.WriteBytes(data) - ps.Uint8(bf, "", true) // What is this string for? + //Season/RequiredObject Flag Replacement + bf.Seek(0x18, 0) + // Bitset Structure: bit 8 unk, bit 7 required objective,bit 6 unk,bit 5 night,bit 4 day,bit 3 cold,bit 2 warm,bit 1 breeding + // if the byte is set to 0 the game choses the quest file corresponding to whatever season the game is on + if s.server.erupeConfig.GameplayOptions.SeasonOverride { + bf.WriteUint16(0) + } else { + bf.WriteUint16(questOption) + } + + // Bitset Structure Quest Varient 1: bit 8 Hiden, bit 7 Fix HC,bit 6 HC to UL,bit 5 GRank,bit 4 Unk,bit 3 UNK,bit 2 UNK,bit 1 UNK + // Bitset Structure Quest Varient 2: bit 8 UNK, bit 7 No Halk Pots,bit 6 No halk/poogie,bit 5 Timer,bit 4 UNK,bit 3 Fixed Difficulty,bit 2 UNK,bit 1 UNK + // Bitset Structure Quest Varient 3: bit 8 Disable Reward Skill, bit 7 GSR to GR,bit 6 unk,bit 5 Musou?,bit 4 Zenith,bit 3 Inception,bit 2 UNK,bit 1 UNK + bf.Seek(0xAF, 0) + quest_variant_3 := bf.ReadUint8() + quest_variant_3 &= 0b11011111 //disables Inception flag at position 3 for any quests that dont have it set. + bf.Seek(0xAF, 0) + bf.WriteUint8(quest_variant_3) + + ps.Uint8(bf, "", true) // Debug/Notes string for quest return bf.Data(), nil + } func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { @@ -195,7 +190,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() bf.WriteUint16(0) - rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark FROM event_quests ORDER BY quest_id") + rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, index_value,quest_type, quest_id,quest_option, COALESCE(mark, 0) AS mark FROM event_quests ORDER BY quest_id") for rows.Next() { data, err := makeEventQuest(s, rows) if err != nil { From 2f8d09b09ee06dd0d03e39505ac4fd3329e0a2a9 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 24 Oct 2023 21:21:21 +1100 Subject: [PATCH 46/96] more GuildTresure optimisation --- config/config.go | 1 + main.go | 1 + patch-schema/09-fix-guild-treasure.sql | 18 +++ .../channelserver/handlers_guild_tresure.go | 105 ++++++++++-------- server/channelserver/handlers_mercenary.go | 46 ++++---- 5 files changed, 99 insertions(+), 72 deletions(-) diff --git a/config/config.go b/config/config.go index 25ac45313..65c663511 100644 --- a/config/config.go +++ b/config/config.go @@ -126,6 +126,7 @@ type GameplayOptions struct { MaximumRP uint16 // Maximum number of RP held by a player MaximumFP uint32 // Maximum number of FP held by a player TreasureHuntExpiry uint32 // Seconds until a Clan Treasure Hunt will expire + TreasureHuntPartnyaCooldown uint32 // Seconds until a Partnya can be assigned to another Clan Treasure Hunt DisableLoginBoost bool // Disables the Login Boost system DisableBoostTime bool // Disables the daily NetCafe Boost Time BoostTimeDuration int // The number of minutes NetCafe Boost Time lasts for diff --git a/main.go b/main.go index f549f4bc8..2a538b094 100644 --- a/main.go +++ b/main.go @@ -126,6 +126,7 @@ func main() { // Clear stale data _ = db.MustExec("DELETE FROM sign_sessions") _ = db.MustExec("DELETE FROM servers") + _ = db.MustExec(`UPDATE guild_characters SET treasure_hunt=NULL`) // Clean the DB if the option is on. if config.DevMode && config.DevModeOptions.CleanDB { diff --git a/patch-schema/09-fix-guild-treasure.sql b/patch-schema/09-fix-guild-treasure.sql index 5abfe3271..1c022292f 100644 --- a/patch-schema/09-fix-guild-treasure.sql +++ b/patch-schema/09-fix-guild-treasure.sql @@ -5,4 +5,22 @@ ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS hunters; ALTER TABLE IF EXISTS public.guild_characters ADD COLUMN treasure_hunt integer; +ALTER TABLE IF EXISTS public.guild_hunts + ADD COLUMN start timestamp with time zone NOT NULL DEFAULT now(); + +UPDATE guild_hunts SET start=to_timestamp(return); + +ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS "return"; + +ALTER TABLE IF EXISTS public.guild_hunts + RENAME claimed TO collected; + +CREATE TABLE public.guild_hunts_claimed +( + hunt_id integer NOT NULL, + character_id integer NOT NULL +); + +ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS treasure; + END; \ No newline at end of file diff --git a/server/channelserver/handlers_guild_tresure.go b/server/channelserver/handlers_guild_tresure.go index 516991595..f3f4815e6 100644 --- a/server/channelserver/handlers_guild_tresure.go +++ b/server/channelserver/handlers_guild_tresure.go @@ -4,19 +4,20 @@ import ( "erupe-ce/common/byteframe" "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" + "time" ) type TreasureHunt struct { - HuntID uint32 `db:"id"` - HostID uint32 `db:"host_id"` - Destination uint32 `db:"destination"` - Level uint32 `db:"level"` - Return uint32 `db:"return"` - Acquired bool `db:"acquired"` - Claimed bool `db:"claimed"` - Hunters uint32 `db:"hunters"` - Treasure string `db:"treasure"` - HuntData []byte `db:"hunt_data"` + HuntID uint32 `db:"id"` + HostID uint32 `db:"host_id"` + Destination uint32 `db:"destination"` + Level uint32 `db:"level"` + Start time.Time `db:"start"` + Acquired bool `db:"acquired"` + Collected bool `db:"collected"` + HuntData []byte `db:"hunt_data"` + Hunters uint32 `db:"hunters"` + Claimed bool `db:"claimed"` } func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { @@ -28,33 +29,39 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { } var hunts []TreasureHunt var hunt TreasureHunt - rows, err := s.server.db.Queryx(`SELECT gh.id, gh.host_id, gh.destination, gh.level, gh.return, gh.acquired, gh.claimed, gh.treasure, gh.hunt_data, - (SELECT COUNT(*) FROM guild_characters gc WHERE gc.treasure_hunt = gh.id AND gc.character_id <> $1) AS hunters - FROM guild_hunts gh WHERE gh.guild_id=$2 AND $3 < gh.return+$4 - `, s.charID, guild.ID, TimeAdjusted().Unix(), s.server.erupeConfig.GameplayOptions.TreasureHuntExpiry) - if err != nil { - rows.Close() - return - } - for rows.Next() { - err = rows.StructScan(&hunt) + + switch pkt.MaxHunts { + case 1: + err = s.server.db.QueryRowx(`SELECT id, host_id, destination, level, start, hunt_data FROM guild_hunts WHERE host_id=$1 AND acquired=FALSE`, s.charID).StructScan(&hunt) + if err == nil { + hunts = append(hunts, hunt) + } + case 30: + rows, err := s.server.db.Queryx(`SELECT gh.id, gh.host_id, gh.destination, gh.level, gh.start, gh.collected, gh.hunt_data, + (SELECT COUNT(*) FROM guild_characters gc WHERE gc.treasure_hunt = gh.id AND gc.character_id <> $1) AS hunters, + CASE + WHEN ghc.character_id IS NOT NULL THEN true + ELSE false + END AS claimed + FROM guild_hunts gh + LEFT JOIN guild_hunts_claimed ghc ON gh.id = ghc.hunt_id AND ghc.character_id = $1 + WHERE gh.guild_id=$2 AND gh.level=2 AND gh.acquired=TRUE + `, s.charID, guild.ID) if err != nil { - continue - } - if pkt.MaxHunts == 1 { - if hunt.HostID != s.charID || hunt.Acquired { - continue + rows.Close() + doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + return + } else { + for rows.Next() { + err = rows.StructScan(&hunt) + if err == nil && hunt.Start.Add(time.Second*time.Duration(s.server.erupeConfig.GameplayOptions.TreasureHuntExpiry)).After(TimeAdjusted()) { + hunts = append(hunts, hunt) + } } - hunt.Claimed = false - hunt.Treasure = "" - hunts = append(hunts, hunt) - break - } else if pkt.MaxHunts == 30 && hunt.Acquired && hunt.Level == 2 { - hunts = append(hunts, hunt) } - } - if len(hunts) > 30 { - hunts = hunts[:30] + if len(hunts) > 30 { + hunts = hunts[:30] + } } bf := byteframe.NewByteFrame() bf.WriteUint16(uint16(len(hunts))) @@ -64,9 +71,9 @@ func handleMsgMhfEnumerateGuildTresure(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(h.Destination) bf.WriteUint32(h.Level) bf.WriteUint32(h.Hunters) - bf.WriteUint32(h.Return) + bf.WriteUint32(uint32(h.Start.Unix())) + bf.WriteBool(h.Collected) bf.WriteBool(h.Claimed) - bf.WriteBool(stringsupport.CSVContains(h.Treasure, int(s.charID))) bf.WriteBytes(h.HuntData) } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) @@ -101,8 +108,8 @@ func handleMsgMhfRegistGuildTresure(s *Session, p mhfpacket.MHFPacket) { huntData.WriteBytes(bf.ReadBytes(9)) } } - s.server.db.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, return, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6, $7) - `, guild.ID, s.charID, destination, level, TimeAdjusted().Unix(), huntData.Data(), catsUsed) + s.server.db.Exec(`INSERT INTO guild_hunts (guild_id, host_id, destination, level, hunt_data, cats_used) VALUES ($1, $2, $3, $4, $5, $6) + `, guild.ID, s.charID, destination, level, huntData.Data(), catsUsed) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } @@ -114,27 +121,33 @@ func handleMsgMhfAcquireGuildTresure(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfOperateGuildTresureReport(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfOperateGuildTresureReport) - var csv string switch pkt.State { case 0: // Report registration s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=$1 WHERE character_id=$2`, pkt.HuntID, s.charID) case 1: // Collected by hunter - s.server.db.Exec(`UPDATE guild_hunts SET claimed=true WHERE id=$1;UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID) + s.server.db.Exec(`UPDATE guild_hunts SET collected=true WHERE id=$1`, pkt.HuntID) + s.server.db.Exec(`UPDATE guild_characters SET treasure_hunt=NULL WHERE treasure_hunt=$1`, pkt.HuntID) case 2: // Claim treasure - err := s.server.db.QueryRow(`SELECT treasure FROM guild_hunts WHERE id=$1`, pkt.HuntID).Scan(&csv) - if err == nil { - csv = stringsupport.CSVAdd(csv, int(s.charID)) - s.server.db.Exec(`UPDATE guild_hunts SET treasure=$1 WHERE id=$2`, csv, pkt.HuntID) - } + s.server.db.Exec(`INSERT INTO guild_hunts_claimed VALUES ($1, $2)`, pkt.HuntID, s.charID) } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } +type TreasureSouvenir struct { + Destination uint32 + Quantity uint32 +} + func handleMsgMhfGetGuildTresureSouvenir(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetGuildTresureSouvenir) bf := byteframe.NewByteFrame() bf.WriteUint32(0) - bf.WriteUint16(0) + souvenirs := []TreasureSouvenir{} + bf.WriteUint16(uint16(len(souvenirs))) + for _, souvenir := range souvenirs { + bf.WriteUint32(souvenir.Destination) + bf.WriteUint32(souvenir.Quantity) + } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index 25e4e3edc..19c358c52 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -325,44 +325,38 @@ type Airou struct { } func getGuildAirouList(s *Session) []Airou { - var guild *Guild - var err error var guildCats []Airou - - // returning 0 cats on any guild issues - // can probably optimise all of the guild queries pretty heavily - guild, err = GetGuildInfoByCharacterId(s, s.charID) + bannedCats := make(map[uint32]int) + guild, err := GetGuildInfoByCharacterId(s, s.charID) if err != nil { return guildCats } - - // Get cats used recently - // Retail reset at midday, 12 hours is a midpoint - tempBanDuration := 43200 - (1800) // Minus hunt time - bannedCats := make(map[uint32]int) - var csvTemp string - rows, err := s.server.db.Query(`SELECT cats_used - FROM guild_hunts gh - INNER JOIN characters c - ON gh.host_id = c.id - WHERE c.id=$1 AND gh.return+$2>$3`, s.charID, tempBanDuration, TimeAdjusted().Unix()) + rows, err := s.server.db.Query(`SELECT cats_used FROM guild_hunts gh + INNER JOIN characters c ON gh.host_id = c.id WHERE c.id=$1 + `, s.charID) if err != nil { s.logger.Warn("Failed to get recently used airous", zap.Error(err)) + return guildCats } + + var csvTemp string + var startTemp time.Time for rows.Next() { - rows.Scan(&csvTemp) - for i, j := range stringsupport.CSVElems(csvTemp) { - bannedCats[uint32(j)] = i + err = rows.Scan(&csvTemp, &startTemp) + if err != nil { + continue + } + if startTemp.Add(time.Second * time.Duration(s.server.erupeConfig.GameplayOptions.TreasureHuntPartnyaCooldown)).Before(TimeAdjusted()) { + for i, j := range stringsupport.CSVElems(csvTemp) { + bannedCats[uint32(j)] = i + } } } - rows, err = s.server.db.Query(`SELECT c.otomoairou - FROM characters c - INNER JOIN guild_characters gc - ON gc.character_id = c.id + rows, err = s.server.db.Query(`SELECT c.otomoairou FROM characters c + INNER JOIN guild_characters gc ON gc.character_id = c.id WHERE gc.guild_id = $1 AND c.otomoairou IS NOT NULL - ORDER BY c.id ASC - LIMIT 60;`, guild.ID) + ORDER BY c.id LIMIT 60`, guild.ID) if err != nil { s.logger.Warn("Selecting otomoairou based on guild failed", zap.Error(err)) return guildCats From ba50dc419ad68a7f2b00892402c2e4199aed00af Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 24 Oct 2023 21:24:35 +1100 Subject: [PATCH 47/96] fix parsing and handling of DistItem packets --- network/mhfpacket/msg_mhf_apply_dist_item.go | 20 ++++++-------- .../mhfpacket/msg_mhf_enumerate_dist_item.go | 15 +++++------ server/channelserver/handlers_distitem.go | 26 ++++++++++++++++--- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/network/mhfpacket/msg_mhf_apply_dist_item.go b/network/mhfpacket/msg_mhf_apply_dist_item.go index 456d8fb12..f98dbb19a 100644 --- a/network/mhfpacket/msg_mhf_apply_dist_item.go +++ b/network/mhfpacket/msg_mhf_apply_dist_item.go @@ -1,18 +1,19 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfApplyDistItem represents the MSG_MHF_APPLY_DIST_ITEM type MsgMhfApplyDistItem struct { - AckHandle uint32 + AckHandle uint32 DistributionType uint8 - DistributionID uint32 - Unk2 uint32 - Unk3 uint32 + DistributionID uint32 + Unk2 uint32 + Unk3 uint32 } // Opcode returns the ID associated with this packet type. @@ -32,10 +33,5 @@ func (m *MsgMhfApplyDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clie // Build builds a binary packet from the current data. func (m *MsgMhfApplyDistItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint8(m.DistributionType) - bf.WriteUint32(m.DistributionID) - bf.WriteUint32(m.Unk2) - bf.WriteUint32(m.Unk3) - return nil -} \ No newline at end of file + return errors.New("NOT IMPLEMENTED") +} diff --git a/network/mhfpacket/msg_mhf_enumerate_dist_item.go b/network/mhfpacket/msg_mhf_enumerate_dist_item.go index 778a91ac6..6d0082ec8 100644 --- a/network/mhfpacket/msg_mhf_enumerate_dist_item.go +++ b/network/mhfpacket/msg_mhf_enumerate_dist_item.go @@ -1,17 +1,19 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfEnumerateDistItem represents the MSG_MHF_ENUMERATE_DIST_ITEM type MsgMhfEnumerateDistItem struct { AckHandle uint32 Unk0 uint8 - Unk1 uint16 + Unk1 uint8 Unk2 uint16 + Unk3 []byte } // Opcode returns the ID associated with this packet type. @@ -23,16 +25,13 @@ func (m *MsgMhfEnumerateDistItem) Opcode() network.PacketID { func (m *MsgMhfEnumerateDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint16() + m.Unk1 = bf.ReadUint8() m.Unk2 = bf.ReadUint16() + m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8())) return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateDistItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint8(m.Unk0) - bf.WriteUint16(m.Unk1) - bf.WriteUint16(m.Unk2) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/server/channelserver/handlers_distitem.go b/server/channelserver/handlers_distitem.go index a2979756f..2bde7c60a 100644 --- a/server/channelserver/handlers_distitem.go +++ b/server/channelserver/handlers_distitem.go @@ -67,10 +67,28 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(distData.MaxSR) bf.WriteUint16(distData.MinGR) bf.WriteUint16(distData.MaxGR) - bf.WriteUint32(0) // Unk - bf.WriteUint32(0) // Unk - ps.Uint16(bf, distData.EventName, true) - bf.WriteBytes(make([]byte, 391)) + bf.WriteUint8(0) + bf.WriteUint16(0) + bf.WriteUint8(0) + bf.WriteUint16(0) + bf.WriteUint16(0) + bf.WriteUint8(0) + ps.Uint8(bf, distData.EventName, true) + for i := 0; i < 6; i++ { + for j := 0; j < 13; j++ { + bf.WriteUint8(0) + bf.WriteUint32(0) + } + } + i := uint8(0) + bf.WriteUint8(i) + if i <= 10 { + for j := uint8(0); j < i; j++ { + bf.WriteUint32(0) + bf.WriteUint32(0) + bf.WriteUint32(0) + } + } } resp := byteframe.NewByteFrame() resp.WriteUint16(uint16(distCount)) From 64cb106c70f877545e7b519fbf9e85861c768ae5 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 24 Oct 2023 22:18:09 +1100 Subject: [PATCH 48/96] formatting, strip out unknown values --- patch-schema/03-event_quests.sql | 6 +--- server/channelserver/handlers_quest.go | 47 +++++++++++++------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/patch-schema/03-event_quests.sql b/patch-schema/03-event_quests.sql index b54758ffe..94aac0c65 100644 --- a/patch-schema/03-event_quests.sql +++ b/patch-schema/03-event_quests.sql @@ -3,14 +3,10 @@ BEGIN; create table if not exists event_quests ( id serial primary key, - index_value integer, max_players integer, quest_type integer not null, quest_id integer not null, - mark integer, - quest_option integer not null, - - + mark integer ); ALTER TABLE IF EXISTS public.servers DROP COLUMN IF EXISTS season; diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index f0995170a..aab84b960 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -119,9 +119,8 @@ func loadQuestFile(s *Session, questId int) []byte { func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { var id, mark uint32 var questId int - var indexValue, maxPlayers, questType uint8 - var questOption uint16 - rows.Scan(&id, &indexValue, &maxPlayers, &questType, &questId, &mark, &questOption) + var maxPlayers, questType uint8 + rows.Scan(&id, &maxPlayers, &questType, &questId, &mark) data := loadQuestFile(s, questId) if data == nil { @@ -130,8 +129,8 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { bf := byteframe.NewByteFrame() bf.WriteUint32(id) - bf.WriteUint32(0) //unk - bf.WriteUint8(indexValue) // Indexer + bf.WriteUint32(0) // Unk + bf.WriteUint8(0) // Unk switch questType { case 16: bf.WriteUint8(s.server.erupeConfig.GameplayOptions.RegularRavienteMaxPlayers) @@ -152,36 +151,38 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { } else { bf.WriteBool(true) } - bf.WriteUint16(0) //unk counter id possibly? + bf.WriteUint16(0) // Unk if _config.ErupeConfig.RealClientMode >= _config.G1 { bf.WriteUint32(mark) } - bf.WriteUint16(0) //possible padding + bf.WriteUint16(0) // Unk bf.WriteUint16(uint16(len(data))) bf.WriteBytes(data) - //Season/RequiredObject Flag Replacement - bf.Seek(0x18, 0) - // Bitset Structure: bit 8 unk, bit 7 required objective,bit 6 unk,bit 5 night,bit 4 day,bit 3 cold,bit 2 warm,bit 1 breeding + + // Time Flag Replacement + // Bitset Structure: b8 UNK, b7 Required Objective, b6 UNK, b5 Night, b4 Day, b3 Cold, b2 Warm, b1 Spring // if the byte is set to 0 the game choses the quest file corresponding to whatever season the game is on + bf.Seek(25, 0) + flagByte := bf.ReadUint8() + bf.Seek(25, 0) if s.server.erupeConfig.GameplayOptions.SeasonOverride { - bf.WriteUint16(0) + bf.WriteUint8(flagByte & 0b11100000) } else { - bf.WriteUint16(questOption) + bf.WriteUint8(flagByte) } - // Bitset Structure Quest Varient 1: bit 8 Hiden, bit 7 Fix HC,bit 6 HC to UL,bit 5 GRank,bit 4 Unk,bit 3 UNK,bit 2 UNK,bit 1 UNK - // Bitset Structure Quest Varient 2: bit 8 UNK, bit 7 No Halk Pots,bit 6 No halk/poogie,bit 5 Timer,bit 4 UNK,bit 3 Fixed Difficulty,bit 2 UNK,bit 1 UNK - // Bitset Structure Quest Varient 3: bit 8 Disable Reward Skill, bit 7 GSR to GR,bit 6 unk,bit 5 Musou?,bit 4 Zenith,bit 3 Inception,bit 2 UNK,bit 1 UNK - bf.Seek(0xAF, 0) - quest_variant_3 := bf.ReadUint8() - quest_variant_3 &= 0b11011111 //disables Inception flag at position 3 for any quests that dont have it set. - bf.Seek(0xAF, 0) - bf.WriteUint8(quest_variant_3) + // Bitset Structure Quest Variant 1: b8 UL Fixed, b7 UNK, b6 UNK, b5 UNK, b4 G Rank, b3 HC to UL, b2 Fix HC, b1 Hiden + // Bitset Structure Quest Variant 2: b8 Road, b7 High Conquest, b6 Fixed Difficulty, b5 No Active Feature, b4 Timer, b3 No Cuff, b2 No Halk Pots, b1 Low Conquest + // Bitset Structure Quest Variant 3: b8 No Sigils, b7 UNK, b6 Interception, b5 Zenith, b4 No GP Skills, b3 No Simple Mode?, b2 GSR to GR, b1 No Reward Skills + + bf.Seek(175, 0) + questVariant3 := bf.ReadUint8() + questVariant3 &= 0b11011111 // disable Interception flag + bf.Seek(175, 0) + bf.WriteUint8(questVariant3) ps.Uint8(bf, "", true) // Debug/Notes string for quest - return bf.Data(), nil - } func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { @@ -190,7 +191,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() bf.WriteUint16(0) - rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, index_value,quest_type, quest_id,quest_option, COALESCE(mark, 0) AS mark FROM event_quests ORDER BY quest_id") + rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark FROM event_quests ORDER BY quest_id") for rows.Next() { data, err := makeEventQuest(s, rows) if err != nil { From 13375fa8e99887e86ea46b6edb860a2a301d10f2 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 24 Oct 2023 23:03:08 +1100 Subject: [PATCH 49/96] fix quest enumeration --- server/channelserver/handlers_quest.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index aab84b960..da3c8166a 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -181,6 +181,7 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { bf.Seek(175, 0) bf.WriteUint8(questVariant3) + bf.Seek(0, 2) ps.Uint8(bf, "", true) // Debug/Notes string for quest return bf.Data(), nil } From 58b401d978885fffcc63ab541447f5067d19730e Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 26 Oct 2023 22:29:42 +1100 Subject: [PATCH 50/96] Update README.md --- README.md | 109 +----------------------------------------------------- 1 file changed, 1 insertion(+), 108 deletions(-) diff --git a/README.md b/README.md index 8f17c33ce..8cf946d0a 100644 --- a/README.md +++ b/README.md @@ -36,115 +36,8 @@ If you want to modify or compile Erupe yourself, please read on. - [Quest and Scenario Binary Files](https://files.catbox.moe/xf0l7w.7z) - [Mezeporta Square Discord](https://discord.gg/DnwcpXM488) - -## Configuration -This portion of the documentation goes over the `config.json` file. - -### General Configuration - -| Variable | Description | Default | Options | -|------------------------|-----------------------------------------------------------------------------------------------------------------------|-----------|---------------------------------| -| Host | The IP or host address the server is running from | 127.0.0.1 | | -| BinPath | The bin path folder is where you place files needed for various parts of the game such as scenario and quest files | bin | | -| Language | This is the language the server will run in. Only English `en` and Japanese `jp` are available, contributions welcome | en | en/jp | -| DisableSoftCrash | | false | | -| HideLoginNotice | This hides the notices that appear on login from `LoginNotices` | true | | -| LoginNotices | This is where you place notices for users, you can have multiple notices | | | -| PatchServerManifest | | | | -| PatchServerFile | | | | -| ScreenshotAPIURL | This is the URL you want user sreenshots to go to | | | -| DeleteOnSaveCorruption | This option flags a character as deleted if they corrupt it, can be used as punishment for cheaters | false | | -| ClientMode | This tells the server what client version it should target | ZZ | Check compatible versions above | -| DevMode | This enables DevModeOptions to be configured | true | | - -### `DevModeOptions` Configuraiton - -| Variable | Description | Default | Options | -|----------------------|---------------------------------------------------------------------------------------------|--------------|----------------------------------| -| AutoCreateAccount | This allows users that don't exist to auto create their account from initial login | true | | -| CleanDB | This cleans the database down | false | | -| MaxLauncherHR | This sets the launcher value to HR7 to allow you to break World HR requirements | false | | -| LogInboundMessages | This will allow inbound messages to be logged to stdout | false | | -| LogOutboundMessages | This will allow outbound messages to be logged to stdout | false | | -| MaxHexdumpLength | This is the maximum amount of hex bytes that will be dumped to stdout | 0 | | -| DivaEvent | This overrides the Diva event stage in game | 0 | 0/1/2/3/-1 | -| FestaEvent | This overrides the Hunter Festival event stage in game | -1 | 0/1/2/3/-1 | -| TournamentEvent | This overrides the Hunter Tournament event stage in game | 0 | 0/1/2/3/-1 | -| MezFesEvent | Enables whether the MezFes event & World are active | true | | -| MezFesAlt | Switches the multiplayer MezFes minigame | false | | -| DisableTokenCheck | This disables the random token that is generated at login from being checked, very insecure | false | | -| QuestDebugTools | Enable various quest debug logs | false | | -| EarthStatusOverride | Enables Pallone Fest, Tower and Conquest War events | 0 | 2=Conquest, 11=Pallone, 21=Tower | -| EarthIDOverride | A random event ID | 0 | | -| EarthMonsterOverride | Sets the ID of the monster targeted in the Conquest War | 0 | | -| SaveDumps.Enables | Enables save dumps to a folder that is set at `SaveDumps.OutputDir` | true | | -| SaveDumps.OutputDir | The folder that save dumps are saved to | save-backups | | - -### `GameplayOptions` Configuraiton - -| Variable | Description | Default | Options | -|----------------------|-----------------------------------------------------------------------------|---------|---------| -| FeaturedWeapons | Number of Active Feature weapons to generate daily | 0 | | -| MaximumNP | Maximum number of NP held by a player | 100000 | | -| MaximumRP | Maximum number of RP held by a player | 100000 | | -| DisableLoginBoost | Disables the Login Boost system | false | | -| DisableBoostTime | Disables the daily NetCafe Boost Time | false | | -| BoostTimeDuration | The number of minutes NetCafe Boost Time lasts for | 120 | | -| GuildMealDuration | The number of minutes a Guild Meal can be activated for after cooking | 60 | | -| BonusQuestAllowance | Number of Bonus Point Quests to allow daily | 3 | | -| DailyQuestAllowance | Number of Daily Quests to allow daily | 1 | | -| MezfesSoloTickets | Number of solo tickets given weekly | 10 | | -| MezfesGroupTickets | Number of group tickets given weekly | 4 | | -| GUrgentRate | Adjusts the rate of G Urgent quests spawning | 10 | | -| GCPMultiplier | Adjusts the multiplier of GCP rewarded for quest completion | 1.00 | | -| GRPMultiplier | Adjusts the multiplier of G Rank Points rewarded for quest completion | 1.00 | | -| GSRPMultiplier | Adjusts the multiplier of G Skill Rank Points rewarded for quest completion | 1.00 | | -| GZennyMultiplier | Adjusts the multiplier of G Zenny rewarded for quest completion | 1.00 | | -| MaterialMultiplier | Adjusts the multiplier of Monster Materials rewarded for quest completion | 1.00 | | -| ExtraCarves | Grant n extra chances to carve ALL carcasses | 0 | | -| DisableHunterNavi | Disables the Hunter Navi | false | | -| EnableHiganjimaEvent | Enables the Higanjima event in the Rasta Bar | false | | -| EnableNierEvent | Enables the Nier event in the Rasta Bar | false | | -| DisableRoad | Disables the Hunting Road | false | | - -### Discord -There is limited Discord capability in Erupe. The feature allows you to replay messages from your server into a channel. -This may be either be removed or revamped in a future version. - -### Commands -There are several chat commands that can be turned on and off. Most of them are really for admins or debugging purposes. - -| Name | command | Description | Default | Options | -|----------|----------------|--------------------------------------------|----------|---------------------| -| Rights | !rights VALUE | Sets the rights integer for your account | disabled | | -| Teleport | !tele X,Y | Teleports user to specific x,y coordinate | disabled | | -| Reload | !reload | Reloads all users and character objects | enabled | | -| KeyQuest | !kqf FLAGS | Sets the Key Quest Flag for your character | disabled | | -| Course | !course OPTION | Enables/Disables a course for your account | enabled | HL,EX,Premium,Boost | -| PSN | !psn USERNAME | Links the specified PSN to your account | enabled | | - -### Ravi Sub Commands -| Name | command | Description | -|----------|----------------------------------|-------------------------------| -| Raviente | !ravi start | Starts Ravi Event | -| Raviente | !ravi cm / !ravi checkmultiplier | Checks Ravi Damage Multiplier | -| Raviente | !ravi ss | Send Sedation Support | -| Raviente | !ravi sr | Send Resurrection Support | -| Raviente | !ravi rs | Request Sedation Support | - - -## World `Entries` config - -| Config Item | Description | Options | -|-------------|---------------|------------------------------------------------------------| -| Type | Server type | 1=Normal, 2=Cities, 3=Newbie, 4=Tavern, 5=Return, 6=MezFes | -| Season | Server season | 0=Green/Breeding, 1=Orange/Warm, 2=Blue/Cold | - -### `Recommend` -This sets the types of Quests that can be ordered from a World. -* 0 = All quests * 1 = Up to 2 star Quests * 2 = Up to 4 star Quests * 4 = All Quests in HR (Enables G Experience Tab) * 5 = Only G Rank Quests -* 6 = Minigame World \ No newline at end of file +* 6 = Minigame World From 3edc77d3b568a95fe38b81276b51ae97f20e96cb Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 26 Oct 2023 22:30:04 +1100 Subject: [PATCH 51/96] Update README.md --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 8cf946d0a..a494b25da 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,3 @@ If you want to modify or compile Erupe yourself, please read on. - [Quest and Scenario Binary Files](https://files.catbox.moe/xf0l7w.7z) - [Mezeporta Square Discord](https://discord.gg/DnwcpXM488) -* 1 = Up to 2 star Quests -* 2 = Up to 4 star Quests -* 4 = All Quests in HR (Enables G Experience Tab) -* 5 = Only G Rank Quests -* 6 = Minigame World From 0b75a426822131346f7095deb130b4e2992f9aa5 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 26 Oct 2023 22:31:00 +1100 Subject: [PATCH 52/96] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a494b25da..034e2a4ea 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ - PlayStation Vita - Wii U (Up to Z2) ### Versions (ClientMode) -All versions after HR compression (G10-ZZ) have been tested extensively and have great functionality. -All versions available on Wii U (G3-Z2) have been tested and should have good functionality. -The second oldest found version is Forward.4 (FW.4), this version has basic functionality. -The oldest found version is Season 6.0 (S6.0), however functionality is very limited. +- All versions after HR compression (G10-ZZ) have been tested extensively and have great functionality. +- All versions available on Wii U (G3-Z2) have been tested and should have good functionality. +- The second oldest found version is Forward.4 (FW.4), this version has basic functionality. +- The oldest found version is Season 6.0 (S6.0), however functionality is very limited. If you have an **installed** copy of Monster Hunter Frontier on an old hard drive, **please** get in contact so we can archive it! From 8abefd74411ef602633c100db64d0ec7be781ae4 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 28 Oct 2023 11:53:53 +1100 Subject: [PATCH 53/96] fix null LoadScenarioData response --- server/channelserver/handlers_data.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 81102b42d..74f6de9d0 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -302,7 +302,7 @@ func handleMsgMhfLoadScenarioData(s *Session, p mhfpacket.MHFPacket) { var scenarioData []byte bf := byteframe.NewByteFrame() err := s.server.db.QueryRow("SELECT scenariodata FROM characters WHERE id = $1", s.charID).Scan(&scenarioData) - if err != nil { + if err != nil || len(scenarioData) < 10 { s.logger.Error("Failed to load scenariodata", zap.Error(err)) bf.WriteBytes(make([]byte, 10)) } else { From e75a77e6b8a62473d9bb4f7a197dcd57d6f46970 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 28 Oct 2023 11:55:06 +1100 Subject: [PATCH 54/96] optimise grpToGR --- server/channelserver/handlers_character.go | 2 +- server/channelserver/handlers_data.go | 179 ++++----------------- 2 files changed, 29 insertions(+), 152 deletions(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 4c5802293..cf17693d7 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -226,7 +226,7 @@ func (save *CharacterSaveData) updateStructWithSaveData() { if _config.ErupeConfig.RealClientMode >= _config.G10 { save.KQF = save.decompSave[save.Pointers[pKQF] : save.Pointers[pKQF]+8] if save.HRP == uint16(999) { - save.GR = grpToGR(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4])) + save.GR = grpToGR(int(binary.LittleEndian.Uint32(save.decompSave[save.Pointers[pGRP] : save.Pointers[pGRP]+4]))) } } } diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 74f6de9d0..5de1c4f65 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -73,162 +73,39 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } -func grpToGR(n uint32) uint16 { - var gr uint16 - gr = 1 - switch grp := int(n); { - case grp < 208750: // Up to 50 - i := 0 - for { - grp -= 500 - if grp <= 500 { - if grp < 0 { - i-- +func grpToGR(n int) uint16 { + var gr int + a := []int{208750, 593400, 993400, 1400900, 2315900, 3340900, 4505900, 5850900, 7415900, 9230900, 11345900, 100000000} + b := []int{7850, 8000, 8150, 9150, 10250, 11650, 13450, 15650, 18150, 21150, 23950} + c := []int{51, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900} + + for i := 0; i < len(a); i++ { + if n < a[i] { + if i == 0 { + for { + n -= 500 + if n <= 500 { + if n < 0 { + i-- + } + break + } else { + i++ + for j := 0; j < i; j++ { + n -= 150 + } + } } - break + gr = i + 2 } else { - i++ - for j := 0; j < i; j++ { - grp -= 150 - } + n -= a[i-1] + gr = c[i-1] + gr += n / b[i-1] } + break } - gr = uint16(i + 2) - break - case grp < 593400: // 51-99 - grp -= 208750 - i := 51 - for { - if grp < 7850 { - break - } - i++ - grp -= 7850 - } - gr = uint16(i) - break - case grp < 993400: // 100-149 - grp -= 593400 - i := 100 - for { - if grp < 8000 { - break - } - i++ - grp -= 8000 - } - gr = uint16(i) - break - case grp < 1400900: // 150-199 - grp -= 993400 - i := 150 - for { - if grp < 8150 { - break - } - i++ - grp -= 8150 - } - gr = uint16(i) - break - case grp < 2315900: // 200-299 - grp -= 1400900 - i := 200 - for { - if grp < 9150 { - break - } - i++ - grp -= 9150 - } - gr = uint16(i) - break - case grp < 3340900: // 300-399 - grp -= 2315900 - i := 300 - for { - if grp < 10250 { - break - } - i++ - grp -= 10250 - } - gr = uint16(i) - break - case grp < 4505900: // 400-499 - grp -= 3340900 - i := 400 - for { - if grp < 11650 { - break - } - i++ - grp -= 11650 - } - gr = uint16(i) - break - case grp < 5850900: // 500-599 - grp -= 4505900 - i := 500 - for { - if grp < 13450 { - break - } - i++ - grp -= 13450 - } - gr = uint16(i) - break - case grp < 7415900: // 600-699 - grp -= 5850900 - i := 600 - for { - if grp < 15650 { - break - } - i++ - grp -= 15650 - } - gr = uint16(i) - break - case grp < 9230900: // 700-799 - grp -= 7415900 - i := 700 - for { - if grp < 18150 { - break - } - i++ - grp -= 18150 - } - gr = uint16(i) - break - case grp < 11345900: // 800-899 - grp -= 9230900 - i := 800 - for { - if grp < 21150 { - break - } - i++ - grp -= 21150 - } - gr = uint16(i) - break - default: // 900+ - grp -= 11345900 - i := 900 - for { - if grp < 23950 { - break - } - i++ - grp -= 23950 - } - gr = uint16(i) - break } - return gr + return uint16(gr) } func dumpSaveData(s *Session, data []byte, suffix string) { From 60dd5df8bcec580961f8e4f222ed09bcfc3cb8b0 Mon Sep 17 00:00:00 2001 From: rockisch Date: Sun, 29 Oct 2023 21:21:11 -0300 Subject: [PATCH 55/96] Update signv2server to return more data --- server/signv2server/dbutils.go | 104 ++++++++++++++-------------- server/signv2server/endpoints.go | 112 ++++++++++++++++++++++--------- 2 files changed, 135 insertions(+), 81 deletions(-) diff --git a/server/signv2server/dbutils.go b/server/signv2server/dbutils.go index 3c8494c95..fb9711da9 100644 --- a/server/signv2server/dbutils.go +++ b/server/signv2server/dbutils.go @@ -10,26 +10,29 @@ import ( "golang.org/x/crypto/bcrypt" ) -func (s *Server) createNewUser(ctx context.Context, username string, password string) (int, error) { +func (s *Server) createNewUser(ctx context.Context, username string, password string) (uint32, uint32, error) { // Create salted hash of user password passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { - return 0, err + return 0, 0, err } - var id int + var ( + id uint32 + rights uint32 + ) err = s.db.QueryRowContext( ctx, ` INSERT INTO users (username, password, return_expires) VALUES ($1, $2, $3) - RETURNING id + RETURNING id, rights `, username, string(passwordHash), time.Now().Add(time.Hour*24*30), - ).Scan(&id) - return id, err + ).Scan(&id, &rights) + return id, rights, err } -func (s *Server) createLoginToken(ctx context.Context, uid int) (string, error) { +func (s *Server) createLoginToken(ctx context.Context, uid uint32) (string, error) { loginToken := token.Generate(16) _, err := s.db.ExecContext(ctx, "INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2)", uid, loginToken) if err != nil { @@ -38,8 +41,8 @@ func (s *Server) createLoginToken(ctx context.Context, uid int) (string, error) return loginToken, nil } -func (s *Server) userIDFromToken(ctx context.Context, token string) (int, error) { - var userID int +func (s *Server) userIDFromToken(ctx context.Context, token string) (uint32, error) { + var userID uint32 err := s.db.QueryRowContext(ctx, "SELECT user_id FROM sign_sessions WHERE token = $1", token).Scan(&userID) if err == sql.ErrNoRows { return 0, fmt.Errorf("invalid login token") @@ -49,65 +52,47 @@ func (s *Server) userIDFromToken(ctx context.Context, token string) (int, error) return userID, nil } -func (s *Server) createCharacter(ctx context.Context, userID int) (int, error) { - var charID int - err := s.db.QueryRowContext(ctx, - "SELECT id FROM characters WHERE is_new_character = true AND user_id = $1", +func (s *Server) createCharacter(ctx context.Context, userID uint32) (Character, error) { + var character Character + err := s.db.GetContext(ctx, &character, + "SELECT id, name, is_female, weapon_type, hrp, gr, last_login FROM characters WHERE is_new_character = true AND user_id = $1 LIMIT 1", userID, - ).Scan(&charID) + ) if err == sql.ErrNoRows { - err = s.db.QueryRowContext(ctx, ` + var count int + s.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM characters WHERE user_id = $1", userID).Scan(&count) + if count >= 16 { + return character, fmt.Errorf("cannot have more than 16 characters") + } + err = s.db.GetContext(ctx, &character, ` INSERT INTO characters ( user_id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login ) VALUES ($1, false, true, '', '', 0, 0, 0, $2) - RETURNING id`, + RETURNING id, name, is_female, weapon_type, hrp, gr, last_login`, userID, uint32(time.Now().Unix()), - ).Scan(&charID) + ) } - return charID, err + return character, err } -func (s *Server) deleteCharacter(ctx context.Context, userID int, charID int) error { - tx, err := s.db.BeginTx(ctx, nil) +func (s *Server) deleteCharacter(ctx context.Context, userID uint32, charID uint32) error { + var isNew bool + err := s.db.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", charID).Scan(&isNew) if err != nil { return err } - defer tx.Rollback() - - _, err = tx.ExecContext( - ctx, ` - DELETE FROM login_boost_state - WHERE char_id = $1`, - charID, - ) - if err != nil { - return err + if isNew { + _, err = s.db.Exec("DELETE FROM characters WHERE id = $1", charID) + } else { + _, err = s.db.Exec("UPDATE characters SET deleted = true WHERE id = $1", charID) } - _, err = tx.ExecContext( - ctx, ` - DELETE FROM guild_characters - WHERE character_id = $1`, - charID, - ) - if err != nil { - return err - } - _, err = tx.ExecContext( - ctx, ` - DELETE FROM characters - WHERE user_id = $1 AND id = $2`, - userID, charID, - ) - if err != nil { - return err - } - return tx.Commit() + return err } -func (s *Server) getCharactersForUser(ctx context.Context, uid int) ([]Character, error) { - characters := make([]Character, 0) +func (s *Server) getCharactersForUser(ctx context.Context, uid uint32) ([]Character, error) { + var characters []Character err := s.db.SelectContext( ctx, &characters, ` SELECT id, name, is_female, weapon_type, hrp, gr, last_login @@ -120,3 +105,20 @@ func (s *Server) getCharactersForUser(ctx context.Context, uid int) ([]Character } return characters, nil } + +func (s *Server) getReturnExpiry(uid uint32) time.Time { + var returnExpiry, lastLogin time.Time + s.db.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid) + if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) { + returnExpiry = time.Now().Add(time.Hour * 24 * 30) + s.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid) + } else { + err := s.db.Get(&returnExpiry, "SELECT return_expires FROM users WHERE id=$1", uid) + if err != nil { + returnExpiry = time.Now() + s.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid) + } + } + s.db.Exec("UPDATE users SET last_login=$1 WHERE id=$2", time.Now(), uid) + return returnExpiry +} diff --git a/server/signv2server/endpoints.go b/server/signv2server/endpoints.go index eeb7442de..b6b888b54 100644 --- a/server/signv2server/endpoints.go +++ b/server/signv2server/endpoints.go @@ -4,7 +4,9 @@ import ( "database/sql" "encoding/json" "errors" + "erupe-ce/server/channelserver" "net/http" + "strings" "time" "github.com/lib/pq" @@ -18,21 +20,78 @@ type LauncherMessage struct { Link string `json:"link"` } +type LauncherResponse struct { + Important []LauncherMessage `json:"important"` + Normal []LauncherMessage `json:"normal"` +} + +type User struct { + Token string `json:"token"` + Rights uint32 `json:"rights"` +} + type Character struct { - ID int `json:"id"` + Id uint32 `json:"id"` Name string `json:"name"` IsFemale bool `json:"isFemale" db:"is_female"` - Weapon int `json:"weapon" db:"weapon_type"` - HR int `json:"hr" db:"hrp"` - GR int `json:"gr"` + Weapon uint32 `json:"weapon" db:"weapon_type"` + Hr uint32 `json:"hr" db:"hrp"` + Gr uint32 `json:"gr"` LastLogin int64 `json:"lastLogin" db:"last_login"` } -func (s *Server) Launcher(w http.ResponseWriter, r *http.Request) { - var respData struct { - Important []LauncherMessage `json:"important"` - Normal []LauncherMessage `json:"normal"` +type MezFes struct { + Id uint32 `json:"id"` + Start uint32 `json:"start"` + End uint32 `json:"end"` + SoloTickets uint32 `json:"soloTickets"` + GroupTickets uint32 `json:"groupTickets"` + Stalls []uint32 `json:"stalls"` +} + +type AuthData struct { + CurrentTs uint32 `json:"currentTs"` + ExpiryTs uint32 `json:"expiryTs"` + EntranceCount uint32 `json:"entranceCount"` + Notifications []string `json:"notifications"` + User User `json:"user"` + Characters []Character `json:"characters"` + MezFes *MezFes `json:"mezFes"` +} + +func (s *Server) newAuthData(userID uint32, userRights uint32, userToken string, characters []Character) AuthData { + resp := AuthData{ + CurrentTs: uint32(channelserver.TimeAdjusted().Unix()), + ExpiryTs: uint32(s.getReturnExpiry(userID).Unix()), + EntranceCount: 1, + User: User{ + Rights: userRights, + Token: userToken, + }, + Characters: characters, } + if s.erupeConfig.DevModeOptions.MezFesEvent { + stalls := []uint32{10, 3, 6, 9, 4, 8, 5, 7} + if s.erupeConfig.DevModeOptions.MezFesAlt { + stalls[4] = 2 + } + resp.MezFes = &MezFes{ + Id: uint32(channelserver.TimeWeekStart().Unix()), + Start: uint32(channelserver.TimeWeekStart().Unix()), + End: uint32(channelserver.TimeWeekNext().Unix()), + SoloTickets: s.erupeConfig.GameplayOptions.MezfesSoloTickets, + GroupTickets: s.erupeConfig.GameplayOptions.MezfesGroupTickets, + Stalls: stalls, + } + } + if !s.erupeConfig.HideLoginNotice { + resp.Notifications = append(resp.Notifications, strings.Join(s.erupeConfig.LoginNotices[:], "")) + } + return resp +} + +func (s *Server) Launcher(w http.ResponseWriter, r *http.Request) { + var respData LauncherResponse respData.Important = []LauncherMessage{ { Message: "Server Update 9 Released!", @@ -75,10 +134,11 @@ func (s *Server) Login(w http.ResponseWriter, r *http.Request) { return } var ( - userID int - password string + userID uint32 + userRights uint32 + password string ) - err := s.db.QueryRow("SELECT id, password FROM users WHERE username = $1", reqData.Username).Scan(&userID, &password) + err := s.db.QueryRow("SELECT id, password, rights FROM users WHERE username = $1", reqData.Username).Scan(&userID, &password, &userRights) if err == sql.ErrNoRows { w.WriteHeader(400) w.Write([]byte("Username does not exist")) @@ -94,22 +154,19 @@ func (s *Server) Login(w http.ResponseWriter, r *http.Request) { return } - var respData struct { - Token string `json:"token"` - Characters []Character `json:"characters"` - } - respData.Token, err = s.createLoginToken(ctx, userID) + userToken, err := s.createLoginToken(ctx, userID) if err != nil { s.logger.Warn("Error registering login token", zap.Error(err)) w.WriteHeader(500) return } - respData.Characters, err = s.getCharactersForUser(ctx, userID) + characters, err := s.getCharactersForUser(ctx, userID) if err != nil { s.logger.Warn("Error getting characters from DB", zap.Error(err)) w.WriteHeader(500) return } + respData := s.newAuthData(userID, userRights, userToken, characters) w.WriteHeader(200) w.Header().Add("Content-Type", "application/json") json.NewEncoder(w).Encode(respData) @@ -128,7 +185,7 @@ func (s *Server) Register(w http.ResponseWriter, r *http.Request) { return } s.logger.Info("Creating account", zap.String("username", reqData.Username)) - userID, err := s.createNewUser(ctx, reqData.Username, reqData.Password) + userID, userRights, err := s.createNewUser(ctx, reqData.Username, reqData.Password) if err != nil { var pqErr *pq.Error if errors.As(err, &pqErr) && pqErr.Constraint == "users_username_key" { @@ -141,15 +198,13 @@ func (s *Server) Register(w http.ResponseWriter, r *http.Request) { return } - var respData struct { - Token string `json:"token"` - } - respData.Token, err = s.createLoginToken(ctx, userID) + userToken, err := s.createLoginToken(ctx, userID) if err != nil { s.logger.Error("Error registering login token", zap.Error(err)) w.WriteHeader(500) return } + respData := s.newAuthData(userID, userRights, userToken, []Character{}) json.NewEncoder(w).Encode(respData) } @@ -165,28 +220,25 @@ func (s *Server) CreateCharacter(w http.ResponseWriter, r *http.Request) { return } - var respData struct { - CharID int `json:"id"` - } userID, err := s.userIDFromToken(ctx, reqData.Token) if err != nil { w.WriteHeader(401) return } - respData.CharID, err = s.createCharacter(ctx, userID) + character, err := s.createCharacter(ctx, userID) if err != nil { s.logger.Error("Failed to create character", zap.Error(err), zap.String("token", reqData.Token)) w.WriteHeader(500) return } - json.NewEncoder(w).Encode(respData) + json.NewEncoder(w).Encode(character) } func (s *Server) DeleteCharacter(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var reqData struct { Token string `json:"token"` - CharID int `json:"id"` + CharId uint32 `json:"charId"` } if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil { s.logger.Error("JSON decode error", zap.Error(err)) @@ -199,8 +251,8 @@ func (s *Server) DeleteCharacter(w http.ResponseWriter, r *http.Request) { w.WriteHeader(401) return } - if err := s.deleteCharacter(ctx, userID, reqData.CharID); err != nil { - s.logger.Error("Failed to delete character", zap.Error(err), zap.String("token", reqData.Token), zap.Int("charID", reqData.CharID)) + if err := s.deleteCharacter(ctx, userID, reqData.CharId); err != nil { + s.logger.Error("Failed to delete character", zap.Error(err), zap.String("token", reqData.Token), zap.Uint32("charID", reqData.CharId)) w.WriteHeader(500) return } From 9d9cc0bf5dff927dfef4b9eaa47df8bc32a6f711 Mon Sep 17 00:00:00 2001 From: rockisch Date: Sun, 29 Oct 2023 21:24:51 -0300 Subject: [PATCH 56/96] Use Go's naming recommendations --- server/signv2server/endpoints.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/server/signv2server/endpoints.go b/server/signv2server/endpoints.go index b6b888b54..c087a70df 100644 --- a/server/signv2server/endpoints.go +++ b/server/signv2server/endpoints.go @@ -31,17 +31,17 @@ type User struct { } type Character struct { - Id uint32 `json:"id"` + ID uint32 `json:"id"` Name string `json:"name"` IsFemale bool `json:"isFemale" db:"is_female"` Weapon uint32 `json:"weapon" db:"weapon_type"` - Hr uint32 `json:"hr" db:"hrp"` - Gr uint32 `json:"gr"` + HR uint32 `json:"hr" db:"hrp"` + GR uint32 `json:"gr"` LastLogin int64 `json:"lastLogin" db:"last_login"` } type MezFes struct { - Id uint32 `json:"id"` + ID uint32 `json:"id"` Start uint32 `json:"start"` End uint32 `json:"end"` SoloTickets uint32 `json:"soloTickets"` @@ -50,8 +50,8 @@ type MezFes struct { } type AuthData struct { - CurrentTs uint32 `json:"currentTs"` - ExpiryTs uint32 `json:"expiryTs"` + CurrentTS uint32 `json:"currentTs"` + ExpiryTS uint32 `json:"expiryTs"` EntranceCount uint32 `json:"entranceCount"` Notifications []string `json:"notifications"` User User `json:"user"` @@ -61,8 +61,8 @@ type AuthData struct { func (s *Server) newAuthData(userID uint32, userRights uint32, userToken string, characters []Character) AuthData { resp := AuthData{ - CurrentTs: uint32(channelserver.TimeAdjusted().Unix()), - ExpiryTs: uint32(s.getReturnExpiry(userID).Unix()), + CurrentTS: uint32(channelserver.TimeAdjusted().Unix()), + ExpiryTS: uint32(s.getReturnExpiry(userID).Unix()), EntranceCount: 1, User: User{ Rights: userRights, @@ -76,7 +76,7 @@ func (s *Server) newAuthData(userID uint32, userRights uint32, userToken string, stalls[4] = 2 } resp.MezFes = &MezFes{ - Id: uint32(channelserver.TimeWeekStart().Unix()), + ID: uint32(channelserver.TimeWeekStart().Unix()), Start: uint32(channelserver.TimeWeekStart().Unix()), End: uint32(channelserver.TimeWeekNext().Unix()), SoloTickets: s.erupeConfig.GameplayOptions.MezfesSoloTickets, @@ -238,7 +238,7 @@ func (s *Server) DeleteCharacter(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var reqData struct { Token string `json:"token"` - CharId uint32 `json:"charId"` + CharID uint32 `json:"charId"` } if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil { s.logger.Error("JSON decode error", zap.Error(err)) @@ -251,8 +251,8 @@ func (s *Server) DeleteCharacter(w http.ResponseWriter, r *http.Request) { w.WriteHeader(401) return } - if err := s.deleteCharacter(ctx, userID, reqData.CharId); err != nil { - s.logger.Error("Failed to delete character", zap.Error(err), zap.String("token", reqData.Token), zap.Uint32("charID", reqData.CharId)) + if err := s.deleteCharacter(ctx, userID, reqData.CharID); err != nil { + s.logger.Error("Failed to delete character", zap.Error(err), zap.String("token", reqData.Token), zap.Uint32("charID", reqData.CharID)) w.WriteHeader(500) return } From 542b8f8bf667f088840658a32fbc880b3d96624f Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 30 Oct 2023 23:23:11 +1100 Subject: [PATCH 57/96] rewrite EnumerateStage --- server/channelserver/handlers_stage.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index e411365d3..258c8b019 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -372,7 +372,6 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { var joinable int for sid, stage := range s.server.stages { stage.RLock() - defer stage.RUnlock() if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { continue @@ -386,9 +385,12 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { resp.WriteUint16(uint16(len(stage.reservedClientSlots))) // Reserved players. resp.WriteUint16(0) // Unk - resp.WriteUint8(0) // Unk - resp.WriteBool(len(stage.clients) > 0) // Has departed. - resp.WriteUint16(stage.maxPlayers) // Max players. + if len(stage.clients) > 0 { + bf.WriteUint16(1) + } else { + bf.WriteUint16(0) + } + resp.WriteUint16(stage.maxPlayers) // Max players. if len(stage.password) > 0 { // This byte has also been seen as 1 // The quest is also recognised as locked when this is 2 @@ -397,6 +399,7 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { resp.WriteUint8(0) } ps.Uint8(resp, sid, false) + stage.RUnlock() } bf.WriteUint16(uint16(joinable)) bf.WriteBytes(resp.Data()) From b526608f4b41eead03df8d22fd7c9738e744908e Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 30 Oct 2023 23:37:07 +1100 Subject: [PATCH 58/96] fix titles not updating correctly --- server/channelserver/handlers_house.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index 560e73ec7..f764a8fa1 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -356,11 +356,11 @@ func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireTitle) var exists int - err := s.server.db.QueryRow("SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2", pkt.TitleID, s.charID).Scan(&exists) + err := s.server.db.QueryRow(`SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2`, pkt.TitleID, s.charID).Scan(&exists) if err != nil || exists == 0 { - s.server.db.Exec("INSERT INTO titles VALUES ($1, $2, now(), now())", pkt.TitleID, s.charID) + s.server.db.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, pkt.TitleID, s.charID) } else { - s.server.db.Exec("UPDATE titles SET updated_at=now()") + s.server.db.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, pkt.TitleID, s.charID) } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } From ffcf511c20ee58002acc7925a74cc4930010671e Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 30 Oct 2023 23:54:50 +1100 Subject: [PATCH 59/96] simplify UseKeepLoginBoost --- server/channelserver/handlers_event.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index d01f92a3d..d39b629d9 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -199,15 +199,11 @@ func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() bf.WriteUint8(0) switch pkt.BoostWeekUsed { - case 1: - fallthrough - case 3: + case 1, 3: expiration = TimeAdjusted().Add(120 * time.Minute) case 4: expiration = TimeAdjusted().Add(180 * time.Minute) - case 2: - fallthrough - case 5: + case 2, 5: expiration = TimeAdjusted().Add(240 * time.Minute) } bf.WriteUint32(uint32(expiration.Unix())) From f9280f483fa1042f5297a63b00a0731443e0af89 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 31 Oct 2023 00:21:05 +1100 Subject: [PATCH 60/96] simplify & handle Mail better --- network/mhfpacket/msg_mhf_list_mail.go | 10 +-- network/mhfpacket/msg_mhf_oprt_mail.go | 14 ++-- network/mhfpacket/msg_mhf_send_mail.go | 5 +- server/channelserver/handlers_mail.go | 95 +++++--------------------- 4 files changed, 32 insertions(+), 92 deletions(-) diff --git a/network/mhfpacket/msg_mhf_list_mail.go b/network/mhfpacket/msg_mhf_list_mail.go index 2dfb351e9..645baf548 100644 --- a/network/mhfpacket/msg_mhf_list_mail.go +++ b/network/mhfpacket/msg_mhf_list_mail.go @@ -1,17 +1,16 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfListMail represents the MSG_MHF_LIST_MAIL type MsgMhfListMail struct { AckHandle uint32 - Unk0 uint32 } // Opcode returns the ID associated with this packet type. @@ -22,7 +21,8 @@ func (m *MsgMhfListMail) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfListMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_oprt_mail.go b/network/mhfpacket/msg_mhf_oprt_mail.go index 2c9e06828..95ec561ee 100644 --- a/network/mhfpacket/msg_mhf_oprt_mail.go +++ b/network/mhfpacket/msg_mhf_oprt_mail.go @@ -11,10 +11,11 @@ import ( type OperateMailOperation uint8 const ( - OPERATE_MAIL_DELETE = 0x01 - OPERATE_MAIL_LOCK = 0x02 - OPERATE_MAIL_UNLOCK = 0x03 - OPERATE_MAIL_ACQUIRE_ITEM = 0x05 + OperateMailDelete = iota + 1 + OperateMailLock + OperateMailUnlock + OpreateMailNull + OperateMailAcquireItem ) // MsgMhfOprtMail represents the MSG_MHF_OPRT_MAIL @@ -23,7 +24,6 @@ type MsgMhfOprtMail struct { AccIndex uint8 Index uint8 Operation OperateMailOperation - Unk0 uint8 Data []byte Amount uint16 ItemID uint16 @@ -40,8 +40,8 @@ func (m *MsgMhfOprtMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCon m.AccIndex = bf.ReadUint8() m.Index = bf.ReadUint8() m.Operation = OperateMailOperation(bf.ReadUint8()) - m.Unk0 = bf.ReadUint8() - if m.Operation == OPERATE_MAIL_ACQUIRE_ITEM { + bf.ReadUint8() // Zeroed + if m.Operation == OperateMailAcquireItem { m.Amount = bf.ReadUint16() m.ItemID = bf.ReadUint16() } diff --git a/network/mhfpacket/msg_mhf_send_mail.go b/network/mhfpacket/msg_mhf_send_mail.go index e0f34ba54..2a21ef93b 100644 --- a/network/mhfpacket/msg_mhf_send_mail.go +++ b/network/mhfpacket/msg_mhf_send_mail.go @@ -15,7 +15,7 @@ type MsgMhfSendMail struct { RecipientID uint32 SubjectLength uint16 BodyLength uint16 - Quantity uint32 + Quantity uint16 ItemID uint16 Subject string Body string @@ -32,7 +32,8 @@ func (m *MsgMhfSendMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCon m.RecipientID = bf.ReadUint32() m.SubjectLength = bf.ReadUint16() m.BodyLength = bf.ReadUint16() - m.Quantity = bf.ReadUint32() + bf.ReadUint16() // Zeroed + m.Quantity = bf.ReadUint16() m.ItemID = bf.ReadUint16() m.Subject = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) m.Body = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) diff --git a/server/channelserver/handlers_mail.go b/server/channelserver/handlers_mail.go index 7e9784ee3..a596d927b 100644 --- a/server/channelserver/handlers_mail.go +++ b/server/channelserver/handlers_mail.go @@ -79,57 +79,6 @@ func (m *Mail) MarkRead(s *Session) error { return nil } -func (m *Mail) MarkDeleted(s *Session) error { - _, err := s.server.db.Exec(` - UPDATE mail SET deleted = true WHERE id = $1 - `, m.ID) - - if err != nil { - s.logger.Error( - "failed to mark mail as deleted", - zap.Error(err), - zap.Int("mailID", m.ID), - ) - return err - } - - return nil -} - -func (m *Mail) MarkAcquired(s *Session) error { - _, err := s.server.db.Exec(` - UPDATE mail SET attached_item_received = true WHERE id = $1 - `, m.ID) - - if err != nil { - s.logger.Error( - "failed to mark mail item as claimed", - zap.Error(err), - zap.Int("mailID", m.ID), - ) - return err - } - - return nil -} - -func (m *Mail) MarkLocked(s *Session, locked bool) error { - _, err := s.server.db.Exec(` - UPDATE mail SET locked = $1 WHERE id = $2 - `, locked, m.ID) - - if err != nil { - s.logger.Error( - "failed to mark mail as locked", - zap.Error(err), - zap.Int("mailID", m.ID), - ) - return err - } - - return nil -} - func GetMailListForCharacter(s *Session, charID uint32) ([]Mail, error) { rows, err := s.server.db.Queryx(` SELECT @@ -256,26 +205,21 @@ func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfReadMail) mailId := s.mailList[pkt.AccIndex] - if mailId == 0 { - doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) - panic("attempting to read mail that doesn't exist in session map") + doAckBufSucceed(s, pkt.AckHandle, []byte{0}) + return } mail, err := GetMailByID(s, mailId) - if err != nil { - doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) - panic(err) + doAckBufSucceed(s, pkt.AckHandle, []byte{0}) + return } - _ = mail.MarkRead(s) - + s.server.db.Exec(`UPDATE mail SET read = true WHERE id = $1`, mail.ID) bf := byteframe.NewByteFrame() - body := stringsupport.UTF8ToSJIS(mail.Body) bf.WriteNullTerminatedBytes(body) - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } @@ -283,10 +227,9 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfListMail) mail, err := GetMailListForCharacter(s, s.charID) - if err != nil { - doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) - panic(err) + doAckBufSucceed(s, pkt.AckHandle, []byte{0}) + return } if s.mailList == nil { @@ -354,24 +297,20 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) { mail, err := GetMailByID(s, s.mailList[pkt.AccIndex]) if err != nil { - panic(err) + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) + return } switch pkt.Operation { - case mhfpacket.OPERATE_MAIL_DELETE: - err = mail.MarkDeleted(s) - case mhfpacket.OPERATE_MAIL_LOCK: - err = mail.MarkLocked(s, true) - case mhfpacket.OPERATE_MAIL_UNLOCK: - err = mail.MarkLocked(s, false) - case mhfpacket.OPERATE_MAIL_ACQUIRE_ITEM: - err = mail.MarkAcquired(s) + case mhfpacket.OperateMailDelete: + s.server.db.Exec(`UPDATE mail SET deleted = true WHERE id = $1`, mail.ID) + case mhfpacket.OperateMailLock: + s.server.db.Exec(`UPDATE mail SET locked = TRUE WHERE id = $1`, mail.ID) + case mhfpacket.OperateMailUnlock: + s.server.db.Exec(`UPDATE mail SET locked = FALSE WHERE id = $1`, mail.ID) + case mhfpacket.OperateMailAcquireItem: + s.server.db.Exec(`UPDATE mail SET attached_item_received = TRUE WHERE id = $1`, mail.ID) } - - if err != nil { - panic(err) - } - doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } From cf8a5da0b2045ed4ade801108339575a9b78b71a Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 1 Nov 2023 08:12:00 +1100 Subject: [PATCH 61/96] Update handlers_stage.go --- server/channelserver/handlers_stage.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index 258c8b019..983d6e79e 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -374,10 +374,12 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { stage.RLock() if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { + stage.RUnlock() continue } if !strings.Contains(stage.id, pkt.StagePrefix) { + stage.RUnlock() continue } From be6f55b5a82a24d6e6a2d158bf4ac45aa1b8839d Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 5 Nov 2023 00:31:16 +1100 Subject: [PATCH 62/96] initial distributions rework --- .../mhfpacket/msg_mhf_enumerate_dist_item.go | 4 +- patch-schema/10-rework-distributions.sql | 15 ++ server/channelserver/handlers_distitem.go | 130 ++++++++---------- 3 files changed, 78 insertions(+), 71 deletions(-) create mode 100644 patch-schema/10-rework-distributions.sql diff --git a/network/mhfpacket/msg_mhf_enumerate_dist_item.go b/network/mhfpacket/msg_mhf_enumerate_dist_item.go index 6d0082ec8..4e89c6dfc 100644 --- a/network/mhfpacket/msg_mhf_enumerate_dist_item.go +++ b/network/mhfpacket/msg_mhf_enumerate_dist_item.go @@ -10,7 +10,7 @@ import ( // MsgMhfEnumerateDistItem represents the MSG_MHF_ENUMERATE_DIST_ITEM type MsgMhfEnumerateDistItem struct { AckHandle uint32 - Unk0 uint8 + DistType uint8 Unk1 uint8 Unk2 uint16 Unk3 []byte @@ -24,7 +24,7 @@ func (m *MsgMhfEnumerateDistItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() + m.DistType = bf.ReadUint8() m.Unk1 = bf.ReadUint8() m.Unk2 = bf.ReadUint16() m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8())) diff --git a/patch-schema/10-rework-distributions.sql b/patch-schema/10-rework-distributions.sql new file mode 100644 index 000000000..c56a9ff67 --- /dev/null +++ b/patch-schema/10-rework-distributions.sql @@ -0,0 +1,15 @@ +BEGIN; + +-- This will delete all of your old distribution data! +--ALTER TABLE IF EXISTS public.distribution DROP COLUMN IF EXISTS data; + +CREATE TABLE public.distribution_items +( + id serial PRIMARY KEY, + distribution_id integer, + item_type integer, + item_id integer, + quantity integer +); + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_distitem.go b/server/channelserver/handlers_distitem.go index 2bde7c60a..97d9e882e 100644 --- a/server/channelserver/handlers_distitem.go +++ b/server/channelserver/handlers_distitem.go @@ -4,24 +4,25 @@ import ( "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/network/mhfpacket" + "time" "go.uber.org/zap" ) type ItemDist struct { - ID uint32 `db:"id"` - Deadline uint32 `db:"deadline"` - TimesAcceptable uint16 `db:"times_acceptable"` - TimesAccepted uint16 `db:"times_accepted"` - MinHR uint16 `db:"min_hr"` - MaxHR uint16 `db:"max_hr"` - MinSR uint16 `db:"min_sr"` - MaxSR uint16 `db:"max_sr"` - MinGR uint16 `db:"min_gr"` - MaxGR uint16 `db:"max_gr"` - EventName string `db:"event_name"` - Description string `db:"description"` - Data []byte `db:"data"` + ID uint32 `db:"id"` + Deadline time.Time `db:"deadline"` + TimesAcceptable uint16 `db:"times_acceptable"` + TimesAccepted uint16 `db:"times_accepted"` + MinHR uint16 `db:"min_hr"` + MaxHR uint16 `db:"max_hr"` + MinSR uint16 `db:"min_sr"` + MaxSR uint16 `db:"max_sr"` + MinGR uint16 `db:"min_gr"` + MaxGR uint16 `db:"max_gr"` + EventName string `db:"event_name"` + Description string `db:"description"` + Data []byte `db:"data"` } func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { @@ -37,13 +38,10 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { WHERE d.id = da.distribution_id AND da.character_id = $1 ) AS times_accepted, - CASE - WHEN (EXTRACT(epoch FROM deadline)::int) IS NULL THEN 0 - ELSE (EXTRACT(epoch FROM deadline)::int) - END deadline + COALESCE(deadline, TO_TIMESTAMP(0)) AS deadline FROM distribution d WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC; - `, s.charID, pkt.Unk0) + `, s.charID, pkt.DistType) if err != nil { s.logger.Error("Error getting distribution data from db", zap.Error(err)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) @@ -56,7 +54,7 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { s.logger.Error("Error parsing item distribution data", zap.Error(err)) } bf.WriteUint32(distData.ID) - bf.WriteUint32(distData.Deadline) + bf.WriteUint32(uint32(distData.Deadline.Unix())) bf.WriteUint32(0) // Unk bf.WriteUint16(distData.TimesAcceptable) bf.WriteUint16(distData.TimesAccepted) @@ -93,67 +91,61 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { resp := byteframe.NewByteFrame() resp.WriteUint16(uint16(distCount)) resp.WriteBytes(bf.Data()) - resp.WriteUint8(0) doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } } +type DistributionItem struct { + ItemType uint8 `db:"item_type"` + ID uint32 `db:"id"` + ItemID uint32 `db:"item_id"` + Quantity uint32 `db:"quantity"` +} + func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfApplyDistItem) - if pkt.DistributionID == 0 { - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 6)) - } else { - row := s.server.db.QueryRowx("SELECT data FROM distribution WHERE id = $1", pkt.DistributionID) - dist := &ItemDist{} - err := row.StructScan(dist) - if err != nil { - s.logger.Error("Error parsing item distribution data", zap.Error(err)) - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 6)) - return + bf := byteframe.NewByteFrame() + bf.WriteUint32(pkt.DistributionID) + var distItems []DistributionItem + rows, err := s.server.db.Queryx(`SELECT id, item_id, item_type, quantity FROM distribution_items WHERE distribution_id=$1`, pkt.DistributionID) + if err == nil { + var distItem DistributionItem + for rows.Next() { + err = rows.StructScan(&distItem) + if err != nil { + continue + } + distItems = append(distItems, distItem) } - - if len(dist.Data) >= 2 { - distData := byteframe.NewByteFrameFromBytes(dist.Data) - distItems := int(distData.ReadUint16()) - for i := 0; i < distItems; i++ { - if len(dist.Data) >= 2+(i*13) { - itemType := distData.ReadUint8() - _ = distData.ReadBytes(6) - quantity := int(distData.ReadUint16()) - _ = distData.ReadBytes(4) - switch itemType { - case 17: - _ = addPointNetcafe(s, quantity) - case 19: - s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID) - case 20: - s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID) - case 21: - s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", quantity, s.charID) - case 23: - saveData, err := GetCharacterSaveData(s, s.charID) - if err == nil { - saveData.RP += uint16(quantity) - saveData.Save(s) - } - } - } + } + bf.WriteUint16(uint16(len(distItems))) + for _, item := range distItems { + bf.WriteUint8(item.ItemType) + bf.WriteUint32(item.ItemID) + bf.WriteUint32(item.Quantity) + bf.WriteUint32(item.ID) + switch item.ItemType { + case 17: + _ = addPointNetcafe(s, int(item.Quantity)) + case 19: + s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) + case 20: + s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) + case 21: + s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) + case 23: + saveData, err := GetCharacterSaveData(s, s.charID) + if err == nil { + saveData.RP += uint16(item.Quantity) + saveData.Save(s) } } + } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - bf := byteframe.NewByteFrame() - bf.WriteUint32(pkt.DistributionID) - bf.WriteBytes(dist.Data) - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - - _, err = s.server.db.Exec(` - INSERT INTO public.distributions_accepted - VALUES ($1, $2) - `, pkt.DistributionID, s.charID) - if err != nil { - s.logger.Error("Error updating accepted dist count", zap.Error(err)) - } + if pkt.DistributionID > 0 { + _, err = s.server.db.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.charID) } } From 4edeaedea3f37c1ee4f625924251c0ab258bfae9 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Sun, 5 Nov 2023 15:23:34 -0500 Subject: [PATCH 63/96] fix: Restore seasons functionality into quests --- server/channelserver/handlers_quest.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index da3c8166a..5c5fb9613 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -47,6 +47,10 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { ) } + if s.server.erupeConfig.GameplayOptions.SeasonOverride { + pkt.Filename = seasonConversion(s, pkt.Filename) + } + data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) @@ -58,6 +62,28 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { } } +func questSuffix(s *Session) string { + // Determine the letter to append for day / night + var timeSet string + if TimeGameAbsolute() > 2880 { + timeSet = "d" + } else { + timeSet = "n" + } + return fmt.Sprintf("%s%d", timeSet, s.server.Season()) +} + +func seasonConversion(s *Session, questFile string) string { + filename := fmt.Sprintf("%s%s", questFile[:5], questSuffix(s)) + + // Return original file if file doesn't exist + if _, err := os.Stat(filename); err == nil { + return filename + } else { + return questFile + } +} + func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest) var data []byte From 68de64a05f57fccafd68aaaa381433e7b8fbba92 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Sun, 5 Nov 2023 19:08:02 -0500 Subject: [PATCH 64/96] fix: Fixed issue with seasons not properly displaying on client --- config.json | 10 +++++----- server/channelserver/handlers_quest.go | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/config.json b/config.json index 31629b894..467512410 100644 --- a/config.json +++ b/config.json @@ -17,8 +17,8 @@ "AutoCreateAccount": true, "CleanDB": false, "MaxLauncherHR": false, - "LogInboundMessages": true, - "LogOutboundMessages": true, + "LogInboundMessages": false, + "LogOutboundMessages": false, "MaxHexdumpLength": 256, "DivaEvent": 0, "FestaEvent": -1, @@ -67,7 +67,7 @@ "EnableHiganjimaEvent": false, "EnableNierEvent": false, "DisableRoad": false, - "SeasonOverride": false + "SeasonOverride": true }, "Discord": { "Enabled": false, @@ -120,9 +120,9 @@ ], "Database": { "Host": "localhost", - "Port": 5432, + "Port": 5433, "User": "postgres", - "Password": "", + "Password": "admin", "Database": "erupe" }, "Sign": { diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 5c5fb9613..40c52f6c4 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -51,8 +51,16 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt.Filename = seasonConversion(s, pkt.Filename) } + // custom quests expect there to be only a d0 for quests, rewrite quests to try for d0 if the quest file doesn't exist + if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))); err != nil { + pkt.Filename = fmt.Sprintf("%s%s", pkt.Filename[:5], "d0") + } + + s.logger.Info("Sent " + pkt.Filename) + data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { + s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) // This will crash the game. doAckBufSucceed(s, pkt.AckHandle, data) @@ -77,10 +85,15 @@ func seasonConversion(s *Session, questFile string) string { filename := fmt.Sprintf("%s%s", questFile[:5], questSuffix(s)) // Return original file if file doesn't exist - if _, err := os.Stat(filename); err == nil { + if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil { return filename } else { - return questFile + // Load d0 if the regular quest file doesn't exist (Fixes custom quests) + if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil { + return questFile + } + + return fmt.Sprintf("%s%s", questFile[:5], "d0") } } From cce64d40108b0cb16a425ccd8285b954f036d80d Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Sun, 5 Nov 2023 19:19:55 -0500 Subject: [PATCH 65/96] fix: Removed random print from code --- server/channelserver/handlers_quest.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 40c52f6c4..c7961ea20 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -56,8 +56,6 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt.Filename = fmt.Sprintf("%s%s", pkt.Filename[:5], "d0") } - s.logger.Info("Sent " + pkt.Filename) - data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { From 5e760da8bc8c570f7b1296e0f1d41038627773d0 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Sun, 5 Nov 2023 19:21:12 -0500 Subject: [PATCH 66/96] chore: Removed credentials --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 467512410..aeb04eadf 100644 --- a/config.json +++ b/config.json @@ -120,9 +120,9 @@ ], "Database": { "Host": "localhost", - "Port": 5433, + "Port": 5432, "User": "postgres", - "Password": "admin", + "Password": "", "Database": "erupe" }, "Sign": { From 6ff20858edd01be10042c6a5ab0b5bf9ccf7b52c Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 7 Nov 2023 16:50:39 +1100 Subject: [PATCH 67/96] rewrite EnumerateStage & parse ReserveStage --- network/mhfpacket/msg_sys_reserve_stage.go | 5 ++--- server/channelserver/handlers_stage.go | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/network/mhfpacket/msg_sys_reserve_stage.go b/network/mhfpacket/msg_sys_reserve_stage.go index 13e47c41b..d2f688af4 100644 --- a/network/mhfpacket/msg_sys_reserve_stage.go +++ b/network/mhfpacket/msg_sys_reserve_stage.go @@ -3,7 +3,6 @@ package mhfpacket import ( "errors" "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -24,8 +23,8 @@ func (m *MsgSysReserveStage) Opcode() network.PacketID { func (m *MsgSysReserveStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Ready = bf.ReadUint8() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + _ = bf.ReadUint8() // StageID length + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index 983d6e79e..be7ab1267 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -367,9 +367,9 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { defer s.server.stagesLock.RUnlock() // Build the response - resp := byteframe.NewByteFrame() bf := byteframe.NewByteFrame() - var joinable int + var joinable uint16 + bf.WriteUint16(0) for sid, stage := range s.server.stages { stage.RLock() @@ -377,34 +377,32 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { stage.RUnlock() continue } - if !strings.Contains(stage.id, pkt.StagePrefix) { stage.RUnlock() continue } - joinable++ - resp.WriteUint16(uint16(len(stage.reservedClientSlots))) // Reserved players. - resp.WriteUint16(0) // Unk + bf.WriteUint16(uint16(len(stage.reservedClientSlots))) + bf.WriteUint16(0) // Unk if len(stage.clients) > 0 { bf.WriteUint16(1) } else { bf.WriteUint16(0) } - resp.WriteUint16(stage.maxPlayers) // Max players. + bf.WriteUint16(stage.maxPlayers) if len(stage.password) > 0 { // This byte has also been seen as 1 // The quest is also recognised as locked when this is 2 - resp.WriteUint8(3) + bf.WriteUint8(2) } else { - resp.WriteUint8(0) + bf.WriteUint8(0) } - ps.Uint8(resp, sid, false) + ps.Uint8(bf, sid, false) stage.RUnlock() } - bf.WriteUint16(uint16(joinable)) - bf.WriteBytes(resp.Data()) + bf.Seek(0, 0) + bf.WriteUint16(joinable) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 29904d5b9297898b4dfd78d8122908749f41c1f0 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 7 Nov 2023 20:23:02 +1100 Subject: [PATCH 68/96] fix signing of min/max Rank Distributions --- patch-schema/10-rework-distributions.sql | 23 ++++++++++++++++++- server/channelserver/handlers_distitem.go | 28 ++++++++++++----------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/patch-schema/10-rework-distributions.sql b/patch-schema/10-rework-distributions.sql index c56a9ff67..4dc794ad3 100644 --- a/patch-schema/10-rework-distributions.sql +++ b/patch-schema/10-rework-distributions.sql @@ -6,10 +6,31 @@ BEGIN; CREATE TABLE public.distribution_items ( id serial PRIMARY KEY, - distribution_id integer, + distribution_id integer NOT NULL, item_type integer, item_id integer, quantity integer ); +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP DEFAULT; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP DEFAULT; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP DEFAULT; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP DEFAULT; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP DEFAULT; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP DEFAULT; + +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP NOT NULL; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP NOT NULL; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP NOT NULL; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP NOT NULL; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP NOT NULL; +ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP NOT NULL; + +UPDATE distribution SET min_hr=NULL WHERE min_hr=65535; +UPDATE distribution SET max_hr=NULL WHERE max_hr=65535; +UPDATE distribution SET min_sr=NULL WHERE min_sr=65535; +UPDATE distribution SET max_sr=NULL WHERE max_sr=65535; +UPDATE distribution SET min_gr=NULL WHERE min_gr=65535; +UPDATE distribution SET max_gr=NULL WHERE max_gr=65535; + END; \ No newline at end of file diff --git a/server/channelserver/handlers_distitem.go b/server/channelserver/handlers_distitem.go index 97d9e882e..7ccf1c74d 100644 --- a/server/channelserver/handlers_distitem.go +++ b/server/channelserver/handlers_distitem.go @@ -14,12 +14,12 @@ type ItemDist struct { Deadline time.Time `db:"deadline"` TimesAcceptable uint16 `db:"times_acceptable"` TimesAccepted uint16 `db:"times_accepted"` - MinHR uint16 `db:"min_hr"` - MaxHR uint16 `db:"max_hr"` - MinSR uint16 `db:"min_sr"` - MaxSR uint16 `db:"max_sr"` - MinGR uint16 `db:"min_gr"` - MaxGR uint16 `db:"max_gr"` + MinHR int16 `db:"min_hr"` + MaxHR int16 `db:"max_hr"` + MinSR int16 `db:"min_sr"` + MaxSR int16 `db:"max_sr"` + MinGR int16 `db:"min_gr"` + MaxGR int16 `db:"max_gr"` EventName string `db:"event_name"` Description string `db:"description"` Data []byte `db:"data"` @@ -31,7 +31,9 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { distCount := 0 dists, err := s.server.db.Queryx(` SELECT d.id, event_name, description, times_acceptable, - min_hr, max_hr, min_sr, max_sr, min_gr, max_gr, + COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr, + COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr, + COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr, ( SELECT count(*) FROM distributions_accepted da @@ -59,12 +61,12 @@ func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(distData.TimesAcceptable) bf.WriteUint16(distData.TimesAccepted) bf.WriteUint16(0) // Unk - bf.WriteUint16(distData.MinHR) - bf.WriteUint16(distData.MaxHR) - bf.WriteUint16(distData.MinSR) - bf.WriteUint16(distData.MaxSR) - bf.WriteUint16(distData.MinGR) - bf.WriteUint16(distData.MaxGR) + bf.WriteInt16(distData.MinHR) + bf.WriteInt16(distData.MaxHR) + bf.WriteInt16(distData.MinSR) + bf.WriteInt16(distData.MaxSR) + bf.WriteInt16(distData.MinGR) + bf.WriteInt16(distData.MaxGR) bf.WriteUint8(0) bf.WriteUint16(0) bf.WriteUint8(0) From 14e61fd661127d009293e12b0c967363d4cbbcf9 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 7 Nov 2023 21:07:49 +1100 Subject: [PATCH 69/96] fix Distribution typing, accepting & add demo --- bundled-schema/DistributionDemo.sql | 11 +++++ patch-schema/10-rework-distributions.sql | 2 +- server/channelserver/handlers_distitem.go | 60 +++++++++++++---------- 3 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 bundled-schema/DistributionDemo.sql diff --git a/bundled-schema/DistributionDemo.sql b/bundled-schema/DistributionDemo.sql new file mode 100644 index 000000000..f8b1dc018 --- /dev/null +++ b/bundled-schema/DistributionDemo.sql @@ -0,0 +1,11 @@ +BEGIN; + +-- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 30 (Item Box extra page) +INSERT INTO distribution (type, event_name, description, times_acceptable) VALUES (1, 'Extra Item Storage', '~C05Adds one new page to your Item Box.', 20); +INSERT INTO distribution_items (distribution_id, item_type, item_id, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 30, 0, 1); + +-- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 31 (Equipment Box extra page) +INSERT INTO distribution (type, event_name, description, times_acceptable) VALUES (1, 'Extra Equipment Storage', '~C05Adds one new page to your Equipment Box.', 20); +INSERT INTO distribution_items (distribution_id, item_type, item_id, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 31, 0, 1); + +END; \ No newline at end of file diff --git a/patch-schema/10-rework-distributions.sql b/patch-schema/10-rework-distributions.sql index 4dc794ad3..7945de343 100644 --- a/patch-schema/10-rework-distributions.sql +++ b/patch-schema/10-rework-distributions.sql @@ -7,7 +7,7 @@ CREATE TABLE public.distribution_items ( id serial PRIMARY KEY, distribution_id integer NOT NULL, - item_type integer, + item_type integer NOT NULL, item_id integer, quantity integer ); diff --git a/server/channelserver/handlers_distitem.go b/server/channelserver/handlers_distitem.go index 7ccf1c74d..97dbfcf15 100644 --- a/server/channelserver/handlers_distitem.go +++ b/server/channelserver/handlers_distitem.go @@ -104,13 +104,9 @@ type DistributionItem struct { Quantity uint32 `db:"quantity"` } -func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfApplyDistItem) - - bf := byteframe.NewByteFrame() - bf.WriteUint32(pkt.DistributionID) +func getDistributionItems(s *Session, i uint32) []DistributionItem { var distItems []DistributionItem - rows, err := s.server.db.Queryx(`SELECT id, item_id, item_type, quantity FROM distribution_items WHERE distribution_id=$1`, pkt.DistributionID) + rows, err := s.server.db.Queryx(`SELECT id, item_type, COALESCE(item_id, 0) AS item_id, COALESCE(quantity, 0) AS quantity FROM distribution_items WHERE distribution_id=$1`, i) if err == nil { var distItem DistributionItem for rows.Next() { @@ -121,38 +117,50 @@ func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) { distItems = append(distItems, distItem) } } + return distItems +} + +func handleMsgMhfApplyDistItem(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfApplyDistItem) + bf := byteframe.NewByteFrame() + bf.WriteUint32(pkt.DistributionID) + distItems := getDistributionItems(s, pkt.DistributionID) bf.WriteUint16(uint16(len(distItems))) for _, item := range distItems { bf.WriteUint8(item.ItemType) bf.WriteUint32(item.ItemID) bf.WriteUint32(item.Quantity) bf.WriteUint32(item.ID) - switch item.ItemType { - case 17: - _ = addPointNetcafe(s, int(item.Quantity)) - case 19: - s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) - case 20: - s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) - case 21: - s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) - case 23: - saveData, err := GetCharacterSaveData(s, s.charID) - if err == nil { - saveData.RP += uint16(item.Quantity) - saveData.Save(s) - } - } } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - - if pkt.DistributionID > 0 { - _, err = s.server.db.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.charID) - } } func handleMsgMhfAcquireDistItem(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireDistItem) + if pkt.DistributionID > 0 { + _, err := s.server.db.Exec(`INSERT INTO public.distributions_accepted VALUES ($1, $2)`, pkt.DistributionID, s.charID) + if err == nil { + distItems := getDistributionItems(s, pkt.DistributionID) + for _, item := range distItems { + switch item.ItemType { + case 17: + _ = addPointNetcafe(s, int(item.Quantity)) + case 19: + s.server.db.Exec("UPDATE users u SET gacha_premium=gacha_premium+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) + case 20: + s.server.db.Exec("UPDATE users u SET gacha_trial=gacha_trial+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) + case 21: + s.server.db.Exec("UPDATE users u SET frontier_points=frontier_points+$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", item.Quantity, s.charID) + case 23: + saveData, err := GetCharacterSaveData(s, s.charID) + if err == nil { + saveData.RP += uint16(item.Quantity) + saveData.Save(s) + } + } + } + } + } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } From 317daef04bbe6c30210dd1cb52082c0aeca09fe3 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 7 Nov 2023 21:26:45 +1100 Subject: [PATCH 70/96] rewrite EnumerateDistItem handler --- .../mhfpacket/msg_mhf_enumerate_dist_item.go | 2 +- server/channelserver/handlers_distitem.go | 106 +++++++++--------- 2 files changed, 53 insertions(+), 55 deletions(-) diff --git a/network/mhfpacket/msg_mhf_enumerate_dist_item.go b/network/mhfpacket/msg_mhf_enumerate_dist_item.go index 4e89c6dfc..bf5796702 100644 --- a/network/mhfpacket/msg_mhf_enumerate_dist_item.go +++ b/network/mhfpacket/msg_mhf_enumerate_dist_item.go @@ -26,7 +26,7 @@ func (m *MsgMhfEnumerateDistItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx. m.AckHandle = bf.ReadUint32() m.DistType = bf.ReadUint8() m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() + m.Unk2 = bf.ReadUint16() // Maximum? Hardcoded to 256 m.Unk3 = bf.ReadBytes(uint(bf.ReadUint8())) return nil } diff --git a/server/channelserver/handlers_distitem.go b/server/channelserver/handlers_distitem.go index 97dbfcf15..b18961202 100644 --- a/server/channelserver/handlers_distitem.go +++ b/server/channelserver/handlers_distitem.go @@ -9,7 +9,7 @@ import ( "go.uber.org/zap" ) -type ItemDist struct { +type Distribution struct { ID uint32 `db:"id"` Deadline time.Time `db:"deadline"` TimesAcceptable uint16 `db:"times_acceptable"` @@ -27,74 +27,72 @@ type ItemDist struct { func handleMsgMhfEnumerateDistItem(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateDistItem) + + var itemDists []Distribution bf := byteframe.NewByteFrame() - distCount := 0 - dists, err := s.server.db.Queryx(` + rows, err := s.server.db.Queryx(` SELECT d.id, event_name, description, times_acceptable, COALESCE(min_hr, -1) AS min_hr, COALESCE(max_hr, -1) AS max_hr, COALESCE(min_sr, -1) AS min_sr, COALESCE(max_sr, -1) AS max_sr, COALESCE(min_gr, -1) AS min_gr, COALESCE(max_gr, -1) AS max_gr, ( - SELECT count(*) - FROM distributions_accepted da - WHERE d.id = da.distribution_id - AND da.character_id = $1 + SELECT count(*) FROM distributions_accepted da + WHERE d.id = da.distribution_id AND da.character_id = $1 ) AS times_accepted, COALESCE(deadline, TO_TIMESTAMP(0)) AS deadline FROM distribution d - WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC; + WHERE character_id = $1 AND type = $2 OR character_id IS NULL AND type = $2 ORDER BY id DESC `, s.charID, pkt.DistType) - if err != nil { - s.logger.Error("Error getting distribution data from db", zap.Error(err)) - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) - } else { - for dists.Next() { - distCount++ - distData := &ItemDist{} - err = dists.StructScan(&distData) + + if err == nil { + var itemDist Distribution + for rows.Next() { + err = rows.StructScan(&itemDist) if err != nil { - s.logger.Error("Error parsing item distribution data", zap.Error(err)) + continue } - bf.WriteUint32(distData.ID) - bf.WriteUint32(uint32(distData.Deadline.Unix())) - bf.WriteUint32(0) // Unk - bf.WriteUint16(distData.TimesAcceptable) - bf.WriteUint16(distData.TimesAccepted) - bf.WriteUint16(0) // Unk - bf.WriteInt16(distData.MinHR) - bf.WriteInt16(distData.MaxHR) - bf.WriteInt16(distData.MinSR) - bf.WriteInt16(distData.MaxSR) - bf.WriteInt16(distData.MinGR) - bf.WriteInt16(distData.MaxGR) - bf.WriteUint8(0) - bf.WriteUint16(0) - bf.WriteUint8(0) - bf.WriteUint16(0) - bf.WriteUint16(0) - bf.WriteUint8(0) - ps.Uint8(bf, distData.EventName, true) - for i := 0; i < 6; i++ { - for j := 0; j < 13; j++ { - bf.WriteUint8(0) - bf.WriteUint32(0) - } - } - i := uint8(0) - bf.WriteUint8(i) - if i <= 10 { - for j := uint8(0); j < i; j++ { - bf.WriteUint32(0) - bf.WriteUint32(0) - bf.WriteUint32(0) - } + itemDists = append(itemDists, itemDist) + } + } + + bf.WriteUint16(uint16(len(itemDists))) + for _, dist := range itemDists { + bf.WriteUint32(dist.ID) + bf.WriteUint32(uint32(dist.Deadline.Unix())) + bf.WriteUint32(0) // Unk + bf.WriteUint16(dist.TimesAcceptable) + bf.WriteUint16(dist.TimesAccepted) + bf.WriteUint16(0) // Unk + bf.WriteInt16(dist.MinHR) + bf.WriteInt16(dist.MaxHR) + bf.WriteInt16(dist.MinSR) + bf.WriteInt16(dist.MaxSR) + bf.WriteInt16(dist.MinGR) + bf.WriteInt16(dist.MaxGR) + bf.WriteUint8(0) + bf.WriteUint16(0) + bf.WriteUint8(0) + bf.WriteUint16(0) + bf.WriteUint16(0) + bf.WriteUint8(0) + ps.Uint8(bf, dist.EventName, true) + for i := 0; i < 6; i++ { + for j := 0; j < 13; j++ { + bf.WriteUint8(0) + bf.WriteUint32(0) + } + } + i := uint8(0) + bf.WriteUint8(i) + if i <= 10 { + for j := uint8(0); j < i; j++ { + bf.WriteUint32(0) + bf.WriteUint32(0) + bf.WriteUint32(0) } } - resp := byteframe.NewByteFrame() - resp.WriteUint16(uint16(distCount)) - resp.WriteBytes(bf.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } type DistributionItem struct { From 7eaf37c1ffa193a27b36c2ae3e4445b579d38fee Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 7 Nov 2023 22:00:07 +1100 Subject: [PATCH 71/96] simplify DistributionDemo script --- bundled-schema/DistributionDemo.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundled-schema/DistributionDemo.sql b/bundled-schema/DistributionDemo.sql index f8b1dc018..d5da8688e 100644 --- a/bundled-schema/DistributionDemo.sql +++ b/bundled-schema/DistributionDemo.sql @@ -2,10 +2,10 @@ BEGIN; -- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 30 (Item Box extra page) INSERT INTO distribution (type, event_name, description, times_acceptable) VALUES (1, 'Extra Item Storage', '~C05Adds one new page to your Item Box.', 20); -INSERT INTO distribution_items (distribution_id, item_type, item_id, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 30, 0, 1); +INSERT INTO distribution_items (distribution_id, item_type, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 30, 1); -- Adds a Distribution that can be accepted up to 20 times that gives one of Item Type 31 (Equipment Box extra page) INSERT INTO distribution (type, event_name, description, times_acceptable) VALUES (1, 'Extra Equipment Storage', '~C05Adds one new page to your Equipment Box.', 20); -INSERT INTO distribution_items (distribution_id, item_type, item_id, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 31, 0, 1); +INSERT INTO distribution_items (distribution_id, item_type, quantity) VALUES ((SELECT id FROM distribution ORDER BY id DESC LIMIT 1), 31, 1); END; \ No newline at end of file From af519a59cf67dad91e15f322beb66b75d1a49b2e Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 7 Nov 2023 16:50:39 +1100 Subject: [PATCH 72/96] rewrite EnumerateStage & parse ReserveStage --- network/mhfpacket/msg_sys_reserve_stage.go | 5 ++--- server/channelserver/handlers_stage.go | 22 ++++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/network/mhfpacket/msg_sys_reserve_stage.go b/network/mhfpacket/msg_sys_reserve_stage.go index 13e47c41b..d2f688af4 100644 --- a/network/mhfpacket/msg_sys_reserve_stage.go +++ b/network/mhfpacket/msg_sys_reserve_stage.go @@ -3,7 +3,6 @@ package mhfpacket import ( "errors" "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -24,8 +23,8 @@ func (m *MsgSysReserveStage) Opcode() network.PacketID { func (m *MsgSysReserveStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Ready = bf.ReadUint8() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + _ = bf.ReadUint8() // StageID length + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index 983d6e79e..be7ab1267 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -367,9 +367,9 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { defer s.server.stagesLock.RUnlock() // Build the response - resp := byteframe.NewByteFrame() bf := byteframe.NewByteFrame() - var joinable int + var joinable uint16 + bf.WriteUint16(0) for sid, stage := range s.server.stages { stage.RLock() @@ -377,34 +377,32 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { stage.RUnlock() continue } - if !strings.Contains(stage.id, pkt.StagePrefix) { stage.RUnlock() continue } - joinable++ - resp.WriteUint16(uint16(len(stage.reservedClientSlots))) // Reserved players. - resp.WriteUint16(0) // Unk + bf.WriteUint16(uint16(len(stage.reservedClientSlots))) + bf.WriteUint16(0) // Unk if len(stage.clients) > 0 { bf.WriteUint16(1) } else { bf.WriteUint16(0) } - resp.WriteUint16(stage.maxPlayers) // Max players. + bf.WriteUint16(stage.maxPlayers) if len(stage.password) > 0 { // This byte has also been seen as 1 // The quest is also recognised as locked when this is 2 - resp.WriteUint8(3) + bf.WriteUint8(2) } else { - resp.WriteUint8(0) + bf.WriteUint8(0) } - ps.Uint8(resp, sid, false) + ps.Uint8(bf, sid, false) stage.RUnlock() } - bf.WriteUint16(uint16(joinable)) - bf.WriteBytes(resp.Data()) + bf.Seek(0, 0) + bf.WriteUint16(joinable) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From 378dfd03723d2a696b8be617221bd77cc71ceee6 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Tue, 7 Nov 2023 21:16:03 -0500 Subject: [PATCH 73/96] fix: Fixed issues with improper loading of areas --- server/channelserver/handlers_quest.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index c7961ea20..2cd326e3c 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -68,19 +68,8 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { } } -func questSuffix(s *Session) string { - // Determine the letter to append for day / night - var timeSet string - if TimeGameAbsolute() > 2880 { - timeSet = "d" - } else { - timeSet = "n" - } - return fmt.Sprintf("%s%d", timeSet, s.server.Season()) -} - func seasonConversion(s *Session, questFile string) string { - filename := fmt.Sprintf("%s%s", questFile[:5], questSuffix(s)) + filename := fmt.Sprintf("%s%d", questFile[:6], s.server.Season()) // Return original file if file doesn't exist if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil { From 611cb2da5bcd96acd658fbbf7eaa3fdf1b6eb94e Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Wed, 8 Nov 2023 13:28:05 -0500 Subject: [PATCH 74/96] feat: Request custom files based on time of day. --- server/channelserver/handlers_quest.go | 42 +++++++++----------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 2cd326e3c..98ce7c8bc 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -51,7 +51,7 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt.Filename = seasonConversion(s, pkt.Filename) } - // custom quests expect there to be only a d0 for quests, rewrite quests to try for d0 if the quest file doesn't exist + // Default to d0 for any other quest that has no alternative versions if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))); err != nil { pkt.Filename = fmt.Sprintf("%s%s", pkt.Filename[:5], "d0") } @@ -71,16 +71,26 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { func seasonConversion(s *Session, questFile string) string { filename := fmt.Sprintf("%s%d", questFile[:6], s.server.Season()) - // Return original file if file doesn't exist + // Return the seasonal file if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", filename))); err == nil { return filename } else { - // Load d0 if the regular quest file doesn't exist (Fixes custom quests) + // Attempt to return the requested quest file if the seasonal file doesn't exist if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil { return questFile } - return fmt.Sprintf("%s%s", questFile[:5], "d0") + // For custom quests, we need to return the day or night version of the quest. + var time string + + if TimeGameAbsolute() > 2880 { + time = "d" + } else { + time = "n" + } + + // Request a file based on day or night + return fmt.Sprintf("%s%s%d", questFile[:5], time, 0) } } @@ -184,30 +194,6 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { bf.WriteUint16(0) // Unk bf.WriteUint16(uint16(len(data))) bf.WriteBytes(data) - - // Time Flag Replacement - // Bitset Structure: b8 UNK, b7 Required Objective, b6 UNK, b5 Night, b4 Day, b3 Cold, b2 Warm, b1 Spring - // if the byte is set to 0 the game choses the quest file corresponding to whatever season the game is on - bf.Seek(25, 0) - flagByte := bf.ReadUint8() - bf.Seek(25, 0) - if s.server.erupeConfig.GameplayOptions.SeasonOverride { - bf.WriteUint8(flagByte & 0b11100000) - } else { - bf.WriteUint8(flagByte) - } - - // Bitset Structure Quest Variant 1: b8 UL Fixed, b7 UNK, b6 UNK, b5 UNK, b4 G Rank, b3 HC to UL, b2 Fix HC, b1 Hiden - // Bitset Structure Quest Variant 2: b8 Road, b7 High Conquest, b6 Fixed Difficulty, b5 No Active Feature, b4 Timer, b3 No Cuff, b2 No Halk Pots, b1 Low Conquest - // Bitset Structure Quest Variant 3: b8 No Sigils, b7 UNK, b6 Interception, b5 Zenith, b4 No GP Skills, b3 No Simple Mode?, b2 GSR to GR, b1 No Reward Skills - - bf.Seek(175, 0) - questVariant3 := bf.ReadUint8() - questVariant3 &= 0b11011111 // disable Interception flag - bf.Seek(175, 0) - bf.WriteUint8(questVariant3) - - bf.Seek(0, 2) ps.Uint8(bf, "", true) // Debug/Notes string for quest return bf.Data(), nil } From 3e4e325675243e3523b0baebe25418059fb639c5 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Sat, 11 Nov 2023 03:42:08 -0500 Subject: [PATCH 75/96] feat: Implement event quest season/time flag override --- patch-schema/10-event-quest-flags.sql | 5 ++++ server/channelserver/handlers_quest.go | 32 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 patch-schema/10-event-quest-flags.sql diff --git a/patch-schema/10-event-quest-flags.sql b/patch-schema/10-event-quest-flags.sql new file mode 100644 index 000000000..24b59db6a --- /dev/null +++ b/patch-schema/10-event-quest-flags.sql @@ -0,0 +1,5 @@ +BEGIN; + +ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS flag_override integer NOT NULL DEFAULT -1; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 98ce7c8bc..7eaf45292 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -156,7 +156,8 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { var id, mark uint32 var questId int var maxPlayers, questType uint8 - rows.Scan(&id, &maxPlayers, &questType, &questId, &mark) + var questFlags int8 + rows.Scan(&id, &maxPlayers, &questType, &questId, &mark, &questFlags) data := loadQuestFile(s, questId) if data == nil { @@ -194,6 +195,35 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { bf.WriteUint16(0) // Unk bf.WriteUint16(uint16(len(data))) bf.WriteBytes(data) + + // Time Flag Replacement + // Bitset Structure: b8 UNK, b7 Required Objective, b6 UNK, b5 Night, b4 Day, b3 Cold, b2 Warm, b1 Spring + // if the byte is set to 0 the game choses the quest file corresponding to whatever season the game is on + bf.Seek(25, 0) + flagByte := bf.ReadUint8() + bf.Seek(25, 0) + if s.server.erupeConfig.GameplayOptions.SeasonOverride { + bf.WriteUint8(flagByte & 0b11100000) + } else { + // Allow for seasons to be specified in database, otherwise use the one in the file. + if questFlags == -1 { + bf.WriteUint8(flagByte) + } else { + bf.WriteUint8(uint8(questFlags)) + } + } + + // Bitset Structure Quest Variant 1: b8 UL Fixed, b7 UNK, b6 UNK, b5 UNK, b4 G Rank, b3 HC to UL, b2 Fix HC, b1 Hiden + // Bitset Structure Quest Variant 2: b8 Road, b7 High Conquest, b6 Fixed Difficulty, b5 No Active Feature, b4 Timer, b3 No Cuff, b2 No Halk Pots, b1 Low Conquest + // Bitset Structure Quest Variant 3: b8 No Sigils, b7 UNK, b6 Interception, b5 Zenith, b4 No GP Skills, b3 No Simple Mode?, b2 GSR to GR, b1 No Reward Skills + + bf.Seek(175, 0) + questVariant3 := bf.ReadUint8() + questVariant3 &= 0b11011111 // disable Interception flag + bf.Seek(175, 0) + bf.WriteUint8(questVariant3) + + bf.Seek(0, 2) ps.Uint8(bf, "", true) // Debug/Notes string for quest return bf.Data(), nil } From f588d47aa18f19f598800f13331abc6e470b7327 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Sun, 12 Nov 2023 16:01:19 -0500 Subject: [PATCH 76/96] chore: Reset config files --- config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index aeb04eadf..31629b894 100644 --- a/config.json +++ b/config.json @@ -17,8 +17,8 @@ "AutoCreateAccount": true, "CleanDB": false, "MaxLauncherHR": false, - "LogInboundMessages": false, - "LogOutboundMessages": false, + "LogInboundMessages": true, + "LogOutboundMessages": true, "MaxHexdumpLength": 256, "DivaEvent": 0, "FestaEvent": -1, @@ -67,7 +67,7 @@ "EnableHiganjimaEvent": false, "EnableNierEvent": false, "DisableRoad": false, - "SeasonOverride": true + "SeasonOverride": false }, "Discord": { "Enabled": false, From a9b8bb4c56a315bc768713a6d34906cdf3f25b20 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Thu, 16 Nov 2023 02:00:01 -0500 Subject: [PATCH 77/96] fix: Added flags to sql query --- config.json | 4 ++-- server/channelserver/handlers_quest.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index 31629b894..5dcb6ef51 100644 --- a/config.json +++ b/config.json @@ -120,9 +120,9 @@ ], "Database": { "Host": "localhost", - "Port": 5432, + "Port": 5433, "User": "postgres", - "Password": "", + "Password": "admin", "Database": "erupe" }, "Sign": { diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 7eaf45292..91a000c5b 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -234,7 +234,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() bf.WriteUint16(0) - rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark FROM event_quests ORDER BY quest_id") + rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, flags FROM event_quests ORDER BY quest_id") for rows.Next() { data, err := makeEventQuest(s, rows) if err != nil { From 8c69a98c58285d1e6bd6f354b5a9c500a49ce488 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 16 Nov 2023 21:31:31 +1100 Subject: [PATCH 78/96] remove arbitrary test code --- server/channelserver/handlers_quest.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index da3c8166a..76a615c49 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -202,18 +202,10 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { continue } else { totalCount++ - if _config.ErupeConfig.RealClientMode == _config.F5 { - if totalCount > pkt.Offset && len(bf.Data()) < 21550 { - returnedCount++ - bf.WriteBytes(data) - continue - } - } else { - if totalCount > pkt.Offset && len(bf.Data()) < 60000 { - returnedCount++ - bf.WriteBytes(data) - continue - } + if totalCount > pkt.Offset && len(bf.Data()) < 60000 { + returnedCount++ + bf.WriteBytes(data) + continue } } } From 15253cdc1f84769cfd171d58a73540899f30ee25 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 16 Nov 2023 21:49:43 +1100 Subject: [PATCH 79/96] remove useless CIDs --- server/channelserver/sys_channel_server.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 1dfef82d0..02ede6f29 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -316,7 +316,6 @@ func (s *Server) BroadcastChatMessage(message string) { msgBinChat.Build(bf) s.BroadcastMHF(&mhfpacket.MsgSysCastedBinary{ - CharID: 0xFFFFFFFF, MessageType: BinaryMessageTypeChat, RawDataPayload: bf.Data(), }, nil) @@ -348,7 +347,6 @@ func (s *Server) BroadcastRaviente(ip uint32, port uint16, stage []byte, _type u bf.WriteUint16(0) // Unk bf.WriteBytes(stage) s.WorldcastMHF(&mhfpacket.MsgSysCastedBinary{ - CharID: 0x00000000, BroadcastType: BroadcastTypeServer, MessageType: BinaryMessageTypeChat, RawDataPayload: bf.Data(), From 72bda06916cd29d63056a2dc2753244b4b07a5b5 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 16 Nov 2023 21:51:28 +1100 Subject: [PATCH 80/96] implement Quest caching --- config.json | 1 + config/config.go | 1 + server/channelserver/handlers_quest.go | 7 +++++++ server/channelserver/sys_channel_server.go | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/config.json b/config.json index 31629b894..a62b45325 100644 --- a/config.json +++ b/config.json @@ -12,6 +12,7 @@ "ScreenshotAPIURL": "", "DeleteOnSaveCorruption": false, "ClientMode": "ZZ", + "QuestCacheExpiry": 300, "DevMode": true, "DevModeOptions": { "AutoCreateAccount": true, diff --git a/config/config.go b/config/config.go index 65c663511..4c156d35e 100644 --- a/config/config.go +++ b/config/config.go @@ -79,6 +79,7 @@ type Config struct { DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion ClientMode string RealClientMode Mode + QuestCacheExpiry int // Number of seconds to keep quest data cached DevMode bool DevModeOptions DevModeOptions diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 76a615c49..2c82986e7 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -77,6 +77,11 @@ func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) { } func loadQuestFile(s *Session, questId int) []byte { + data, exists := s.server.questCacheData[questId] + if exists && s.server.questCacheTime[questId].Add(time.Duration(s.server.erupeConfig.QuestCacheExpiry)*time.Second).After(time.Now()) { + return data + } + file, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%05dd0.bin", questId))) if err != nil { return nil @@ -113,6 +118,8 @@ func loadQuestFile(s *Session, questId int) []byte { } questBody.WriteBytes(newStrings.Data()) + s.server.questCacheData[questId] = questBody.Data() + s.server.questCacheTime[questId] = time.Now() return questBody.Data() } diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 02ede6f29..d12d713f5 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -5,6 +5,7 @@ import ( "net" "strings" "sync" + "time" "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" @@ -73,6 +74,9 @@ type Server struct { name string raviente *Raviente + + questCacheData map[int][]byte + questCacheTime map[int]time.Time } type Raviente struct { @@ -163,6 +167,8 @@ func NewServer(config *Config) *Server { state: make([]uint32, 30), support: make([]uint32, 30), }, + questCacheData: make(map[int][]byte), + questCacheTime: make(map[int]time.Time), } // Mezeporta From 6c32eae9f24565f61f182f9b59abf1707ca95ee2 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 16 Nov 2023 21:56:48 +1100 Subject: [PATCH 81/96] simplify code --- server/channelserver/handlers_cast_binary.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 30a377b82..168e2f181 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -6,6 +6,7 @@ import ( "erupe-ce/common/mhfcourse" "erupe-ce/common/token" "erupe-ce/config" + "erupe-ce/network" "erupe-ce/network/binpacket" "erupe-ce/network/mhfpacket" "fmt" @@ -125,7 +126,7 @@ func parseChatCommand(s *Session, command string) { deleteNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(deleteNotif, s.clientContext) } - deleteNotif.WriteUint16(0x0010) + deleteNotif.WriteUint16(uint16(network.MSG_SYS_END)) s.QueueSend(deleteNotif.Data()) time.Sleep(500 * time.Millisecond) reloadNotif := byteframe.NewByteFrame() @@ -160,7 +161,7 @@ func parseChatCommand(s *Session, command string) { reloadNotif.WriteUint16(uint16(temp.Opcode())) temp.Build(reloadNotif, s.clientContext) } - reloadNotif.WriteUint16(0x0010) + reloadNotif.WriteUint16(uint16(network.MSG_SYS_END)) s.QueueSend(reloadNotif.Data()) } else { sendDisabledCommandMessage(s, commands["Reload"]) From 34044f72b043089484c2f1852ccde178fcf6b888 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Thu, 16 Nov 2023 11:07:00 -0500 Subject: [PATCH 82/96] chore: Fix config.json --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 5dcb6ef51..31629b894 100644 --- a/config.json +++ b/config.json @@ -120,9 +120,9 @@ ], "Database": { "Host": "localhost", - "Port": 5433, + "Port": 5432, "User": "postgres", - "Password": "admin", + "Password": "", "Database": "erupe" }, "Sign": { From 2e2d129871089000b52e43f4a379d990b3ca3195 Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Thu, 16 Nov 2023 11:10:46 -0500 Subject: [PATCH 83/96] docs: Fix annotation for custom quest conditions --- server/channelserver/handlers_quest.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 91a000c5b..999519766 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -80,7 +80,8 @@ func seasonConversion(s *Session, questFile string) string { return questFile } - // For custom quests, we need to return the day or night version of the quest. + // If the code reaches this point, it's most likely a custom quest with no seasonal variations in the files. + // Since event quests when seasonal pick day or night and the client requests either one, we need to differentiate between the two to prevent issues. var time string if TimeGameAbsolute() > 2880 { @@ -89,7 +90,7 @@ func seasonConversion(s *Session, questFile string) string { time = "n" } - // Request a file based on day or night + // Request a D0 or N0 file depending on the time of day. The time of day matters since the client will quite a few issues if it's different to the one it requests. return fmt.Sprintf("%s%s%d", questFile[:5], time, 0) } } From 6384d79a7ab00a0bda0cc197b679df9cc9b7548e Mon Sep 17 00:00:00 2001 From: Matthe815 Date: Thu, 16 Nov 2023 11:29:31 -0500 Subject: [PATCH 84/96] fix: Removed unnecessary condition --- server/channelserver/handlers_quest.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 999519766..7c782fb60 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -51,14 +51,8 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt.Filename = seasonConversion(s, pkt.Filename) } - // Default to d0 for any other quest that has no alternative versions - if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))); err != nil { - pkt.Filename = fmt.Sprintf("%s%s", pkt.Filename[:5], "d0") - } - data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", pkt.Filename))) if err != nil { - s.logger.Error(fmt.Sprintf("Failed to open file: %s/quests/%s.bin", s.server.erupeConfig.BinPath, pkt.Filename)) // This will crash the game. doAckBufSucceed(s, pkt.AckHandle, data) From 490aecd94b5c31e368e01be2193881024cc6d839 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 18 Nov 2023 15:44:59 +1100 Subject: [PATCH 85/96] rewrite comments & change quest flag code --- ...est-flags.sql => 11-event-quest-flags.sql} | 2 +- server/channelserver/handlers_quest.go | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) rename patch-schema/{10-event-quest-flags.sql => 11-event-quest-flags.sql} (62%) diff --git a/patch-schema/10-event-quest-flags.sql b/patch-schema/11-event-quest-flags.sql similarity index 62% rename from patch-schema/10-event-quest-flags.sql rename to patch-schema/11-event-quest-flags.sql index 24b59db6a..5f88d732d 100644 --- a/patch-schema/10-event-quest-flags.sql +++ b/patch-schema/11-event-quest-flags.sql @@ -1,5 +1,5 @@ BEGIN; -ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS flag_override integer NOT NULL DEFAULT -1; +ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS flags integer; END; \ No newline at end of file diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index 7c782fb60..fbabec35d 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -70,22 +70,22 @@ func seasonConversion(s *Session, questFile string) string { return filename } else { // Attempt to return the requested quest file if the seasonal file doesn't exist - if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil { + if _, err = os.Stat(filepath.Join(s.server.erupeConfig.BinPath, fmt.Sprintf("quests/%s.bin", questFile))); err == nil { return questFile } // If the code reaches this point, it's most likely a custom quest with no seasonal variations in the files. // Since event quests when seasonal pick day or night and the client requests either one, we need to differentiate between the two to prevent issues. - var time string + var _time string if TimeGameAbsolute() > 2880 { - time = "d" + _time = "d" } else { - time = "n" + _time = "n" } - // Request a D0 or N0 file depending on the time of day. The time of day matters since the client will quite a few issues if it's different to the one it requests. - return fmt.Sprintf("%s%s%d", questFile[:5], time, 0) + // Request a d0 or n0 file depending on the time of day. The time of day matters and issues will occur if it's different to the one it requests. + return fmt.Sprintf("%s%s%d", questFile[:5], _time, 0) } } @@ -149,10 +149,9 @@ func loadQuestFile(s *Session, questId int) []byte { func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { var id, mark uint32 - var questId int + var questId, flags int var maxPlayers, questType uint8 - var questFlags int8 - rows.Scan(&id, &maxPlayers, &questType, &questId, &mark, &questFlags) + rows.Scan(&id, &maxPlayers, &questType, &questId, &mark, &flags) data := loadQuestFile(s, questId) if data == nil { @@ -201,10 +200,10 @@ func makeEventQuest(s *Session, rows *sql.Rows) ([]byte, error) { bf.WriteUint8(flagByte & 0b11100000) } else { // Allow for seasons to be specified in database, otherwise use the one in the file. - if questFlags == -1 { + if flags < 0 { bf.WriteUint8(flagByte) } else { - bf.WriteUint8(uint8(questFlags)) + bf.WriteUint8(uint8(flags)) } } @@ -229,7 +228,7 @@ func handleMsgMhfEnumerateQuest(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() bf.WriteUint16(0) - rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, flags FROM event_quests ORDER BY quest_id") + rows, _ := s.server.db.Query("SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, COALESCE(flags, -1) FROM event_quests ORDER BY quest_id") for rows.Next() { data, err := makeEventQuest(s, rows) if err != nil { From fc57d6368973574a5fb0b8dae14dedb9de874d84 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 00:35:22 +1100 Subject: [PATCH 86/96] update parsing of many packets --- .../mhfpacket/msg_mhf_acquire_guild_tresure.go | 4 ++-- network/mhfpacket/msg_mhf_acquire_title.go | 12 ++++++------ .../mhfpacket/msg_mhf_check_daily_cafepoint.go | 7 +++---- network/mhfpacket/msg_mhf_check_monthly_item.go | 5 +++-- network/mhfpacket/msg_mhf_check_weekly_stamp.go | 3 +-- network/mhfpacket/msg_mhf_create_guild.go | 7 ++----- .../mhfpacket/msg_mhf_displayed_achievement.go | 12 +++++------- network/mhfpacket/msg_mhf_enumerate_event.go | 14 +++++--------- network/mhfpacket/msg_mhf_enumerate_price.go | 14 ++++++-------- network/mhfpacket/msg_mhf_enumerate_ranking.go | 15 +++++++-------- .../mhfpacket/msg_mhf_enumerate_union_item.go | 5 ++--- network/mhfpacket/msg_mhf_get_achievement.go | 3 +-- network/mhfpacket/msg_mhf_get_rengoku_binary.go | 11 +++++------ network/mhfpacket/msg_mhf_info_festa.go | 17 +++++++++-------- network/mhfpacket/msg_mhf_list_member.go | 13 +++++++------ network/mhfpacket/msg_mhf_read_mail.go | 3 +-- network/mhfpacket/msg_mhf_release_event.go | 3 +-- network/mhfpacket/msg_mhf_update_cafepoint.go | 14 ++++++-------- network/mhfpacket/msg_mhf_update_guacot.go | 2 +- network/mhfpacket/msg_mhf_update_guild_icon.go | 12 +++++------- network/mhfpacket/msg_mhf_update_guild_item.go | 17 ++++++++--------- network/mhfpacket/msg_mhf_update_house.go | 8 ++++---- network/mhfpacket/msg_mhf_update_union_item.go | 15 +++++++-------- network/mhfpacket/msg_sys_get_file.go | 2 +- network/mhfpacket/msg_sys_hide_client.go | 15 +++++++-------- network/mhfpacket/msg_sys_issue_logkey.go | 13 ++++++------- network/mhfpacket/msg_sys_rights_reload.go | 14 +++++++------- network/mhfpacket/msg_sys_set_stage_pass.go | 13 ++++++------- network/mhfpacket/msg_sys_terminal_log.go | 16 +++++++--------- server/channelserver/handlers.go | 6 +++--- server/channelserver/handlers_guild.go | 8 ++++---- server/channelserver/handlers_house.go | 14 ++++++++------ 32 files changed, 146 insertions(+), 171 deletions(-) diff --git a/network/mhfpacket/msg_mhf_acquire_guild_tresure.go b/network/mhfpacket/msg_mhf_acquire_guild_tresure.go index 775e98bf5..ac9feb557 100644 --- a/network/mhfpacket/msg_mhf_acquire_guild_tresure.go +++ b/network/mhfpacket/msg_mhf_acquire_guild_tresure.go @@ -12,7 +12,7 @@ import ( type MsgMhfAcquireGuildTresure struct { AckHandle uint32 HuntID uint32 - Unk uint8 + Unk bool } // Opcode returns the ID associated with this packet type. @@ -24,7 +24,7 @@ func (m *MsgMhfAcquireGuildTresure) Opcode() network.PacketID { func (m *MsgMhfAcquireGuildTresure) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.HuntID = bf.ReadUint32() - m.Unk = bf.ReadUint8() + m.Unk = bf.ReadBool() return nil } diff --git a/network/mhfpacket/msg_mhf_acquire_title.go b/network/mhfpacket/msg_mhf_acquire_title.go index fe3a5ca95..9b9dd84dc 100644 --- a/network/mhfpacket/msg_mhf_acquire_title.go +++ b/network/mhfpacket/msg_mhf_acquire_title.go @@ -11,9 +11,7 @@ import ( // MsgMhfAcquireTitle represents the MSG_MHF_ACQUIRE_TITLE type MsgMhfAcquireTitle struct { AckHandle uint32 - Unk0 uint16 - Unk1 uint16 - TitleID uint16 + TitleIDs []uint16 } // Opcode returns the ID associated with this packet type. @@ -24,9 +22,11 @@ func (m *MsgMhfAcquireTitle) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfAcquireTitle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() - m.TitleID = bf.ReadUint16() + titles := int(bf.ReadUint16()) + bf.ReadUint16() // Zeroed + for i := 0; i < titles; i++ { + m.TitleIDs = append(m.TitleIDs, bf.ReadUint16()) + } return nil } diff --git a/network/mhfpacket/msg_mhf_check_daily_cafepoint.go b/network/mhfpacket/msg_mhf_check_daily_cafepoint.go index 6e4c26b97..fee1ec222 100644 --- a/network/mhfpacket/msg_mhf_check_daily_cafepoint.go +++ b/network/mhfpacket/msg_mhf_check_daily_cafepoint.go @@ -1,9 +1,10 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfCheckDailyCafepoint represents the MSG_MHF_CHECK_DAILY_CAFEPOINT @@ -25,7 +26,5 @@ func (m *MsgMhfCheckDailyCafepoint) Parse(bf *byteframe.ByteFrame, ctx *clientct } func (m *MsgMhfCheckDailyCafepoint) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint32(m.Unk) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_check_monthly_item.go b/network/mhfpacket/msg_mhf_check_monthly_item.go index 860725aa4..257e0f855 100644 --- a/network/mhfpacket/msg_mhf_check_monthly_item.go +++ b/network/mhfpacket/msg_mhf_check_monthly_item.go @@ -12,7 +12,6 @@ import ( type MsgMhfCheckMonthlyItem struct { AckHandle uint32 Type uint8 - Unk []byte } // Opcode returns the ID associated with this packet type. @@ -24,7 +23,9 @@ func (m *MsgMhfCheckMonthlyItem) Opcode() network.PacketID { func (m *MsgMhfCheckMonthlyItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Type = bf.ReadUint8() - m.Unk = bf.ReadBytes(3) + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_check_weekly_stamp.go b/network/mhfpacket/msg_mhf_check_weekly_stamp.go index f03b1d1e7..069a17456 100644 --- a/network/mhfpacket/msg_mhf_check_weekly_stamp.go +++ b/network/mhfpacket/msg_mhf_check_weekly_stamp.go @@ -12,7 +12,6 @@ type MsgMhfCheckWeeklyStamp struct { AckHandle uint32 StampType string Unk1 bool - Unk2 uint16 // Hardcoded 0 in the binary } // Opcode returns the ID associated with this packet type. @@ -31,7 +30,7 @@ func (m *MsgMhfCheckWeeklyStamp) Parse(bf *byteframe.ByteFrame, ctx *clientctx.C m.StampType = "ex" } m.Unk1 = bf.ReadBool() - m.Unk2 = bf.ReadUint16() + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_create_guild.go b/network/mhfpacket/msg_mhf_create_guild.go index e37267885..e82f7157e 100644 --- a/network/mhfpacket/msg_mhf_create_guild.go +++ b/network/mhfpacket/msg_mhf_create_guild.go @@ -12,8 +12,6 @@ import ( // MsgMhfCreateGuild represents the MSG_MHF_CREATE_GUILD type MsgMhfCreateGuild struct { AckHandle uint32 - Unk0 uint8 - Unk1 uint8 Name string } @@ -25,9 +23,8 @@ func (m *MsgMhfCreateGuild) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfCreateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - _ = bf.ReadUint16() // len + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Name length m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_mhf_displayed_achievement.go b/network/mhfpacket/msg_mhf_displayed_achievement.go index 03de31f39..2633c081e 100644 --- a/network/mhfpacket/msg_mhf_displayed_achievement.go +++ b/network/mhfpacket/msg_mhf_displayed_achievement.go @@ -1,15 +1,14 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfDisplayedAchievement represents the MSG_MHF_DISPLAYED_ACHIEVEMENT -type MsgMhfDisplayedAchievement struct { - Unk0 uint8 -} +type MsgMhfDisplayedAchievement struct{} // Opcode returns the ID associated with this packet type. func (m *MsgMhfDisplayedAchievement) Opcode() network.PacketID { @@ -18,12 +17,11 @@ func (m *MsgMhfDisplayedAchievement) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfDisplayedAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.Unk0 = bf.ReadUint8() + bf.ReadUint8() // Zeroed return nil } // Build builds a binary packet from the current data. func (m *MsgMhfDisplayedAchievement) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint8(m.Unk0) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_enumerate_event.go b/network/mhfpacket/msg_mhf_enumerate_event.go index d73f92cdc..6a863f92f 100644 --- a/network/mhfpacket/msg_mhf_enumerate_event.go +++ b/network/mhfpacket/msg_mhf_enumerate_event.go @@ -1,16 +1,15 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfEnumerateEvent represents the MSG_MHF_ENUMERATE_EVENT type MsgMhfEnumerateEvent struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 0 in the binary - Unk1 uint16 // Hardcoded 0 in the binary } // Opcode returns the ID associated with this packet type. @@ -21,15 +20,12 @@ func (m *MsgMhfEnumerateEvent) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Zeroed return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateEvent) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint16(m.Unk0) - bf.WriteUint16(m.Unk1) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_enumerate_price.go b/network/mhfpacket/msg_mhf_enumerate_price.go index 5dcfa69f3..e36246364 100644 --- a/network/mhfpacket/msg_mhf_enumerate_price.go +++ b/network/mhfpacket/msg_mhf_enumerate_price.go @@ -1,18 +1,16 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumeratePrice represents the MSG_MHF_ENUMERATE_PRICE type MsgMhfEnumeratePrice struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 0 in the binary - Unk1 uint16 // Hardcoded 0 in the binary } // Opcode returns the ID associated with this packet type. @@ -23,8 +21,8 @@ func (m *MsgMhfEnumeratePrice) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumeratePrice) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_ranking.go b/network/mhfpacket/msg_mhf_enumerate_ranking.go index 4baef5738..a891a0e12 100644 --- a/network/mhfpacket/msg_mhf_enumerate_ranking.go +++ b/network/mhfpacket/msg_mhf_enumerate_ranking.go @@ -1,18 +1,16 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumerateRanking represents the MSG_MHF_ENUMERATE_RANKING type MsgMhfEnumerateRanking struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 0 in the binary - Unk1 uint16 // Hardcoded 0 in the binary } // Opcode returns the ID associated with this packet type. @@ -23,8 +21,9 @@ func (m *MsgMhfEnumerateRanking) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateRanking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + bf.ReadUint16() // Zeroed + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_union_item.go b/network/mhfpacket/msg_mhf_enumerate_union_item.go index 780539b12..38ff89f5c 100644 --- a/network/mhfpacket/msg_mhf_enumerate_union_item.go +++ b/network/mhfpacket/msg_mhf_enumerate_union_item.go @@ -11,7 +11,6 @@ import ( // MsgMhfEnumerateUnionItem represents the MSG_MHF_ENUMERATE_UNION_ITEM type MsgMhfEnumerateUnionItem struct { AckHandle uint32 - Unk0 uint16 } // Opcode returns the ID associated with this packet type. @@ -22,8 +21,8 @@ func (m *MsgMhfEnumerateUnionItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateUnionItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_get_achievement.go b/network/mhfpacket/msg_mhf_get_achievement.go index afa49d0d4..bca41bb7b 100644 --- a/network/mhfpacket/msg_mhf_get_achievement.go +++ b/network/mhfpacket/msg_mhf_get_achievement.go @@ -12,7 +12,6 @@ import ( type MsgMhfGetAchievement struct { AckHandle uint32 CharID uint32 - Unk1 uint32 // char? } // Opcode returns the ID associated with this packet type. @@ -24,7 +23,7 @@ func (m *MsgMhfGetAchievement) Opcode() network.PacketID { func (m *MsgMhfGetAchievement) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.CharID = bf.ReadUint32() - m.Unk1 = bf.ReadUint32() + bf.ReadUint32() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_get_rengoku_binary.go b/network/mhfpacket/msg_mhf_get_rengoku_binary.go index fc43a3718..f7dda97ad 100644 --- a/network/mhfpacket/msg_mhf_get_rengoku_binary.go +++ b/network/mhfpacket/msg_mhf_get_rengoku_binary.go @@ -1,17 +1,16 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfGetRengokuBinary represents the MSG_MHF_GET_RENGOKU_BINARY type MsgMhfGetRengokuBinary struct { AckHandle uint32 - Unk0 uint8 // Hardcoded 0 in binary } // Opcode returns the ID associated with this packet type. @@ -22,7 +21,7 @@ func (m *MsgMhfGetRengokuBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetRengokuBinary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_info_festa.go b/network/mhfpacket/msg_mhf_info_festa.go index 6926f0b8d..0877e6a4c 100644 --- a/network/mhfpacket/msg_mhf_info_festa.go +++ b/network/mhfpacket/msg_mhf_info_festa.go @@ -1,18 +1,17 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfInfoFesta represents the MSG_MHF_INFO_FESTA type MsgMhfInfoFesta struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 0 in the binary - Unk1 uint16 // Hardcoded 0 in the binary + Unk0 uint8 } // Opcode returns the ID associated with this packet type. @@ -23,8 +22,10 @@ func (m *MsgMhfInfoFesta) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfInfoFesta) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + m.Unk0 = bf.ReadUint8() + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_list_member.go b/network/mhfpacket/msg_mhf_list_member.go index 0eaf4ca5f..bee4a4874 100644 --- a/network/mhfpacket/msg_mhf_list_member.go +++ b/network/mhfpacket/msg_mhf_list_member.go @@ -1,17 +1,17 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfListMember represents the MSG_MHF_LIST_MEMBER type MsgMhfListMember struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 01 00 in the JP client. + Unk0 uint8 // Hardcoded 01 in the JP client. } // Opcode returns the ID associated with this packet type. @@ -22,7 +22,8 @@ func (m *MsgMhfListMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfListMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() + m.Unk0 = bf.ReadUint8() + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_read_mail.go b/network/mhfpacket/msg_mhf_read_mail.go index 1d2b03cf5..957f144f9 100644 --- a/network/mhfpacket/msg_mhf_read_mail.go +++ b/network/mhfpacket/msg_mhf_read_mail.go @@ -19,7 +19,6 @@ type MsgMhfReadMail struct { // This is the index within the current mail list Index uint8 - Unk0 uint16 } // Opcode returns the ID associated with this packet type. @@ -32,7 +31,7 @@ func (m *MsgMhfReadMail) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCon m.AckHandle = bf.ReadUint32() m.AccIndex = bf.ReadUint8() m.Index = bf.ReadUint8() - m.Unk0 = bf.ReadUint16() + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_release_event.go b/network/mhfpacket/msg_mhf_release_event.go index 52178279b..20ebcdba0 100644 --- a/network/mhfpacket/msg_mhf_release_event.go +++ b/network/mhfpacket/msg_mhf_release_event.go @@ -12,7 +12,6 @@ import ( type MsgMhfReleaseEvent struct { AckHandle uint32 RaviID uint32 - Unk1 uint32 } // Opcode returns the ID associated with this packet type. @@ -24,7 +23,7 @@ func (m *MsgMhfReleaseEvent) Opcode() network.PacketID { func (m *MsgMhfReleaseEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.RaviID = bf.ReadUint32() - m.Unk1 = bf.ReadUint32() + bf.ReadUint32() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_update_cafepoint.go b/network/mhfpacket/msg_mhf_update_cafepoint.go index 671e893aa..aea9a43aa 100644 --- a/network/mhfpacket/msg_mhf_update_cafepoint.go +++ b/network/mhfpacket/msg_mhf_update_cafepoint.go @@ -1,18 +1,16 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfUpdateCafepoint represents the MSG_MHF_UPDATE_CAFEPOINT type MsgMhfUpdateCafepoint struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 0 in binary - Unk1 uint16 // Hardcoded 0 in binary } // Opcode returns the ID associated with this packet type. @@ -23,8 +21,8 @@ func (m *MsgMhfUpdateCafepoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUpdateCafepoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_update_guacot.go b/network/mhfpacket/msg_mhf_update_guacot.go index 433854ae3..685f66f1b 100644 --- a/network/mhfpacket/msg_mhf_update_guacot.go +++ b/network/mhfpacket/msg_mhf_update_guacot.go @@ -30,7 +30,7 @@ func (m *MsgMhfUpdateGuacot) Opcode() network.PacketID { func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.EntryCount = bf.ReadUint16() - _ = bf.ReadUint16() // Zero + bf.ReadUint16() // Zeroed var temp Goocoo for i := 0; i < int(m.EntryCount); i++ { temp.Index = bf.ReadUint32() diff --git a/network/mhfpacket/msg_mhf_update_guild_icon.go b/network/mhfpacket/msg_mhf_update_guild_icon.go index 6e3a780e5..248bb93ea 100644 --- a/network/mhfpacket/msg_mhf_update_guild_icon.go +++ b/network/mhfpacket/msg_mhf_update_guild_icon.go @@ -25,8 +25,6 @@ type GuildIconMsgPart struct { type MsgMhfUpdateGuildIcon struct { AckHandle uint32 GuildID uint32 - PartCount uint16 - Unk1 uint16 IconParts []GuildIconMsgPart } @@ -39,12 +37,12 @@ func (m *MsgMhfUpdateGuildIcon) Opcode() network.PacketID { func (m *MsgMhfUpdateGuildIcon) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.GuildID = bf.ReadUint32() - m.PartCount = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + partCount := int(bf.ReadUint16()) + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + m.IconParts = make([]GuildIconMsgPart, partCount) - m.IconParts = make([]GuildIconMsgPart, m.PartCount) - - for i := 0; i < int(m.PartCount); i++ { + for i := 0; i < partCount; i++ { m.IconParts[i] = GuildIconMsgPart{ Index: bf.ReadUint16(), ID: bf.ReadUint16(), diff --git a/network/mhfpacket/msg_mhf_update_guild_item.go b/network/mhfpacket/msg_mhf_update_guild_item.go index 3eb37a8cb..dbea591ea 100644 --- a/network/mhfpacket/msg_mhf_update_guild_item.go +++ b/network/mhfpacket/msg_mhf_update_guild_item.go @@ -10,7 +10,7 @@ import ( type Item struct { Unk0 uint32 - ItemId uint16 + ItemID uint16 Amount uint16 Unk1 uint32 } @@ -19,9 +19,7 @@ type Item struct { type MsgMhfUpdateGuildItem struct { AckHandle uint32 GuildId uint32 - Amount uint16 - Unk1 uint16 // 0x00 0x00 - Items []Item // Array of updated item IDs + Items []Item } // Opcode returns the ID associated with this packet type. @@ -33,13 +31,14 @@ func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID { func (m *MsgMhfUpdateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.GuildId = bf.ReadUint32() - m.Amount = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() - m.Items = make([]Item, int(m.Amount)) + itemCount := int(bf.ReadUint16()) + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + m.Items = make([]Item, itemCount) - for i := 0; i < int(m.Amount); i++ { + for i := 0; i < itemCount; i++ { m.Items[i].Unk0 = bf.ReadUint32() - m.Items[i].ItemId = bf.ReadUint16() + m.Items[i].ItemID = bf.ReadUint16() m.Items[i].Amount = bf.ReadUint16() m.Items[i].Unk1 = bf.ReadUint32() } diff --git a/network/mhfpacket/msg_mhf_update_house.go b/network/mhfpacket/msg_mhf_update_house.go index 320972673..2c6f0401d 100644 --- a/network/mhfpacket/msg_mhf_update_house.go +++ b/network/mhfpacket/msg_mhf_update_house.go @@ -13,8 +13,7 @@ import ( type MsgMhfUpdateHouse struct { AckHandle uint32 State uint8 - Unk1 uint8 // Always 0x01 - Unk2 uint16 // Always 0x0000 + Unk1 uint8 // Always 0x01 Password string } @@ -28,8 +27,9 @@ func (m *MsgMhfUpdateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client m.AckHandle = bf.ReadUint32() m.State = bf.ReadUint8() m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() - _ = bf.ReadUint8() // Password length + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Password length m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_mhf_update_union_item.go b/network/mhfpacket/msg_mhf_update_union_item.go index 5e4d83d24..68e8de365 100644 --- a/network/mhfpacket/msg_mhf_update_union_item.go +++ b/network/mhfpacket/msg_mhf_update_union_item.go @@ -11,9 +11,7 @@ import ( // MsgMhfUpdateUnionItem represents the MSG_MHF_UPDATE_UNION_ITEM type MsgMhfUpdateUnionItem struct { AckHandle uint32 - Amount uint16 - Unk1 uint16 // 0x00 0x00 - Items []Item // Array of updated item IDs + Items []Item } // Opcode returns the ID associated with this packet type. @@ -24,13 +22,14 @@ func (m *MsgMhfUpdateUnionItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUpdateUnionItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Amount = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() - m.Items = make([]Item, int(m.Amount)) + itemCount := int(bf.ReadUint16()) + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + m.Items = make([]Item, itemCount) - for i := 0; i < int(m.Amount); i++ { + for i := 0; i < itemCount; i++ { m.Items[i].Unk0 = bf.ReadUint32() - m.Items[i].ItemId = bf.ReadUint16() + m.Items[i].ItemID = bf.ReadUint16() m.Items[i].Amount = bf.ReadUint16() m.Items[i].Unk1 = bf.ReadUint32() } diff --git a/network/mhfpacket/msg_sys_get_file.go b/network/mhfpacket/msg_sys_get_file.go index 41b2a9029..99af6aa5e 100644 --- a/network/mhfpacket/msg_sys_get_file.go +++ b/network/mhfpacket/msg_sys_get_file.go @@ -4,9 +4,9 @@ import ( "errors" "erupe-ce/common/bfutil" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) type scenarioFileIdentifer struct { diff --git a/network/mhfpacket/msg_sys_hide_client.go b/network/mhfpacket/msg_sys_hide_client.go index e01c22cab..a2c714a41 100644 --- a/network/mhfpacket/msg_sys_hide_client.go +++ b/network/mhfpacket/msg_sys_hide_client.go @@ -1,18 +1,16 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysHideClient represents the MSG_SYS_HIDE_CLIENT type MsgSysHideClient struct { Hide bool - Unk0 uint16 // Hardcoded 0 in binary - Unk1 uint8 // Hardcoded 0 in binary } // Opcode returns the ID associated with this packet type. @@ -23,8 +21,9 @@ func (m *MsgSysHideClient) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysHideClient) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.Hide = bf.ReadBool() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint8() + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_sys_issue_logkey.go b/network/mhfpacket/msg_sys_issue_logkey.go index a22956186..d5bb6522d 100644 --- a/network/mhfpacket/msg_sys_issue_logkey.go +++ b/network/mhfpacket/msg_sys_issue_logkey.go @@ -1,18 +1,17 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysIssueLogkey represents the MSG_SYS_ISSUE_LOGKEY type MsgSysIssueLogkey struct { AckHandle uint32 - Unk0 uint16 // Hardcoded 00 01 in binary - Unk1 uint16 // Hardcoded 0 in binary. + Unk0 uint16 } // Opcode returns the ID associated with this packet type. @@ -24,7 +23,7 @@ func (m *MsgSysIssueLogkey) Opcode() network.PacketID { func (m *MsgSysIssueLogkey) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_sys_rights_reload.go b/network/mhfpacket/msg_sys_rights_reload.go index 7a8ac06e0..a70be8f38 100644 --- a/network/mhfpacket/msg_sys_rights_reload.go +++ b/network/mhfpacket/msg_sys_rights_reload.go @@ -1,17 +1,17 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysRightsReload represents the MSG_SYS_RIGHTS_RELOAD -type MsgSysRightsReload struct{ +type MsgSysRightsReload struct { AckHandle uint32 - Unk0 byte + Unk0 []byte } // Opcode returns the ID associated with this packet type. @@ -22,7 +22,7 @@ func (m *MsgSysRightsReload) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysRightsReload) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() + m.Unk0 = bf.ReadBytes(uint(bf.ReadUint8())) return nil } diff --git a/network/mhfpacket/msg_sys_set_stage_pass.go b/network/mhfpacket/msg_sys_set_stage_pass.go index 5cdbb2b88..1461241b0 100644 --- a/network/mhfpacket/msg_sys_set_stage_pass.go +++ b/network/mhfpacket/msg_sys_set_stage_pass.go @@ -1,17 +1,16 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysSetStagePass represents the MSG_SYS_SET_STAGE_PASS type MsgSysSetStagePass struct { - Unk0 uint8 // Hardcoded 0 in the binary - Password string // NULL-terminated string + Password string // NULL-terminated string } // Opcode returns the ID associated with this packet type. @@ -21,8 +20,8 @@ func (m *MsgSysSetStagePass) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysSetStagePass) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.Unk0 = bf.ReadUint8() - _ = bf.ReadUint8() // Password length + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Password length m.Password = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_terminal_log.go b/network/mhfpacket/msg_sys_terminal_log.go index bc8f3f7c5..5033346b4 100644 --- a/network/mhfpacket/msg_sys_terminal_log.go +++ b/network/mhfpacket/msg_sys_terminal_log.go @@ -23,11 +23,9 @@ type TerminalLogEntry struct { // MsgSysTerminalLog represents the MSG_SYS_TERMINAL_LOG type MsgSysTerminalLog struct { - AckHandle uint32 - LogID uint32 // 0 on the first packet, and the server sends back a value to use for subsequent requests. - EntryCount uint16 - Unk0 uint16 // Hardcoded 0 in the binary - Entries []*TerminalLogEntry + AckHandle uint32 + LogID uint32 // 0 on the first packet, and the server sends back a value to use for subsequent requests. + Entries []TerminalLogEntry } // Opcode returns the ID associated with this packet type. @@ -39,11 +37,11 @@ func (m *MsgSysTerminalLog) Opcode() network.PacketID { func (m *MsgSysTerminalLog) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.LogID = bf.ReadUint32() - m.EntryCount = bf.ReadUint16() - m.Unk0 = bf.ReadUint16() + entryCount := int(bf.ReadUint16()) + bf.ReadUint16() // Zeroed - for i := 0; i < int(m.EntryCount); i++ { - e := &TerminalLogEntry{} + var e TerminalLogEntry + for i := 0; i < entryCount; i++ { e.Index = bf.ReadUint32() e.Type1 = bf.ReadUint8() e.Type2 = bf.ReadUint8() diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 211fcaf79..057881723 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -705,16 +705,16 @@ func handleMsgMhfUpdateUnionItem(s *Session, p mhfpacket.MHFPacket) { // Update item stacks newItems := make([]Item, len(oldItems)) copy(newItems, oldItems) - for i := 0; i < int(pkt.Amount); i++ { + for i := 0; i < len(pkt.Items); i++ { for j := 0; j <= len(oldItems); j++ { if j == len(oldItems) { var newItem Item - newItem.ItemId = pkt.Items[i].ItemId + newItem.ItemId = pkt.Items[i].ItemID newItem.Amount = pkt.Items[i].Amount newItems = append(newItems, newItem) break } - if pkt.Items[i].ItemId == oldItems[j].ItemId { + if pkt.Items[i].ItemID == oldItems[j].ItemId { newItems[j].Amount = pkt.Items[i].Amount break } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index b8c7c04f6..cf190aa45 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1609,16 +1609,16 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) { // Update item stacks newItems := make([]Item, len(oldItems)) copy(newItems, oldItems) - for i := 0; i < int(pkt.Amount); i++ { + for i := 0; i < len(pkt.Items); i++ { for j := 0; j <= len(oldItems); j++ { if j == len(oldItems) { var newItem Item - newItem.ItemId = pkt.Items[i].ItemId + newItem.ItemId = pkt.Items[i].ItemID newItem.Amount = pkt.Items[i].Amount newItems = append(newItems, newItem) break } - if pkt.Items[i].ItemId == oldItems[j].ItemId { + if pkt.Items[i].ItemID == oldItems[j].ItemId { newItems[j].Amount = pkt.Items[i].Amount break } @@ -1677,7 +1677,7 @@ func handleMsgMhfUpdateGuildIcon(s *Session, p mhfpacket.MHFPacket) { icon := &GuildIcon{} - icon.Parts = make([]GuildIconPart, pkt.PartCount) + icon.Parts = make([]GuildIconPart, len(pkt.IconParts)) for i, p := range pkt.IconParts { icon.Parts[i] = GuildIconPart{ diff --git a/server/channelserver/handlers_house.go b/server/channelserver/handlers_house.go index f764a8fa1..9dc51995d 100644 --- a/server/channelserver/handlers_house.go +++ b/server/channelserver/handlers_house.go @@ -355,12 +355,14 @@ func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAcquireTitle) - var exists int - err := s.server.db.QueryRow(`SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2`, pkt.TitleID, s.charID).Scan(&exists) - if err != nil || exists == 0 { - s.server.db.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, pkt.TitleID, s.charID) - } else { - s.server.db.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, pkt.TitleID, s.charID) + for _, title := range pkt.TitleIDs { + var exists int + err := s.server.db.QueryRow(`SELECT count(*) FROM titles WHERE id=$1 AND char_id=$2`, title, s.charID).Scan(&exists) + if err != nil || exists == 0 { + s.server.db.Exec(`INSERT INTO titles VALUES ($1, $2, now(), now())`, title, s.charID) + } else { + s.server.db.Exec(`UPDATE titles SET updated_at=now() WHERE id=$1 AND char_id=$2`, title, s.charID) + } } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } From 85fc76edd5f977c176497202cbc48cf5999cf67b Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 02:34:02 +1100 Subject: [PATCH 87/96] update parsing of many packets --- network/mhfpacket/msg_mhf_acquire_festa.go | 25 +++---- .../mhfpacket/msg_mhf_acquire_monthly_item.go | 13 ++-- network/mhfpacket/msg_mhf_announce.go | 5 +- .../mhfpacket/msg_mhf_arrange_guild_member.go | 19 ++---- network/mhfpacket/msg_mhf_create_joint.go | 25 +++---- network/mhfpacket/msg_mhf_entry_festa.go | 22 +++--- .../msg_mhf_enumerate_festa_member.go | 18 ++--- network/mhfpacket/msg_mhf_enumerate_guacot.go | 5 +- network/mhfpacket/msg_mhf_enumerate_guild.go | 18 +++-- .../mhfpacket/msg_mhf_enumerate_guild_item.go | 16 ++--- .../msg_mhf_enumerate_guild_member.go | 21 +++--- network/mhfpacket/msg_mhf_enumerate_house.go | 3 +- .../mhfpacket/msg_mhf_enumerate_inv_guild.go | 16 ++++- .../msg_mhf_exchange_weekly_stamp.go | 3 +- network/mhfpacket/msg_mhf_info_joint.go | 3 +- .../mhfpacket/msg_mhf_load_guild_cooking.go | 14 ++-- network/mhfpacket/msg_mhf_load_house.go | 5 +- .../mhfpacket/msg_mhf_operate_guild_member.go | 4 +- network/mhfpacket/msg_mhf_operate_joint.go | 8 ++- network/mhfpacket/msg_mhf_opr_member.go | 31 +++++---- network/mhfpacket/msg_mhf_register_event.go | 7 +- .../msg_mhf_set_guild_manage_right.go | 3 +- network/mhfpacket/msg_mhf_stampcard_stamp.go | 2 +- network/mhfpacket/msg_mhf_state_festa_g.go | 12 ++-- network/mhfpacket/msg_mhf_state_festa_u.go | 22 +++--- network/mhfpacket/msg_mhf_transfer_item.go | 15 +++-- network/mhfpacket/msg_mhf_transit_message.go | 3 +- .../mhfpacket/msg_mhf_update_guild_item.go | 4 +- network/mhfpacket/msg_mhf_use_gacha_point.go | 22 +++--- network/mhfpacket/msg_mhf_vote_festa.go | 4 +- .../msg_sys_create_acquire_semaphore.go | 5 +- network/mhfpacket/msg_sys_create_semaphore.go | 16 +++-- network/mhfpacket/msg_sys_enumerate_client.go | 5 +- network/mhfpacket/msg_sys_get_stage_binary.go | 5 +- network/mhfpacket/msg_sys_load_register.go | 4 +- network/mhfpacket/msg_sys_login.go | 26 ++++--- network/mhfpacket/msg_sys_operate_register.go | 2 +- network/mhfpacket/msg_sys_set_stage_binary.go | 7 +- .../mhfpacket/msg_sys_wait_stage_binary.go | 5 +- server/channelserver/handlers.go | 2 +- server/channelserver/handlers_clients.go | 67 +++++++++---------- server/channelserver/handlers_guild.go | 33 +++++---- .../channelserver/handlers_guild_alliance.go | 3 +- server/channelserver/handlers_register.go | 2 +- 44 files changed, 272 insertions(+), 278 deletions(-) diff --git a/network/mhfpacket/msg_mhf_acquire_festa.go b/network/mhfpacket/msg_mhf_acquire_festa.go index 30e75d7a4..87cf758f0 100644 --- a/network/mhfpacket/msg_mhf_acquire_festa.go +++ b/network/mhfpacket/msg_mhf_acquire_festa.go @@ -1,19 +1,19 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfAcquireFesta represents the MSG_MHF_ACQUIRE_FESTA type MsgMhfAcquireFesta struct { - AckHandle uint32 - FestaID uint32 - GuildID uint32 - Unk uint16 + AckHandle uint32 + FestaID uint32 + GuildID uint32 + Unk uint8 } // Opcode returns the ID associated with this packet type. @@ -23,11 +23,12 @@ func (m *MsgMhfAcquireFesta) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfAcquireFesta) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.FestaID = bf.ReadUint32() - m.GuildID = bf.ReadUint32() - m.Unk = bf.ReadUint16() - return nil + m.AckHandle = bf.ReadUint32() + m.FestaID = bf.ReadUint32() + m.GuildID = bf.ReadUint32() + m.Unk = bf.ReadUint8() + bf.ReadUint8() // Zeroed + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_acquire_monthly_item.go b/network/mhfpacket/msg_mhf_acquire_monthly_item.go index acc10b42a..d64288f9f 100644 --- a/network/mhfpacket/msg_mhf_acquire_monthly_item.go +++ b/network/mhfpacket/msg_mhf_acquire_monthly_item.go @@ -11,9 +11,9 @@ import ( // MsgMhfAcquireMonthlyItem represents the MSG_MHF_ACQUIRE_MONTHLY_ITEM type MsgMhfAcquireMonthlyItem struct { AckHandle uint32 - Unk0 uint16 - Unk1 uint16 - Unk2 uint32 + Unk0 uint8 + Unk1 uint8 + Unk2 uint16 Unk3 uint32 } @@ -25,10 +25,11 @@ func (m *MsgMhfAcquireMonthlyItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfAcquireMonthlyItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() - m.Unk2 = bf.ReadUint32() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.Unk2 = bf.ReadUint16() m.Unk3 = bf.ReadUint32() + bf.ReadUint32() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_announce.go b/network/mhfpacket/msg_mhf_announce.go index c4c9deb7f..2b1d9ea76 100644 --- a/network/mhfpacket/msg_mhf_announce.go +++ b/network/mhfpacket/msg_mhf_announce.go @@ -14,7 +14,7 @@ type MsgMhfAnnounce struct { IPAddress uint32 Port uint16 StageID []byte - Type uint8 + Data *byteframe.ByteFrame } // Opcode returns the ID associated with this packet type. @@ -31,8 +31,7 @@ func (m *MsgMhfAnnounce) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCon _ = bf.ReadUint8() _ = bf.ReadUint8() m.StageID = bf.ReadBytes(32) - _ = bf.ReadUint32() - m.Type = bf.ReadUint8() + m.Data = byteframe.NewByteFrameFromBytes(bf.ReadBytes(uint(bf.ReadUint32()))) return nil } diff --git a/network/mhfpacket/msg_mhf_arrange_guild_member.go b/network/mhfpacket/msg_mhf_arrange_guild_member.go index 3bd4e73f0..066735a10 100644 --- a/network/mhfpacket/msg_mhf_arrange_guild_member.go +++ b/network/mhfpacket/msg_mhf_arrange_guild_member.go @@ -1,9 +1,10 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfArrangeGuildMember represents the MSG_MHF_ARRANGE_GUILD_MEMBER @@ -22,11 +23,11 @@ func (m *MsgMhfArrangeGuildMember) Opcode() network.PacketID { func (m *MsgMhfArrangeGuildMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.GuildID = bf.ReadUint32() - charCount := bf.ReadUint16() - + bf.ReadUint8() // Zeroed + charCount := int(bf.ReadUint8()) m.CharIDs = make([]uint32, charCount) - for i := uint16(0); i < charCount; i++ { + for i := 0; i < charCount; i++ { m.CharIDs[i] = bf.ReadUint32() } @@ -35,13 +36,5 @@ func (m *MsgMhfArrangeGuildMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx // Build builds a binary packet from the current data. func (m *MsgMhfArrangeGuildMember) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint32(m.GuildID) - bf.WriteUint16(uint16(len(m.CharIDs))) - - for _, charID := range m.CharIDs { - bf.WriteUint32(charID) - } - - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_create_joint.go b/network/mhfpacket/msg_mhf_create_joint.go index 1a969fc4a..5a9a9f5fd 100644 --- a/network/mhfpacket/msg_mhf_create_joint.go +++ b/network/mhfpacket/msg_mhf_create_joint.go @@ -1,19 +1,19 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/common/stringsupport" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/common/stringsupport" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfCreateJoint represents the MSG_MHF_CREATE_JOINT type MsgMhfCreateJoint struct { - AckHandle uint32 - GuildID uint32 - Name string + AckHandle uint32 + GuildID uint32 + Name string } // Opcode returns the ID associated with this packet type. @@ -23,11 +23,12 @@ func (m *MsgMhfCreateJoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfCreateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.GuildID = bf.ReadUint32() - _ = bf.ReadUint32() // len - m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) - return nil + m.AckHandle = bf.ReadUint32() + m.GuildID = bf.ReadUint32() + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Name length + m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_entry_festa.go b/network/mhfpacket/msg_mhf_entry_festa.go index 9572cede6..de46b2d0e 100644 --- a/network/mhfpacket/msg_mhf_entry_festa.go +++ b/network/mhfpacket/msg_mhf_entry_festa.go @@ -1,18 +1,18 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEntryFesta represents the MSG_MHF_ENTRY_FESTA type MsgMhfEntryFesta struct { - AckHandle uint32 - FestaID uint32 - GuildID uint32 + AckHandle uint32 + FestaID uint32 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -22,11 +22,11 @@ func (m *MsgMhfEntryFesta) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEntryFesta) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.FestaID = bf.ReadUint32() - m.GuildID = bf.ReadUint32() - _ = bf.ReadUint16() // Always 0 - return nil + m.AckHandle = bf.ReadUint32() + m.FestaID = bf.ReadUint32() + m.GuildID = bf.ReadUint32() + bf.ReadUint16() // Zeroed + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_enumerate_festa_member.go b/network/mhfpacket/msg_mhf_enumerate_festa_member.go index f0b5cc478..4b90589a9 100644 --- a/network/mhfpacket/msg_mhf_enumerate_festa_member.go +++ b/network/mhfpacket/msg_mhf_enumerate_festa_member.go @@ -1,18 +1,18 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumerateFestaMember represents the MSG_MHF_ENUMERATE_FESTA_MEMBER type MsgMhfEnumerateFestaMember struct { - AckHandle uint32 - FestaID uint32 - GuildID uint32 + AckHandle uint32 + FestaID uint32 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -22,11 +22,11 @@ func (m *MsgMhfEnumerateFestaMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateFestaMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() + m.AckHandle = bf.ReadUint32() m.FestaID = bf.ReadUint32() m.GuildID = bf.ReadUint32() - _ = bf.ReadUint16() // Hardcoded 0 in the binary. - return nil + bf.ReadUint16() // Zeroed + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_enumerate_guacot.go b/network/mhfpacket/msg_mhf_enumerate_guacot.go index 2f970f938..71cae7adf 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guacot.go +++ b/network/mhfpacket/msg_mhf_enumerate_guacot.go @@ -10,8 +10,7 @@ import ( // MsgMhfEnumerateGuacot represents the MSG_MHF_ENUMERATE_GUACOT type MsgMhfEnumerateGuacot struct { AckHandle uint32 - Unk0 uint32 // Hardcoded 0 in binary - Unk1 uint16 // Hardcoded 0 in binary + Unk0 uint32 } // Opcode returns the ID associated with this packet type. @@ -23,7 +22,7 @@ func (m *MsgMhfEnumerateGuacot) Opcode() network.PacketID { func (m *MsgMhfEnumerateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint32() - m.Unk1 = bf.ReadUint16() + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_guild.go b/network/mhfpacket/msg_mhf_enumerate_guild.go index f90a7cc7b..61ead7870 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild.go @@ -2,9 +2,7 @@ package mhfpacket import ( "errors" - "erupe-ce/common/bfutil" "erupe-ce/common/byteframe" - "erupe-ce/common/stringsupport" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -34,8 +32,8 @@ type MsgMhfEnumerateGuild struct { Type EnumerateGuildType Page uint8 Sorting bool - Data1 []byte - Data2 string + Data1 *byteframe.ByteFrame + Data2 *byteframe.ByteFrame } // Opcode returns the ID associated with this packet type. @@ -49,12 +47,12 @@ func (m *MsgMhfEnumerateGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.Type = EnumerateGuildType(bf.ReadUint8()) m.Page = bf.ReadUint8() m.Sorting = bf.ReadBool() - _ = bf.ReadBytes(1) - m.Data1 = bf.ReadBytes(4) - _ = bf.ReadBytes(2) - lenData2 := uint(bf.ReadUint8()) - _ = bf.ReadBytes(1) - m.Data2 = stringsupport.SJISToUTF8(bfutil.UpToNull(bf.ReadBytes(lenData2))) + bf.ReadUint8() // Zeroed + m.Data1 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(4)) + bf.ReadUint16() // Zeroed + dataLen := uint(bf.ReadUint8()) + bf.ReadUint8() // Zeroed + m.Data2 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(dataLen)) return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_guild_item.go b/network/mhfpacket/msg_mhf_enumerate_guild_item.go index 4f538ca5d..6d3516371 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild_item.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild_item.go @@ -1,18 +1,17 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumerateGuildItem represents the MSG_MHF_ENUMERATE_GUILD_ITEM type MsgMhfEnumerateGuildItem struct { AckHandle uint32 - GuildId uint32 - Unk0 uint16 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -22,9 +21,10 @@ func (m *MsgMhfEnumerateGuildItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.GuildId = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() + m.AckHandle = bf.ReadUint32() + m.GuildID = bf.ReadUint32() + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_enumerate_guild_member.go b/network/mhfpacket/msg_mhf_enumerate_guild_member.go index f15de35f6..e90c431f2 100644 --- a/network/mhfpacket/msg_mhf_enumerate_guild_member.go +++ b/network/mhfpacket/msg_mhf_enumerate_guild_member.go @@ -1,17 +1,17 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgMhfEnumerateGuildMember represents the MSG_MHF_ENUMERATE_GUILD_MEMBER type MsgMhfEnumerateGuildMember struct { - AckHandle uint32 - Unk0 uint16 // Hardcoded 00 01 in the binary - Unk1 uint32 // Alliance related - GuildID uint32 + AckHandle uint32 + AllianceID uint32 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -22,17 +22,14 @@ func (m *MsgMhfEnumerateGuildMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateGuildMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint32() + bf.ReadUint8() // Zeroed + bf.ReadUint8() // Always 1 + m.AllianceID = bf.ReadUint32() m.GuildID = bf.ReadUint32() return nil } // Build builds a binary packet from the current data. func (m *MsgMhfEnumerateGuildMember) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint32(m.AckHandle) - bf.WriteUint16(m.Unk0) - bf.WriteUint32(m.Unk1) - bf.WriteUint32(m.GuildID) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/network/mhfpacket/msg_mhf_enumerate_house.go b/network/mhfpacket/msg_mhf_enumerate_house.go index da6a25de7..41f57323a 100644 --- a/network/mhfpacket/msg_mhf_enumerate_house.go +++ b/network/mhfpacket/msg_mhf_enumerate_house.go @@ -14,7 +14,6 @@ type MsgMhfEnumerateHouse struct { AckHandle uint32 CharID uint32 Method uint8 - Unk uint16 Name string } @@ -28,7 +27,7 @@ func (m *MsgMhfEnumerateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.AckHandle = bf.ReadUint32() m.CharID = bf.ReadUint32() m.Method = bf.ReadUint8() - m.Unk = bf.ReadUint16() + bf.ReadUint16() // Zeroed lenName := bf.ReadUint8() if lenName > 0 { m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) diff --git a/network/mhfpacket/msg_mhf_enumerate_inv_guild.go b/network/mhfpacket/msg_mhf_enumerate_inv_guild.go index cf2057bed..994c374d8 100644 --- a/network/mhfpacket/msg_mhf_enumerate_inv_guild.go +++ b/network/mhfpacket/msg_mhf_enumerate_inv_guild.go @@ -10,8 +10,13 @@ import ( // MsgMhfEnumerateInvGuild represents the MSG_MHF_ENUMERATE_INV_GUILD type MsgMhfEnumerateInvGuild struct { - AckHandle uint32 - Unk []byte + AckHandle uint32 + Unk uint32 + Operation uint8 + ActiveHours uint8 + DaysActive uint8 + PlayStyle uint8 + GuildRequest uint8 } // Opcode returns the ID associated with this packet type. @@ -22,7 +27,12 @@ func (m *MsgMhfEnumerateInvGuild) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateInvGuild) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk = bf.ReadBytes(9) + m.Unk = bf.ReadUint32() + m.Operation = bf.ReadUint8() + m.ActiveHours = bf.ReadUint8() + m.DaysActive = bf.ReadUint8() + m.PlayStyle = bf.ReadUint8() + m.GuildRequest = bf.ReadUint8() return nil } diff --git a/network/mhfpacket/msg_mhf_exchange_weekly_stamp.go b/network/mhfpacket/msg_mhf_exchange_weekly_stamp.go index 918a870ac..829bb6fb2 100644 --- a/network/mhfpacket/msg_mhf_exchange_weekly_stamp.go +++ b/network/mhfpacket/msg_mhf_exchange_weekly_stamp.go @@ -13,7 +13,6 @@ type MsgMhfExchangeWeeklyStamp struct { AckHandle uint32 StampType string Unk1 uint8 - Unk2 uint16 } // Opcode returns the ID associated with this packet type. @@ -32,7 +31,7 @@ func (m *MsgMhfExchangeWeeklyStamp) Parse(bf *byteframe.ByteFrame, ctx *clientct m.StampType = "ex" } m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint16() + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_info_joint.go b/network/mhfpacket/msg_mhf_info_joint.go index 17e468c7c..c349c9768 100644 --- a/network/mhfpacket/msg_mhf_info_joint.go +++ b/network/mhfpacket/msg_mhf_info_joint.go @@ -12,7 +12,6 @@ import ( type MsgMhfInfoJoint struct { AckHandle uint32 AllianceID uint32 - Unk uint32 } // Opcode returns the ID associated with this packet type. @@ -24,7 +23,7 @@ func (m *MsgMhfInfoJoint) Opcode() network.PacketID { func (m *MsgMhfInfoJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.AllianceID = bf.ReadUint32() - m.Unk = bf.ReadUint32() + bf.ReadUint32() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_load_guild_cooking.go b/network/mhfpacket/msg_mhf_load_guild_cooking.go index 515187bc2..0e293c073 100644 --- a/network/mhfpacket/msg_mhf_load_guild_cooking.go +++ b/network/mhfpacket/msg_mhf_load_guild_cooking.go @@ -1,17 +1,17 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfLoadGuildCooking represents the MSG_MHF_LOAD_GUILD_COOKING -type MsgMhfLoadGuildCooking struct{ - AckHandle uint32 - MaxMeals uint8 +type MsgMhfLoadGuildCooking struct { + AckHandle uint32 + MaxMeals uint8 } // Opcode returns the ID associated with this packet type. @@ -22,7 +22,7 @@ func (m *MsgMhfLoadGuildCooking) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfLoadGuildCooking) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - _ = bf.ReadUint8() + m.MaxMeals = bf.ReadUint8() return nil } diff --git a/network/mhfpacket/msg_mhf_load_house.go b/network/mhfpacket/msg_mhf_load_house.go index a012b2f1c..138c8af22 100644 --- a/network/mhfpacket/msg_mhf_load_house.go +++ b/network/mhfpacket/msg_mhf_load_house.go @@ -16,7 +16,6 @@ type MsgMhfLoadHouse struct { Destination uint8 // False if already in hosts My Series, in case host updates PW CheckPass bool - Unk3 uint16 // Hardcoded 0 in binary Password string } @@ -31,8 +30,8 @@ func (m *MsgMhfLoadHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCo m.CharID = bf.ReadUint32() m.Destination = bf.ReadUint8() m.CheckPass = bf.ReadBool() - _ = bf.ReadUint16() - _ = bf.ReadUint8() // Password length + bf.ReadUint16() // Zeroed + bf.ReadUint8() // Password length m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_mhf_operate_guild_member.go b/network/mhfpacket/msg_mhf_operate_guild_member.go index 7aed7a21d..8daf82dc5 100644 --- a/network/mhfpacket/msg_mhf_operate_guild_member.go +++ b/network/mhfpacket/msg_mhf_operate_guild_member.go @@ -23,7 +23,6 @@ type MsgMhfOperateGuildMember struct { GuildID uint32 CharID uint32 Action uint8 - Unk []byte } // Opcode returns the ID associated with this packet type. @@ -37,7 +36,8 @@ func (m *MsgMhfOperateGuildMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx m.GuildID = bf.ReadUint32() m.CharID = bf.ReadUint32() m.Action = bf.ReadUint8() - m.Unk = bf.ReadBytes(3) + bf.ReadUint8() // Zeroed + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_operate_joint.go b/network/mhfpacket/msg_mhf_operate_joint.go index 1fa360d01..eccb3139d 100644 --- a/network/mhfpacket/msg_mhf_operate_joint.go +++ b/network/mhfpacket/msg_mhf_operate_joint.go @@ -22,7 +22,8 @@ type MsgMhfOperateJoint struct { AllianceID uint32 GuildID uint32 Action OperateJointAction - UnkData *byteframe.ByteFrame + Data1 *byteframe.ByteFrame + Data2 *byteframe.ByteFrame } // Opcode returns the ID associated with this packet type. @@ -36,8 +37,9 @@ func (m *MsgMhfOperateJoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien m.AllianceID = bf.ReadUint32() m.GuildID = bf.ReadUint32() m.Action = OperateJointAction(bf.ReadUint8()) - m.UnkData = byteframe.NewByteFrameFromBytes(bf.DataFromCurrent()) - bf.Seek(int64(len(bf.Data())-2), 0) + dataLen := uint(bf.ReadUint8()) + m.Data1 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(4)) + m.Data2 = byteframe.NewByteFrameFromBytes(bf.ReadBytes(dataLen)) return nil } diff --git a/network/mhfpacket/msg_mhf_opr_member.go b/network/mhfpacket/msg_mhf_opr_member.go index 32641cb39..b0dceaba5 100644 --- a/network/mhfpacket/msg_mhf_opr_member.go +++ b/network/mhfpacket/msg_mhf_opr_member.go @@ -1,20 +1,20 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfOprMember represents the MSG_MHF_OPR_MEMBER type MsgMhfOprMember struct { - AckHandle uint32 - Blacklist bool - Operation bool - Unk uint16 - CharID uint32 + AckHandle uint32 + Blacklist bool + Operation bool + Unk uint16 + CharIDs []uint32 } // Opcode returns the ID associated with this packet type. @@ -24,12 +24,15 @@ func (m *MsgMhfOprMember) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfOprMember) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.Blacklist = bf.ReadBool() - m.Operation = bf.ReadBool() - m.Unk = bf.ReadUint16() - m.CharID = bf.ReadUint32() - return nil + m.AckHandle = bf.ReadUint32() + m.Blacklist = bf.ReadBool() + m.Operation = bf.ReadBool() + bf.ReadUint8() + chars := int(bf.ReadUint8()) + for i := 0; i < chars; i++ { + m.CharIDs = append(m.CharIDs, bf.ReadUint32()) + } + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_register_event.go b/network/mhfpacket/msg_mhf_register_event.go index 956c4a399..46afb1a2e 100644 --- a/network/mhfpacket/msg_mhf_register_event.go +++ b/network/mhfpacket/msg_mhf_register_event.go @@ -12,8 +12,7 @@ type MsgMhfRegisterEvent struct { Unk0 uint16 WorldID uint16 LandID uint16 - Unk3 uint8 - Unk4 uint8 + Unk1 bool } // Opcode returns the ID associated with this packet type. @@ -27,8 +26,8 @@ func (m *MsgMhfRegisterEvent) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clie m.Unk0 = bf.ReadUint16() m.WorldID = bf.ReadUint16() m.LandID = bf.ReadUint16() - m.Unk3 = bf.ReadUint8() - m.Unk4 = bf.ReadUint8() + m.Unk1 = bf.ReadBool() + bf.ReadUint8() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_set_guild_manage_right.go b/network/mhfpacket/msg_mhf_set_guild_manage_right.go index 3feed2654..9eb2d8b21 100644 --- a/network/mhfpacket/msg_mhf_set_guild_manage_right.go +++ b/network/mhfpacket/msg_mhf_set_guild_manage_right.go @@ -13,7 +13,6 @@ type MsgMhfSetGuildManageRight struct { AckHandle uint32 CharID uint32 Allowed bool - Unk []byte } // Opcode returns the ID associated with this packet type. @@ -26,7 +25,7 @@ func (m *MsgMhfSetGuildManageRight) Parse(bf *byteframe.ByteFrame, ctx *clientct m.AckHandle = bf.ReadUint32() m.CharID = bf.ReadUint32() m.Allowed = bf.ReadBool() - m.Unk = bf.ReadBytes(3) + bf.ReadBytes(3) // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_stampcard_stamp.go b/network/mhfpacket/msg_mhf_stampcard_stamp.go index 5ac650ad2..f9da9612e 100644 --- a/network/mhfpacket/msg_mhf_stampcard_stamp.go +++ b/network/mhfpacket/msg_mhf_stampcard_stamp.go @@ -34,7 +34,7 @@ func (m *MsgMhfStampcardStamp) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.HR = bf.ReadUint16() m.GR = bf.ReadUint16() m.Stamps = bf.ReadUint16() - _ = bf.ReadUint16() + bf.ReadUint16() // Zeroed if _config.ErupeConfig.RealClientMode > _config.Z1 { m.Reward1 = uint16(bf.ReadUint32()) m.Reward2 = uint16(bf.ReadUint32()) diff --git a/network/mhfpacket/msg_mhf_state_festa_g.go b/network/mhfpacket/msg_mhf_state_festa_g.go index 86c6526bf..e356b98be 100644 --- a/network/mhfpacket/msg_mhf_state_festa_g.go +++ b/network/mhfpacket/msg_mhf_state_festa_g.go @@ -1,18 +1,18 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfStateFestaG represents the MSG_MHF_STATE_FESTA_G type MsgMhfStateFestaG struct { AckHandle uint32 - FestaID uint32 - GuildID uint32 + FestaID uint32 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -25,7 +25,7 @@ func (m *MsgMhfStateFestaG) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client m.AckHandle = bf.ReadUint32() m.FestaID = bf.ReadUint32() m.GuildID = bf.ReadUint32() - _ = bf.ReadUint16() // Hardcoded 0 in the binary. + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_mhf_state_festa_u.go b/network/mhfpacket/msg_mhf_state_festa_u.go index ef76498bd..013966dba 100644 --- a/network/mhfpacket/msg_mhf_state_festa_u.go +++ b/network/mhfpacket/msg_mhf_state_festa_u.go @@ -1,18 +1,18 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfStateFestaU represents the MSG_MHF_STATE_FESTA_U type MsgMhfStateFestaU struct { - AckHandle uint32 - FestaID uint32 - GuildID uint32 + AckHandle uint32 + FestaID uint32 + GuildID uint32 } // Opcode returns the ID associated with this packet type. @@ -22,11 +22,11 @@ func (m *MsgMhfStateFestaU) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfStateFestaU) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.FestaID = bf.ReadUint32() - m.GuildID = bf.ReadUint32() - _ = bf.ReadUint16() // Hardcoded 0 in the binary. - return nil + m.AckHandle = bf.ReadUint32() + m.FestaID = bf.ReadUint32() + m.GuildID = bf.ReadUint32() + bf.ReadUint16() // Zeroed + return nil } // Build builds a binary packet from the current data. diff --git a/network/mhfpacket/msg_mhf_transfer_item.go b/network/mhfpacket/msg_mhf_transfer_item.go index e3c2cc67c..69dfdb13f 100644 --- a/network/mhfpacket/msg_mhf_transfer_item.go +++ b/network/mhfpacket/msg_mhf_transfer_item.go @@ -1,11 +1,11 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfTransferItem represents the MSG_MHF_TRANSFER_ITEM @@ -15,8 +15,8 @@ type MsgMhfTransferItem struct { // correlate with any item IDs that would make sense to get after quests so // I have no idea what this actually does Unk0 uint32 - Unk1 uint16 // Hardcoded - Unk2 uint16 // Hardcoded + Unk1 uint8 + Unk2 uint16 } // Opcode returns the ID associated with this packet type. @@ -28,7 +28,8 @@ func (m *MsgMhfTransferItem) Opcode() network.PacketID { func (m *MsgMhfTransferItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint32() - m.Unk1 = bf.ReadUint16() + m.Unk1 = bf.ReadUint8() + bf.ReadUint8() // Zeroed m.Unk2 = bf.ReadUint16() return nil } diff --git a/network/mhfpacket/msg_mhf_transit_message.go b/network/mhfpacket/msg_mhf_transit_message.go index 1d15c6d42..1442af08d 100644 --- a/network/mhfpacket/msg_mhf_transit_message.go +++ b/network/mhfpacket/msg_mhf_transit_message.go @@ -12,7 +12,6 @@ import ( type MsgMhfTransitMessage struct { AckHandle uint32 Unk0 uint8 - Unk1 uint8 SearchType uint16 MessageData []byte } @@ -26,7 +25,7 @@ func (m *MsgMhfTransitMessage) Opcode() network.PacketID { func (m *MsgMhfTransitMessage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() + bf.ReadUint8() // Zeroed m.SearchType = bf.ReadUint16() m.MessageData = bf.ReadBytes(uint(bf.ReadUint16())) return nil diff --git a/network/mhfpacket/msg_mhf_update_guild_item.go b/network/mhfpacket/msg_mhf_update_guild_item.go index dbea591ea..ddd7ef6e5 100644 --- a/network/mhfpacket/msg_mhf_update_guild_item.go +++ b/network/mhfpacket/msg_mhf_update_guild_item.go @@ -18,7 +18,7 @@ type Item struct { // MsgMhfUpdateGuildItem represents the MSG_MHF_UPDATE_GUILD_ITEM type MsgMhfUpdateGuildItem struct { AckHandle uint32 - GuildId uint32 + GuildID uint32 Items []Item } @@ -30,7 +30,7 @@ func (m *MsgMhfUpdateGuildItem) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUpdateGuildItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.GuildId = bf.ReadUint32() + m.GuildID = bf.ReadUint32() itemCount := int(bf.ReadUint16()) bf.ReadUint8() // Zeroed bf.ReadUint8() // Zeroed diff --git a/network/mhfpacket/msg_mhf_use_gacha_point.go b/network/mhfpacket/msg_mhf_use_gacha_point.go index 33a4ef143..5245b5eaf 100644 --- a/network/mhfpacket/msg_mhf_use_gacha_point.go +++ b/network/mhfpacket/msg_mhf_use_gacha_point.go @@ -1,19 +1,20 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfUseGachaPoint represents the MSG_MHF_USE_GACHA_POINT -type MsgMhfUseGachaPoint struct{ - AckHandle uint32 - Unk0 uint16 // padding? - TrialCoins uint32 - PremiumCoins uint32 +type MsgMhfUseGachaPoint struct { + AckHandle uint32 + Unk0 uint8 + Unk1 uint8 + TrialCoins uint32 + PremiumCoins uint32 } // Opcode returns the ID associated with this packet type. @@ -24,7 +25,8 @@ func (m *MsgMhfUseGachaPoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfUseGachaPoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() m.TrialCoins = bf.ReadUint32() m.PremiumCoins = bf.ReadUint32() return nil diff --git a/network/mhfpacket/msg_mhf_vote_festa.go b/network/mhfpacket/msg_mhf_vote_festa.go index b3c05d5fd..201c1b5ac 100644 --- a/network/mhfpacket/msg_mhf_vote_festa.go +++ b/network/mhfpacket/msg_mhf_vote_festa.go @@ -11,7 +11,7 @@ import ( // MsgMhfVoteFesta represents the MSG_MHF_VOTE_FESTA type MsgMhfVoteFesta struct { AckHandle uint32 - Unk uint32 + FestaID uint32 GuildID uint32 TrialID uint32 } @@ -24,7 +24,7 @@ func (m *MsgMhfVoteFesta) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfVoteFesta) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk = bf.ReadUint32() + m.FestaID = bf.ReadUint32() m.GuildID = bf.ReadUint32() m.TrialID = bf.ReadUint32() return nil diff --git a/network/mhfpacket/msg_sys_create_acquire_semaphore.go b/network/mhfpacket/msg_sys_create_acquire_semaphore.go index 694aaaeed..9e22c50e7 100644 --- a/network/mhfpacket/msg_sys_create_acquire_semaphore.go +++ b/network/mhfpacket/msg_sys_create_acquire_semaphore.go @@ -2,7 +2,6 @@ package mhfpacket import ( "errors" - "erupe-ce/common/bfutil" "erupe-ce/common/byteframe" _config "erupe-ce/config" "erupe-ce/network" @@ -29,8 +28,8 @@ func (m *MsgSysCreateAcquireSemaphore) Parse(bf *byteframe.ByteFrame, ctx *clien if _config.ErupeConfig.RealClientMode >= _config.S7 { // Assuming this was added with Ravi? m.PlayerCount = bf.ReadUint8() } - SemaphoreIDLength := bf.ReadUint8() - m.SemaphoreID = string(bfutil.UpToNull(bf.ReadBytes(uint(SemaphoreIDLength)))) + bf.ReadUint8() // SemaphoreID length + m.SemaphoreID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_create_semaphore.go b/network/mhfpacket/msg_sys_create_semaphore.go index 361802e05..c9b29d2ab 100644 --- a/network/mhfpacket/msg_sys_create_semaphore.go +++ b/network/mhfpacket/msg_sys_create_semaphore.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + _config "erupe-ce/config" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -10,10 +11,10 @@ import ( // MsgSysCreateSemaphore represents the MSG_SYS_CREATE_SEMAPHORE type MsgSysCreateSemaphore struct { - AckHandle uint32 - Unk0 uint16 - DataSize uint16 - RawDataPayload []byte + AckHandle uint32 + Unk0 uint16 + PlayerCount uint8 + SemaphoreID string } // Opcode returns the ID associated with this packet type. @@ -25,8 +26,11 @@ func (m *MsgSysCreateSemaphore) Opcode() network.PacketID { func (m *MsgSysCreateSemaphore) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint16() - m.DataSize = bf.ReadUint16() - m.RawDataPayload = bf.ReadBytes(uint(m.DataSize)) + if _config.ErupeConfig.RealClientMode >= _config.S7 { // Assuming this was added with Ravi? + m.PlayerCount = bf.ReadUint8() + } + bf.ReadUint8() // SemaphoreID length + m.SemaphoreID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_enumerate_client.go b/network/mhfpacket/msg_sys_enumerate_client.go index 5318549a6..06764d65b 100644 --- a/network/mhfpacket/msg_sys_enumerate_client.go +++ b/network/mhfpacket/msg_sys_enumerate_client.go @@ -3,7 +3,6 @@ package mhfpacket import ( "errors" - "erupe-ce/common/bfutil" "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" @@ -27,8 +26,8 @@ func (m *MsgSysEnumerateClient) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint8() m.Get = bf.ReadUint8() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + bf.ReadUint8() // StageID length + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_get_stage_binary.go b/network/mhfpacket/msg_sys_get_stage_binary.go index 336f563d5..c2da50122 100644 --- a/network/mhfpacket/msg_sys_get_stage_binary.go +++ b/network/mhfpacket/msg_sys_get_stage_binary.go @@ -2,7 +2,6 @@ package mhfpacket import ( "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -27,8 +26,8 @@ func (m *MsgSysGetStageBinary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.BinaryType0 = bf.ReadUint8() m.BinaryType1 = bf.ReadUint8() m.Unk0 = bf.ReadUint32() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + bf.ReadUint8() // StageID length + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_load_register.go b/network/mhfpacket/msg_sys_load_register.go index 7e1ac5950..edf4eafb4 100644 --- a/network/mhfpacket/msg_sys_load_register.go +++ b/network/mhfpacket/msg_sys_load_register.go @@ -24,8 +24,8 @@ func (m *MsgSysLoadRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien m.AckHandle = bf.ReadUint32() m.RegisterID = bf.ReadUint32() m.Values = bf.ReadUint8() - _ = bf.ReadUint8() - _ = bf.ReadUint16() + bf.ReadUint8() // Zeroed + bf.ReadUint16() // Zeroed return nil } diff --git a/network/mhfpacket/msg_sys_login.go b/network/mhfpacket/msg_sys_login.go index fc881b991..5f8a7c7cc 100644 --- a/network/mhfpacket/msg_sys_login.go +++ b/network/mhfpacket/msg_sys_login.go @@ -1,24 +1,22 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysLogin represents the MSG_SYS_LOGIN type MsgSysLogin struct { - AckHandle uint32 - CharID0 uint32 - LoginTokenNumber uint32 - HardcodedZero0 uint16 - RequestVersion uint16 - CharID1 uint32 - HardcodedZero1 uint16 - LoginTokenStringLength uint16 // Hardcoded to 0x11 - LoginTokenString string + AckHandle uint32 + CharID0 uint32 + LoginTokenNumber uint32 + HardcodedZero0 uint16 + RequestVersion uint16 + CharID1 uint32 + LoginTokenString string } // Opcode returns the ID associated with this packet type. @@ -34,8 +32,8 @@ func (m *MsgSysLogin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContex m.HardcodedZero0 = bf.ReadUint16() m.RequestVersion = bf.ReadUint16() m.CharID1 = bf.ReadUint32() - m.HardcodedZero1 = bf.ReadUint16() - m.LoginTokenStringLength = bf.ReadUint16() + bf.ReadUint16() // Zeroed + bf.ReadUint16() // Always 11 m.LoginTokenString = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_operate_register.go b/network/mhfpacket/msg_sys_operate_register.go index 6978609b1..75946d340 100644 --- a/network/mhfpacket/msg_sys_operate_register.go +++ b/network/mhfpacket/msg_sys_operate_register.go @@ -23,7 +23,7 @@ func (m *MsgSysOperateRegister) Opcode() network.PacketID { func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.SemaphoreID = bf.ReadUint32() - _ = bf.ReadUint16() + bf.ReadUint16() // Zeroed dataSize := bf.ReadUint16() m.RawDataPayload = bf.ReadBytes(uint(dataSize)) return nil diff --git a/network/mhfpacket/msg_sys_set_stage_binary.go b/network/mhfpacket/msg_sys_set_stage_binary.go index eecee64a1..79832c7bb 100644 --- a/network/mhfpacket/msg_sys_set_stage_binary.go +++ b/network/mhfpacket/msg_sys_set_stage_binary.go @@ -2,7 +2,6 @@ package mhfpacket import ( "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -24,9 +23,9 @@ func (m *MsgSysSetStageBinary) Opcode() network.PacketID { func (m *MsgSysSetStageBinary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.BinaryType0 = bf.ReadUint8() m.BinaryType1 = bf.ReadUint8() - stageIDLength := bf.ReadUint8() // <= 0x20 - dataSize := bf.ReadUint16() // <= 0x400 - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + bf.ReadUint8() // StageID length <= 0x20 + dataSize := bf.ReadUint16() // <= 0x400 + m.StageID = string(bf.ReadNullTerminatedBytes()) m.RawDataPayload = bf.ReadBytes(uint(dataSize)) return nil } diff --git a/network/mhfpacket/msg_sys_wait_stage_binary.go b/network/mhfpacket/msg_sys_wait_stage_binary.go index 2a443cc72..5127e53de 100644 --- a/network/mhfpacket/msg_sys_wait_stage_binary.go +++ b/network/mhfpacket/msg_sys_wait_stage_binary.go @@ -2,7 +2,6 @@ package mhfpacket import ( "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -27,8 +26,8 @@ func (m *MsgSysWaitStageBinary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl m.BinaryType0 = bf.ReadUint8() m.BinaryType1 = bf.ReadUint8() m.Unk0 = bf.ReadUint32() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + bf.ReadUint8() // StageID length + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 057881723..154dbc100 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -611,7 +611,7 @@ func handleMsgMhfServerCommand(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfAnnounce(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfAnnounce) - s.server.BroadcastRaviente(pkt.IPAddress, pkt.Port, pkt.StageID, pkt.Type) + s.server.BroadcastRaviente(pkt.IPAddress, pkt.Port, pkt.StageID, pkt.Data.ReadUint8()) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/server/channelserver/handlers_clients.go b/server/channelserver/handlers_clients.go index 12e8540b3..e1d2c4a49 100644 --- a/server/channelserver/handlers_clients.go +++ b/server/channelserver/handlers_clients.go @@ -60,20 +60,19 @@ func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) { resp := byteframe.NewByteFrame() resp.WriteUint32(0) // Blacklist count err := s.server.db.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.charID).Scan(&csv) - if err != nil { - panic(err) - } - cids := stringsupport.CSVElems(csv) - for _, cid := range cids { - var name string - err = s.server.db.QueryRow("SELECT name FROM characters WHERE id=$1", cid).Scan(&name) - if err != nil { - continue + if err == nil { + cids := stringsupport.CSVElems(csv) + for _, cid := range cids { + var name string + err = s.server.db.QueryRow("SELECT name FROM characters WHERE id=$1", cid).Scan(&name) + if err != nil { + continue + } + count++ + resp.WriteUint32(uint32(cid)) + resp.WriteUint32(16) + resp.WriteBytes(stringsupport.PaddedString(name, 16, true)) } - count++ - resp.WriteUint32(uint32(cid)) - resp.WriteUint32(16) - resp.WriteBytes(stringsupport.PaddedString(name, 16, true)) } resp.Seek(0, 0) resp.WriteUint32(count) @@ -83,28 +82,28 @@ func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfOprMember(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfOprMember) var csv string - if pkt.Blacklist { - err := s.server.db.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.charID).Scan(&csv) - if err != nil { - panic(err) + for _, cid := range pkt.CharIDs { + if pkt.Blacklist { + err := s.server.db.QueryRow("SELECT blocked FROM characters WHERE id=$1", s.charID).Scan(&csv) + if err == nil { + if pkt.Operation { + csv = stringsupport.CSVRemove(csv, int(cid)) + } else { + csv = stringsupport.CSVAdd(csv, int(cid)) + } + s.server.db.Exec("UPDATE characters SET blocked=$1 WHERE id=$2", csv, s.charID) + } + } else { // Friendlist + err := s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&csv) + if err == nil { + if pkt.Operation { + csv = stringsupport.CSVRemove(csv, int(cid)) + } else { + csv = stringsupport.CSVAdd(csv, int(cid)) + } + s.server.db.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.charID) + } } - if pkt.Operation { - csv = stringsupport.CSVRemove(csv, int(pkt.CharID)) - } else { - csv = stringsupport.CSVAdd(csv, int(pkt.CharID)) - } - s.server.db.Exec("UPDATE characters SET blocked=$1 WHERE id=$2", csv, s.charID) - } else { // Friendlist - err := s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&csv) - if err != nil { - panic(err) - } - if pkt.Operation { - csv = stringsupport.CSVRemove(csv, int(pkt.CharID)) - } else { - csv = stringsupport.CSVAdd(csv, int(pkt.CharID)) - } - s.server.db.Exec("UPDATE characters SET friends=$1 WHERE id=$2", csv, s.charID) } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index cf190aa45..48d2bbadf 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1147,7 +1147,6 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { var alliances []*GuildAlliance var rows *sqlx.Rows var err error - bf := byteframe.NewByteFrameFromBytes(pkt.Data1) if pkt.Type <= 8 { var tempGuilds []*Guild @@ -1164,20 +1163,20 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { switch pkt.Type { case mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME: for _, guild := range tempGuilds { - if strings.Contains(guild.Name, pkt.Data2) { + if strings.Contains(guild.Name, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) { guilds = append(guilds, guild) } } case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_NAME: for _, guild := range tempGuilds { - if strings.Contains(guild.LeaderName, pkt.Data2) { + if strings.Contains(guild.LeaderName, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) { guilds = append(guilds, guild) } } case mhfpacket.ENUMERATE_GUILD_TYPE_LEADER_ID: - ID := bf.ReadUint32() + CID := pkt.Data1.ReadUint32() for _, guild := range tempGuilds { - if guild.LeaderCharID == ID { + if guild.LeaderCharID == CID { guilds = append(guilds, guild) } } @@ -1215,15 +1214,15 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { } guilds = tempGuilds case mhfpacket.ENUMERATE_GUILD_TYPE_MOTTO: - mainMotto := uint8(bf.ReadUint16()) - subMotto := uint8(bf.ReadUint16()) + mainMotto := uint8(pkt.Data1.ReadUint16()) + subMotto := uint8(pkt.Data1.ReadUint16()) for _, guild := range tempGuilds { if guild.MainMotto == mainMotto && guild.SubMotto == subMotto { guilds = append(guilds, guild) } } case mhfpacket.ENUMERATE_GUILD_TYPE_RECRUITING: - recruitingMotto := uint8(bf.ReadUint16()) + recruitingMotto := uint8(pkt.Data1.ReadUint16()) for _, guild := range tempGuilds { if guild.MainMotto == recruitingMotto { guilds = append(guilds, guild) @@ -1244,20 +1243,20 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { switch pkt.Type { case mhfpacket.ENUMERATE_ALLIANCE_TYPE_ALLIANCE_NAME: for _, alliance := range tempAlliances { - if strings.Contains(alliance.Name, pkt.Data2) { + if strings.Contains(alliance.Name, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) { alliances = append(alliances, alliance) } } case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_NAME: for _, alliance := range tempAlliances { - if strings.Contains(alliance.ParentGuild.LeaderName, pkt.Data2) { + if strings.Contains(alliance.ParentGuild.LeaderName, stringsupport.SJISToUTF8(pkt.Data2.ReadNullTerminatedBytes())) { alliances = append(alliances, alliance) } } case mhfpacket.ENUMERATE_ALLIANCE_TYPE_LEADER_ID: - ID := bf.ReadUint32() + CID := pkt.Data1.ReadUint32() for _, alliance := range tempAlliances { - if alliance.ParentGuild.LeaderCharID == ID { + if alliance.ParentGuild.LeaderCharID == CID { alliances = append(alliances, alliance) } } @@ -1291,7 +1290,7 @@ func handleMsgMhfEnumerateGuild(s *Session, p mhfpacket.MHFPacket) { return } - bf = byteframe.NewByteFrame() + bf := byteframe.NewByteFrame() if pkt.Type > 8 { hasNextPage := false @@ -1436,7 +1435,7 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) { for _, member := range guildMembers { bf.WriteUint32(member.CharID) bf.WriteUint16(member.HRP) - if s.server.erupeConfig.RealClientMode > _config.G7 { + if s.server.erupeConfig.RealClientMode >= _config.G10 { bf.WriteUint16(member.GR) } if s.server.erupeConfig.RealClientMode < _config.ZZ { @@ -1558,7 +1557,7 @@ func handleMsgMhfEnumerateGuildItem(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateGuildItem) var boxContents []byte bf := byteframe.NewByteFrame() - err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents) + err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", pkt.GuildID).Scan(&boxContents) if err != nil { s.logger.Error("Failed to get guild item box contents from db", zap.Error(err)) bf.WriteBytes(make([]byte, 4)) @@ -1592,7 +1591,7 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) { // Get item cache from DB var boxContents []byte var oldItems []Item - err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", int(pkt.GuildId)).Scan(&boxContents) + err := s.server.db.QueryRow("SELECT item_box FROM guilds WHERE id = $1", pkt.GuildID).Scan(&boxContents) if err != nil { s.logger.Error("Failed to get guild item box contents from db", zap.Error(err)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) @@ -1642,7 +1641,7 @@ func handleMsgMhfUpdateGuildItem(s *Session, p mhfpacket.MHFPacket) { } // Upload new item cache - _, err = s.server.db.Exec("UPDATE guilds SET item_box = $1 WHERE id = $2", bf.Data(), int(pkt.GuildId)) + _, err = s.server.db.Exec("UPDATE guilds SET item_box = $1 WHERE id = $2", bf.Data(), pkt.GuildID) if err != nil { s.logger.Error("Failed to update guild item box contents in db", zap.Error(err)) } diff --git a/server/channelserver/handlers_guild_alliance.go b/server/channelserver/handlers_guild_alliance.go index f27d67026..39dbe13f6 100644 --- a/server/channelserver/handlers_guild_alliance.go +++ b/server/channelserver/handlers_guild_alliance.go @@ -162,8 +162,7 @@ func handleMsgMhfOperateJoint(s *Session, p mhfpacket.MHFPacket) { } case mhfpacket.OPERATE_JOINT_KICK: if alliance.ParentGuild.LeaderCharID == s.charID { - _ = pkt.UnkData.ReadUint8() - kickedGuildID := pkt.UnkData.ReadUint32() + kickedGuildID := pkt.Data1.ReadUint32() if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID > 0 { s.server.db.Exec(`UPDATE guild_alliances SET sub1_id = sub2_id, sub2_id = NULL WHERE id = $1`, alliance.ID) } else if kickedGuildID == alliance.SubGuild1ID && alliance.SubGuild2ID == 0 { diff --git a/server/channelserver/handlers_register.go b/server/channelserver/handlers_register.go index 6a74358aa..3d47c3633 100644 --- a/server/channelserver/handlers_register.go +++ b/server/channelserver/handlers_register.go @@ -10,7 +10,7 @@ func handleMsgMhfRegisterEvent(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfRegisterEvent) bf := byteframe.NewByteFrame() // Some kind of check if there's already a session - if pkt.Unk3 > 0 && s.server.getRaviSemaphore() == nil { + if pkt.Unk1 && s.server.getRaviSemaphore() == nil { doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) return } From 1e6675b3f58d101ae71fd2861b7d18e8a071677b Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 04:59:30 +1100 Subject: [PATCH 88/96] add support for Festa Trial voting --- patch-schema/13-festa-trial-votes.sql | 5 ++++ server/channelserver/handlers_festa.go | 34 +++++++++++++++++--------- server/channelserver/handlers_guild.go | 12 ++++----- 3 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 patch-schema/13-festa-trial-votes.sql diff --git a/patch-schema/13-festa-trial-votes.sql b/patch-schema/13-festa-trial-votes.sql new file mode 100644 index 000000000..d9e3d0290 --- /dev/null +++ b/patch-schema/13-festa-trial-votes.sql @@ -0,0 +1,5 @@ +BEGIN; + +ALTER TABLE IF EXISTS public.guild_characters ADD COLUMN trial_vote integer; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 7ca50d9d1..024cee00d 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -96,7 +96,7 @@ func cleanupFesta(s *Session) { s.server.db.Exec("DELETE FROM events WHERE event_type='festa'") s.server.db.Exec("DELETE FROM festa_registrations") s.server.db.Exec("DELETE FROM festa_prizes_accepted") - s.server.db.Exec("UPDATE guild_characters SET souls=0") + s.server.db.Exec("UPDATE guild_characters SET souls=0, trial_vote=NULL") } func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 { @@ -141,13 +141,13 @@ func generateFestaTimestamps(s *Session, start uint32, debug bool) []uint32 { } type FestaTrial struct { - ID uint32 `db:"id"` - Objective uint16 `db:"objective"` - GoalID uint32 `db:"goal_id"` - TimesReq uint16 `db:"times_req"` - Locale uint16 `db:"locale_req"` - Reward uint16 `db:"reward"` - Monopoly uint16 + ID uint32 `db:"id"` + Objective uint16 `db:"objective"` + GoalID uint32 `db:"goal_id"` + TimesReq uint16 `db:"times_req"` + Locale uint16 `db:"locale_req"` + Reward uint16 `db:"reward"` + Monopoly FestivalColour `db:"monopoly"` Unk uint16 } @@ -205,7 +205,19 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { var trials []FestaTrial var trial FestaTrial - rows, _ = s.server.db.Queryx("SELECT * FROM festa_trials") + rows, _ = s.server.db.Queryx(`SELECT ft.*, + COALESCE(CASE + WHEN COUNT(gc.id) FILTER (WHERE fr.team = 'blue' AND gc.trial_vote = ft.id) > + COUNT(gc.id) FILTER (WHERE fr.team = 'red' AND gc.trial_vote = ft.id) + THEN CAST('blue' AS public.festival_colour) + WHEN COUNT(gc.id) FILTER (WHERE fr.team = 'red' AND gc.trial_vote = ft.id) > + COUNT(gc.id) FILTER (WHERE fr.team = 'blue' AND gc.trial_vote = ft.id) + THEN CAST('red' AS public.festival_colour) + END, CAST('none' AS public.festival_colour)) AS monopoly + FROM public.festa_trials ft + LEFT JOIN public.guild_characters gc ON ft.id = gc.trial_vote + LEFT JOIN public.festa_registrations fr ON gc.guild_id = fr.guild_id + GROUP BY ft.id`) for rows.Next() { err := rows.StructScan(&trial) if err != nil { @@ -221,8 +233,7 @@ func handleMsgMhfInfoFesta(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(trial.TimesReq) bf.WriteUint16(trial.Locale) bf.WriteUint16(trial.Reward) - trial.Monopoly = 0xFFFF // NYI - bf.WriteUint16(trial.Monopoly) + bf.WriteInt16(int16(FestivalColourCodes[trial.Monopoly])) bf.WriteUint16(trial.Unk) } @@ -395,6 +406,7 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfVoteFesta) + s.server.db.Exec(`UPDATE guild_characters SET trial_vote=$1 WHERE character_id=$2`, pkt.TrialID, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 48d2bbadf..7a726832f 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -25,14 +25,14 @@ type FestivalColour string const ( FestivalColourNone FestivalColour = "none" - FestivalColourRed FestivalColour = "red" FestivalColourBlue FestivalColour = "blue" + FestivalColourRed FestivalColour = "red" ) -var FestivalColourCodes = map[FestivalColour]uint8{ - FestivalColourBlue: 0x00, - FestivalColourRed: 0x01, - FestivalColourNone: 0xFF, +var FestivalColourCodes = map[FestivalColour]int8{ + FestivalColourNone: -1, + FestivalColourBlue: 0, + FestivalColourRed: 1, } type GuildApplicationType string @@ -967,7 +967,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint8(uint8(len(guildLeaderName))) bf.WriteBytes(guildName) bf.WriteBytes(guildComment) - bf.WriteUint8(FestivalColourCodes[guild.FestivalColour]) + bf.WriteInt8(FestivalColourCodes[guild.FestivalColour]) bf.WriteUint32(guild.RankRP) bf.WriteBytes(guildLeaderName) bf.WriteUint32(0) // Unk From e5fa0501b745fc6ea64401152ec5e221a09c21cb Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 20:17:03 +1100 Subject: [PATCH 89/96] add packet time profiling --- server/channelserver/sys_session.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 406ea4384..ff3ad34e0 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -62,8 +62,9 @@ type Session struct { mailList []int // For Debuging - Name string - closed bool + Name string + closed bool + ackStart map[uint32]time.Time } // NewSession creates a new Session type. @@ -78,6 +79,7 @@ func NewSession(server *Server, conn net.Conn) *Session { lastPacket: time.Now(), sessionStart: TimeAdjusted().Unix(), stageMoveStack: stringstack.New(), + ackStart: make(map[uint32]time.Time), } s.SetObjectID() return s @@ -192,6 +194,10 @@ func (s *Session) handlePacketGroup(pktGroup []byte) { s.lastPacket = time.Now() bf := byteframe.NewByteFrameFromBytes(pktGroup) opcodeUint16 := bf.ReadUint16() + if len(bf.Data()) >= 6 { + s.ackStart[bf.ReadUint32()] = time.Now() + bf.Seek(2, io.SeekStart) + } opcode := network.PacketID(opcodeUint16) // This shouldn't be needed, but it's better to recover and let the connection die than to panic the server. @@ -262,7 +268,15 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien if ignored(opcodePID) { return } - fmt.Printf("[%s] -> [%s]\n", sender, recipient) + var ackHandle uint32 + if len(data) >= 6 { + ackHandle = binary.BigEndian.Uint32(data[2:6]) + } + if t, ok := s.ackStart[ackHandle]; ok { + fmt.Printf("[%s] -> [%s] (%fs)\n", sender, recipient, float64(time.Now().UnixNano()-t.UnixNano())/1000000000) + } else { + fmt.Printf("[%s] -> [%s]\n", sender, recipient) + } fmt.Printf("Opcode: %s\n", opcodePID) if len(data) <= s.server.erupeConfig.DevModeOptions.MaxHexdumpLength { fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) From d7d3e7c61f354c065b73e653324d3030b2abdd79 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 23:12:58 +1100 Subject: [PATCH 90/96] update parsing of CastBinary & EnterStage --- network/mhfpacket/msg_sys_cast_binary.go | 14 ++++++-------- network/mhfpacket/msg_sys_enter_stage.go | 5 ++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/network/mhfpacket/msg_sys_cast_binary.go b/network/mhfpacket/msg_sys_cast_binary.go index 07935f2aa..f0b0c2bd3 100644 --- a/network/mhfpacket/msg_sys_cast_binary.go +++ b/network/mhfpacket/msg_sys_cast_binary.go @@ -1,17 +1,16 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysCastBinary represents the MSG_SYS_CAST_BINARY type MsgSysCastBinary struct { - Unk0 uint16 - Unk1 uint16 + Unk uint32 BroadcastType uint8 MessageType uint8 RawDataPayload []byte @@ -24,8 +23,7 @@ func (m *MsgSysCastBinary) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysCastBinary) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint16() + m.Unk = bf.ReadUint32() m.BroadcastType = bf.ReadUint8() m.MessageType = bf.ReadUint8() dataSize := bf.ReadUint16() diff --git a/network/mhfpacket/msg_sys_enter_stage.go b/network/mhfpacket/msg_sys_enter_stage.go index 977ff486f..5a1ccb8ab 100644 --- a/network/mhfpacket/msg_sys_enter_stage.go +++ b/network/mhfpacket/msg_sys_enter_stage.go @@ -4,7 +4,6 @@ import ( "errors" "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -25,8 +24,8 @@ func (m *MsgSysEnterStage) Opcode() network.PacketID { func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.UnkBool = bf.ReadUint8() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + bf.ReadUint8() + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } From e066e9566f190ab40f016e7a06a813be1704b259 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 23:13:12 +1100 Subject: [PATCH 91/96] remove duplicate CleanupObject --- server/channelserver/handlers_stage.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index be7ab1267..cf8757b00 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -163,7 +163,6 @@ func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { s.stageMoveStack.Lock() } - s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{}) if s.reservationStage != nil { s.reservationStage = nil } From 105a118163c79d5c7f5ff60f6c205e52aefd0f46 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 19 Nov 2023 23:13:34 +1100 Subject: [PATCH 92/96] filter workflow triggers --- .github/workflows/go.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 955febd9a..e69ee1705 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,6 +1,15 @@ name: Build -on: [push] +on: + push: + paths: + - 'common/**' + - 'config/**' + - 'network/**' + - 'server/**' + - 'go.mod' + - 'go.sum' + - 'main.go' jobs: build: From b6cc8c3a1222ebdb7cf43dbc0b06b00706a59655 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 20 Nov 2023 00:01:22 +1100 Subject: [PATCH 93/96] fix incorrect Client Version string --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 4c156d35e..a4cb99eb7 100644 --- a/config/config.go +++ b/config/config.go @@ -58,7 +58,7 @@ const ( ) var versionStrings = []string{"S1.0", "S1.5", "S2.0", "S2.5", "S3.0", "S3.5", "S4.0", "S5.0", "S5.5", "S6.0", "S7.0", - "S8.0", "S8.5", "S9", "S10", "FW.1", "FW.2", "FW.3", "FW.4", "FW.5", "G1", "G2", "G3", "G3.1", "G3.2", "GG", "G5", + "S8.0", "S8.5", "S9.0", "S10", "FW.1", "FW.2", "FW.3", "FW.4", "FW.5", "G1", "G2", "G3", "G3.1", "G3.2", "GG", "G5", "G5.1", "G5.2", "G6", "G6.1", "G7", "G8", "G8.1", "G9", "G9.1", "G10", "G10.1", "Z1", "Z2", "ZZ"} func (m Mode) String() string { From bcf2ba40e50d4da191867c4b699a7a8a36c5d50c Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 20 Nov 2023 00:13:49 +1100 Subject: [PATCH 94/96] fix possible integer bounding issues --- common/stringsupport/string_convert.go | 4 ++-- server/channelserver/handlers_cast_binary.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/stringsupport/string_convert.go b/common/stringsupport/string_convert.go index 452c85321..de4d04364 100644 --- a/common/stringsupport/string_convert.go +++ b/common/stringsupport/string_convert.go @@ -69,7 +69,7 @@ func CSVRemove(csv string, v int) string { func CSVContains(csv string, v int) bool { s := strings.Split(csv, ",") for i := 0; i < len(s); i++ { - j, _ := strconv.ParseInt(s[i], 10, 64) + j, _ := strconv.ParseInt(s[i], 10, 32) if int(j) == v { return true } @@ -92,7 +92,7 @@ func CSVElems(csv string) []int { } s := strings.Split(csv, ",") for i := 0; i < len(s); i++ { - j, _ := strconv.ParseInt(s[i], 10, 64) + j, _ := strconv.ParseInt(s[i], 10, 32) r = append(r, int(j)) } return r diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 168e2f181..15a85f32b 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -298,8 +298,8 @@ func parseChatCommand(s *Session, command string) { case commands["Teleport"].Prefix: if commands["Teleport"].Enabled { if len(args) > 2 { - x, _ := strconv.Atoi(args[1]) - y, _ := strconv.Atoi(args[2]) + x, _ := strconv.ParseInt(args[1], 10, 16) + y, _ := strconv.ParseInt(args[2], 10, 16) payload := byteframe.NewByteFrame() payload.SetLE() payload.WriteUint8(2) // SetState type(position == 2) From e9fa4e5261ae536b0960994ab4463d8719dbdcbe Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 20 Nov 2023 00:49:50 +1100 Subject: [PATCH 95/96] fix LogOutboundMessages not working --- server/channelserver/sys_session.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index ff3ad34e0..a9b89a918 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -260,7 +260,7 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien if sender == "Server" && !s.server.erupeConfig.DevModeOptions.LogOutboundMessages { return - } else if !s.server.erupeConfig.DevModeOptions.LogInboundMessages { + } else if sender != "Server" && !s.server.erupeConfig.DevModeOptions.LogInboundMessages { return } @@ -281,7 +281,7 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien if len(data) <= s.server.erupeConfig.DevModeOptions.MaxHexdumpLength { fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) } else { - fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data)) + fmt.Printf("Data [%d bytes]: (Too long!)\n\n", len(data)) } } From 405e65346bccc1ef8733bdc581a3b35f4e35eca1 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 20 Nov 2023 00:58:24 +1100 Subject: [PATCH 96/96] add LogMessageData DevModeOption & disable Logging by default --- config.json | 5 +++-- config/config.go | 1 + server/channelserver/sys_session.go | 10 +++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/config.json b/config.json index a62b45325..e3e2b7ea4 100644 --- a/config.json +++ b/config.json @@ -18,8 +18,9 @@ "AutoCreateAccount": true, "CleanDB": false, "MaxLauncherHR": false, - "LogInboundMessages": true, - "LogOutboundMessages": true, + "LogInboundMessages": false, + "LogOutboundMessages": false, + "LogMessageData": false, "MaxHexdumpLength": 256, "DivaEvent": 0, "FestaEvent": -1, diff --git a/config/config.go b/config/config.go index a4cb99eb7..ee0e6b377 100644 --- a/config/config.go +++ b/config/config.go @@ -101,6 +101,7 @@ type DevModeOptions struct { MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds. LogInboundMessages bool // Log all messages sent to the server LogOutboundMessages bool // Log all messages sent to the clients + LogMessageData bool // Log all bytes transferred as a hexdump MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled DivaEvent int // Diva Defense event status FestaEvent int // Hunter's Festa event status diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index a9b89a918..32004151d 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -278,10 +278,14 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien fmt.Printf("[%s] -> [%s]\n", sender, recipient) } fmt.Printf("Opcode: %s\n", opcodePID) - if len(data) <= s.server.erupeConfig.DevModeOptions.MaxHexdumpLength { - fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) + if s.server.erupeConfig.DevModeOptions.LogMessageData { + if len(data) <= s.server.erupeConfig.DevModeOptions.MaxHexdumpLength { + fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) + } else { + fmt.Printf("Data [%d bytes]: (Too long!)\n\n", len(data)) + } } else { - fmt.Printf("Data [%d bytes]: (Too long!)\n\n", len(data)) + fmt.Printf("\n") } }