From 6ec9d9d8690f1b09c8fa22fdcbeb56976c305fef Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 11 Feb 2024 23:22:42 +1100 Subject: [PATCH 1/4] add AutoBackportQuest DebugOption --- config.json | 1 + config/config.go | 1 + server/channelserver/handlers_quest.go | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/config.json b/config.json index 9bb641f72..c8705a661 100644 --- a/config.json +++ b/config.json @@ -36,6 +36,7 @@ "TournamentOverride": 0, "DisableTokenCheck": false, "QuestTools": false, + "AutoQuestBackport": true, "ProxyPort": 0, "CapLink": { "Values": [51728, 20000, 51729, 1, 20000], diff --git a/config/config.go b/config/config.go index d2038f150..b0094f628 100644 --- a/config/config.go +++ b/config/config.go @@ -118,6 +118,7 @@ type DebugOptions struct { TournamentOverride int // VS Tournament event status DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) QuestTools bool // Enable various quest debug logs + AutoQuestBackport bool // Automatically backport quest files ProxyPort uint16 // Forces the game to connect to a channel server proxy CapLink CapLinkOptions } diff --git a/server/channelserver/handlers_quest.go b/server/channelserver/handlers_quest.go index c8bd41f3b..148908dbf 100644 --- a/server/channelserver/handlers_quest.go +++ b/server/channelserver/handlers_quest.go @@ -2,6 +2,7 @@ package channelserver import ( "database/sql" + "encoding/binary" "erupe-ce/common/byteframe" "erupe-ce/common/decryption" ps "erupe-ce/common/pascalstring" @@ -21,6 +22,20 @@ type tuneValue struct { Value uint16 } +func BackportQuest(data []byte) []byte { + wp := binary.LittleEndian.Uint32(data[0:4]) + 96 + rp := wp + 4 + for i := uint32(0); i < 6; i++ { + if i != 0 { + wp += 4 + rp += 8 + } + copy(data[wp:wp+4], data[rp:rp+4]) + } + copy(data[wp:wp+180], data[rp:rp+180]) + return data +} + func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysGetFile) @@ -63,6 +78,9 @@ func handleMsgSysGetFile(s *Session, p mhfpacket.MHFPacket) { doAckBufSucceed(s, pkt.AckHandle, data) return } + if _config.ErupeConfig.RealClientMode <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport { + data = BackportQuest(decryption.UnpackSimple(data)) + } doAckBufSucceed(s, pkt.AckHandle, data) } } @@ -124,6 +142,9 @@ func loadQuestFile(s *Session, questId int) []byte { } decrypted := decryption.UnpackSimple(file) + if _config.ErupeConfig.RealClientMode <= _config.Z1 && s.server.erupeConfig.DebugOptions.AutoQuestBackport { + decrypted = BackportQuest(decrypted) + } fileBytes := byteframe.NewByteFrameFromBytes(decrypted) fileBytes.SetLE() fileBytes.Seek(int64(fileBytes.ReadUint32()), 0) From 5f370896dff9f01df63fbe50859d4eac20624573 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 14 Feb 2024 17:28:01 +1100 Subject: [PATCH 2/4] clean up Tower responses --- schemas/patch-schema/02-tower.sql | 4 +-- server/channelserver/handlers_tower.go | 47 ++++++++++++++++---------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/schemas/patch-schema/02-tower.sql b/schemas/patch-schema/02-tower.sql index 0697fc2be..732f46c5e 100644 --- a/schemas/patch-schema/02-tower.sql +++ b/schemas/patch-schema/02-tower.sql @@ -7,8 +7,8 @@ CREATE TABLE IF NOT EXISTS tower ( tsp INT, block1 INT, block2 INT, - skills TEXT DEFAULT '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,0,0,0,0,0,0,0,0,0,0,0', - gems TEXT DEFAULT '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,0' + skills TEXT, + gems TEXT ); ALTER TABLE IF EXISTS guild_characters diff --git a/server/channelserver/handlers_tower.go b/server/channelserver/handlers_tower.go index 7f6bdb3b9..e075804e4 100644 --- a/server/channelserver/handlers_tower.go +++ b/server/channelserver/handlers_tower.go @@ -1,8 +1,10 @@ package channelserver import ( + _config "erupe-ce/config" "fmt" "go.uber.org/zap" + "strings" "time" "erupe-ce/common/byteframe" @@ -16,8 +18,8 @@ type TowerInfoTRP struct { } type TowerInfoSkill struct { - TSP int32 - Unk1 []int16 // 40 + TSP int32 + Skills []int16 // 64 } type TowerInfoHistory struct { @@ -32,6 +34,14 @@ type TowerInfoLevel struct { Unk3 int32 } +func EmptyTowerCSV(len int) string { + temp := make([]string, len) + for i := range temp { + temp[i] = "0" + } + return strings.Join(temp, ",") +} + func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetTowerInfo) var data []*byteframe.ByteFrame @@ -44,21 +54,24 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { towerInfo := TowerInfo{ TRP: []TowerInfoTRP{{0, 0}}, - Skill: []TowerInfoSkill{{0, make([]int16, 40)}}, + Skill: []TowerInfoSkill{{0, make([]int16, 64)}}, History: []TowerInfoHistory{{make([]int16, 5), make([]int16, 5)}}, Level: []TowerInfoLevel{{0, 0, 0, 0}, {0, 0, 0, 0}}, } - tempSkills := "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,0,0,0,0,0,0,0,0,0,0,0" - - err := s.server.db.QueryRow(`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), skills FROM tower WHERE char_id=$1 - `, s.charID).Scan(&towerInfo.TRP[0].TR, &towerInfo.TRP[0].TRP, &towerInfo.Skill[0].TSP, &towerInfo.Level[0].Floors, &towerInfo.Level[1].Floors, &tempSkills) + var tempSkills string + err := s.server.db.QueryRow(`SELECT COALESCE(tr, 0), COALESCE(trp, 0), COALESCE(tsp, 0), COALESCE(block1, 0), COALESCE(block2, 0), COALESCE(skills, $1) FROM tower WHERE char_id=$2 + `, EmptyTowerCSV(64), s.charID).Scan(&towerInfo.TRP[0].TR, &towerInfo.TRP[0].TRP, &towerInfo.Skill[0].TSP, &towerInfo.Level[0].Floors, &towerInfo.Level[1].Floors, &tempSkills) if err != nil { s.server.db.Exec(`INSERT INTO tower (char_id) VALUES ($1)`, s.charID) } + if _config.ErupeConfig.RealClientMode <= _config.G7 { + towerInfo.Level = towerInfo.Level[:1] + } + for i, skill := range stringsupport.CSVElems(tempSkills) { - towerInfo.Skill[0].Unk1[i] = int16(skill) + towerInfo.Skill[0].Skills[i] = int16(skill) } switch pkt.InfoType { @@ -73,8 +86,8 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { for _, skills := range towerInfo.Skill { bf := byteframe.NewByteFrame() bf.WriteInt32(skills.TSP) - for i := range skills.Unk1 { - bf.WriteInt16(skills.Unk1[i]) + for i := range skills.Skills { + bf.WriteInt16(skills.Skills[i]) } data = append(data, bf) } @@ -89,7 +102,7 @@ func handleMsgMhfGetTowerInfo(s *Session, p mhfpacket.MHFPacket) { } data = append(data, bf) } - case 5: + case 3, 5: for _, level := range towerInfo.Level { bf := byteframe.NewByteFrame() bf.WriteInt32(level.Floors) @@ -123,8 +136,8 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) { switch pkt.InfoType { case 2: - skills := "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,0,0,0,0,0,0,0,0,0,0,0" - s.server.db.QueryRow(`SELECT skills FROM tower WHERE char_id=$1`, s.charID).Scan(&skills) + var skills string + s.server.db.QueryRow(`SELECT COALESCE(skills, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(64), s.charID).Scan(&skills) s.server.db.Exec(`UPDATE tower SET skills=$1, tsp=tsp-$2 WHERE char_id=$3`, stringsupport.CSVSetIndex(skills, int(pkt.Skill), stringsupport.CSVGetIndex(skills, int(pkt.Skill))+1), pkt.Cost, s.charID) case 1, 7: // This might give too much TSP? No idea what the rate is supposed to be @@ -412,8 +425,8 @@ func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) { gemInfo := []GemInfo{} gemHistory := []GemHistory{} - tempGems := "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,0" - s.server.db.QueryRow(`SELECT gems FROM tower WHERE char_id=$1`, s.charID).Scan(&tempGems) + var tempGems string + s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$1`, EmptyTowerCSV(30), s.charID).Scan(&tempGems) for i, v := range stringsupport.CSVElems(tempGems) { gemInfo = append(gemInfo, GemInfo{uint16(((i / 5) * 256) + ((i % 5) + 1)), uint16(v)}) } @@ -455,8 +468,8 @@ func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) { ) } - gems := "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,0" - s.server.db.QueryRow(`SELECT gems FROM tower WHERE char_id=$1`, s.charID).Scan(&gems) + var gems string + s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$1`, EmptyTowerCSV(30), s.charID).Scan(&gems) switch pkt.Op { case 1: // Add gem i := int(((pkt.Gem / 256) * 5) + (((pkt.Gem - ((pkt.Gem / 256) * 256)) - 1) % 5)) From 685f51ecb38d8e39ee7f9131b2cd4aa49498879c Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 14 Feb 2024 18:03:56 +1100 Subject: [PATCH 3/4] clean up Tower responses --- server/channelserver/handlers_tower.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_tower.go b/server/channelserver/handlers_tower.go index e075804e4..e6d4d8849 100644 --- a/server/channelserver/handlers_tower.go +++ b/server/channelserver/handlers_tower.go @@ -426,7 +426,7 @@ func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) { gemHistory := []GemHistory{} var tempGems string - s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$1`, EmptyTowerCSV(30), s.charID).Scan(&tempGems) + s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.charID).Scan(&tempGems) for i, v := range stringsupport.CSVElems(tempGems) { gemInfo = append(gemInfo, GemInfo{uint16(((i / 5) * 256) + ((i % 5) + 1)), uint16(v)}) } @@ -469,7 +469,7 @@ func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) { } var gems string - s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$1`, EmptyTowerCSV(30), s.charID).Scan(&gems) + s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.charID).Scan(&gems) switch pkt.Op { case 1: // Add gem i := int(((pkt.Gem / 256) * 5) + (((pkt.Gem - ((pkt.Gem / 256) * 256)) - 1) % 5)) From 79cdc28a01b52991e0c85c2e80311f2a8cc74214 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 14 Feb 2024 18:36:06 +1100 Subject: [PATCH 4/4] simplify Gem math --- server/channelserver/handlers_tower.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_tower.go b/server/channelserver/handlers_tower.go index e6d4d8849..8f32a7882 100644 --- a/server/channelserver/handlers_tower.go +++ b/server/channelserver/handlers_tower.go @@ -428,7 +428,7 @@ func handleMsgMhfGetGemInfo(s *Session, p mhfpacket.MHFPacket) { var tempGems string s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.charID).Scan(&tempGems) for i, v := range stringsupport.CSVElems(tempGems) { - gemInfo = append(gemInfo, GemInfo{uint16(((i / 5) * 256) + ((i % 5) + 1)), uint16(v)}) + gemInfo = append(gemInfo, GemInfo{uint16((i / 5 << 8) + (i%5 + 1)), uint16(v)}) } switch pkt.Unk0 { @@ -472,7 +472,7 @@ func handleMsgMhfPostGemInfo(s *Session, p mhfpacket.MHFPacket) { s.server.db.QueryRow(`SELECT COALESCE(gems, $1) FROM tower WHERE char_id=$2`, EmptyTowerCSV(30), s.charID).Scan(&gems) switch pkt.Op { case 1: // Add gem - i := int(((pkt.Gem / 256) * 5) + (((pkt.Gem - ((pkt.Gem / 256) * 256)) - 1) % 5)) + i := int((pkt.Gem >> 8 * 5) + (pkt.Gem - pkt.Gem&0xFF00 - 1%5)) s.server.db.Exec(`UPDATE tower SET gems=$1 WHERE char_id=$2`, stringsupport.CSVSetIndex(gems, i, stringsupport.CSVGetIndex(gems, i)+int(pkt.Quantity)), s.charID) case 2: // Transfer gem // no way im doing this for now