From d92270a249f50a8565b241adca40103c8bff3b6b Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 00:01:59 +1100 Subject: [PATCH 01/46] fix PostTinyBin parsing --- network/mhfpacket/msg_mhf_post_tiny_bin.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/network/mhfpacket/msg_mhf_post_tiny_bin.go b/network/mhfpacket/msg_mhf_post_tiny_bin.go index 4c06a51e0..7c709d1e4 100644 --- a/network/mhfpacket/msg_mhf_post_tiny_bin.go +++ b/network/mhfpacket/msg_mhf_post_tiny_bin.go @@ -11,7 +11,10 @@ import ( // MsgMhfPostTinyBin represents the MSG_MHF_POST_TINY_BIN type MsgMhfPostTinyBin struct { AckHandle uint32 - Unk []byte + Unk0 uint16 + Unk1 uint8 + Unk2 uint8 + Data []byte } // Opcode returns the ID associated with this packet type. @@ -22,7 +25,10 @@ func (m *MsgMhfPostTinyBin) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfPostTinyBin) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk = bf.ReadBytes(14) + m.Unk0 = bf.ReadUint16() + m.Unk1 = bf.ReadUint8() + m.Unk2 = bf.ReadUint8() + m.Data = bf.ReadBytes(uint(bf.ReadUint16())) return nil } From 051f2d2a4dd1c5dab4adf195ef5369b8c0241d4e Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 00:11:10 +1100 Subject: [PATCH 02/46] parse GetRyoudama correctly --- network/mhfpacket/msg_mhf_get_ryoudama.go | 26 ++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/network/mhfpacket/msg_mhf_get_ryoudama.go b/network/mhfpacket/msg_mhf_get_ryoudama.go index a173ded18..2cffc3bdc 100644 --- a/network/mhfpacket/msg_mhf_get_ryoudama.go +++ b/network/mhfpacket/msg_mhf_get_ryoudama.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" ) // MsgMhfGetRyoudama represents the MSG_MHF_GET_RYOUDAMA -type MsgMhfGetRyoudama struct{ - AckHandle uint32 - Unk0 uint16 - Unk1 uint32 - Unk2 uint8 +type MsgMhfGetRyoudama struct { + AckHandle uint32 + Unk0 uint8 + Unk1 uint8 + GuildID uint32 + Unk3 uint8 } // Opcode returns the ID associated with this packet type. @@ -24,9 +25,10 @@ func (m *MsgMhfGetRyoudama) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetRyoudama) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint16() - m.Unk1 = bf.ReadUint32() - m.Unk2 = bf.ReadUint8() + m.Unk0 = bf.ReadUint8() + m.Unk1 = bf.ReadUint8() + m.GuildID = bf.ReadUint32() + m.Unk3 = bf.ReadUint8() return nil } From ab4669acc9fcd23368e7ef94c3c07e012b3e2e8d Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 00:57:14 +1100 Subject: [PATCH 03/46] unhide EnumerateQuest packet logs --- server/channelserver/sys_session.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 7691cb3a0..970ce1b11 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -228,7 +228,6 @@ func ignored(opcode network.PacketID) bool { network.MSG_SYS_TIME, network.MSG_SYS_EXTEND_THRESHOLD, network.MSG_SYS_POSITION_OBJECT, - network.MSG_MHF_ENUMERATE_QUEST, network.MSG_MHF_SAVEDATA, } set := make(map[network.PacketID]struct{}, len(ignoreList)) From c110082ab515641fd75f22f5d005501d5b46eb6d Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 01:08:21 +1100 Subject: [PATCH 04/46] test session timeout --- server/channelserver/sys_session.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 970ce1b11..0bdf8e335 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -32,6 +32,7 @@ type Session struct { cryptConn *network.CryptConn sendPackets chan packet clientContext *clientctx.ClientContext + lastPacket time.Time userEnteredStage bool // If the user has entered a stage before stageID string @@ -73,6 +74,7 @@ func NewSession(server *Server, conn net.Conn) *Session { cryptConn: network.NewCryptConn(conn), sendPackets: make(chan packet, 20), clientContext: &clientctx.ClientContext{}, // Unused + lastPacket: time.Now(), sessionStart: TimeAdjusted().Unix(), stageMoveStack: stringstack.New(), } @@ -160,6 +162,10 @@ func (s *Session) sendLoop() { func (s *Session) recvLoop() { for { + if time.Now().Add(-30 * time.Second).After(s.lastPacket) { + logoutPlayer(s) + return + } if s.closed { logoutPlayer(s) return @@ -181,6 +187,7 @@ func (s *Session) recvLoop() { } func (s *Session) handlePacketGroup(pktGroup []byte) { + s.lastPacket = time.Now() bf := byteframe.NewByteFrameFromBytes(pktGroup) opcodeUint16 := bf.ReadUint16() opcode := network.PacketID(opcodeUint16) From 29cf7add112524f4b685d6836d881f10515162cf Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 16:26:16 +1100 Subject: [PATCH 05/46] rework netcafe course activation --- config.json | 1 - network/mhfpacket/msg_sys_update_right.go | 18 +++++++++--------- server/channelserver/handlers.go | 11 ++++++++--- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/config.json b/config.json index 98311f132..cd86056a3 100644 --- a/config.json +++ b/config.json @@ -85,7 +85,6 @@ {"Name": "HunterSupport", "Enabled": false}, {"Name": "NBoost", "Enabled": false}, {"Name": "NetCafe", "Enabled": true}, - {"Name": "OfficialCafe", "Enabled": true}, {"Name": "HLRenewing", "Enabled": true}, {"Name": "EXRenewing", "Enabled": true} ], diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go index d6260c934..8364e37bf 100644 --- a/network/mhfpacket/msg_sys_update_right.go +++ b/network/mhfpacket/msg_sys_update_right.go @@ -78,25 +78,25 @@ func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame, ctx *clientctx.Client func Courses() []Course { var courses = []Course{ {Aliases: []string{"Trial", "TL"}, ID: 1}, - {Aliases: []string{"HunterLife", "HL"}, ID: 2}, + {Aliases: []string{"HunterLife", "HL"}, ID: 2}, // BASIC {Aliases: []string{"Extra", "ExtraA", "EX"}, ID: 3}, {Aliases: []string{"ExtraB"}, ID: 4}, {Aliases: []string{"Mobile"}, ID: 5}, {Aliases: []string{"Premium"}, ID: 6}, {Aliases: []string{"Pallone", "ExtraC"}, ID: 7}, - {Aliases: []string{"Assist", "Legend", "Rasta"}, ID: 8}, // Legend + {Aliases: []string{"Assist", "Legend", "Rasta"}, ID: 8}, // LEGEND {Aliases: []string{"N"}, ID: 9}, - {Aliases: []string{"Hiden", "Secret"}, ID: 10}, // Secret - {Aliases: []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, ID: 11}, // Royal + {Aliases: []string{"Hiden", "Secret"}, ID: 10}, // SECRET + {Aliases: []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, ID: 11}, // ROYAL {Aliases: []string{"NBoost", "NetCafeBoost", "Boost"}, ID: 12}, // 13-19 = (unknown), 20 = DEBUG, 21 = COG_LINK_EXPIRED, 22 = 360_GOLD, 23 = PS3_TROP {Aliases: []string{"COG"}, ID: 24}, - {Aliases: []string{"NetCafe", "Cafe", "InternetCafe"}, ID: 25}, - {Aliases: []string{"OfficialCafe", "Official"}, ID: 26}, - {Aliases: []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew"}, ID: 27}, - {Aliases: []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew"}, ID: 28}, + // 25 = CAFE_SP, active with 26 but useless on it's own? Just use OFFICIAL and set bit + {Aliases: []string{"NetCafe", "Cafe", "OfficialCafe", "Official"}, ID: 26}, + {Aliases: []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew"}, ID: 27}, // CARD + {Aliases: []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew"}, ID: 28}, // CARD_EX {Aliases: []string{"Free"}, ID: 29}, - // 30 = real netcafe bit + // 30 = NETCAFE, what actually gives you any NetCafe gameplay benefits } for i := range courses { courses[i].Value = uint32(math.Pow(2, float64(courses[i].ID))) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 5ca89c86d..343b12094 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -78,13 +78,18 @@ func updateRights(s *Session) { 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) s.courses = mhfpacket.GetCourseStruct(rightsInt) rights := []mhfpacket.ClientRight{{1, 0, 0}} - var netcafeBitSet bool + var normalCafeBitSet, netcafeBitSet bool for _, course := range s.courses { - if (course.ID == 9 || course.ID == 25 || course.ID == 26) && !netcafeBitSet { + if (course.ID == 9 || course.ID == 26) && !netcafeBitSet { netcafeBitSet = true - rightsInt += 0x40000000 // set netcafe bit + rightsInt += 0x40000000 rights = append(rights, mhfpacket.ClientRight{ID: 30}) } + if (course.ID == 26) && !normalCafeBitSet { + normalCafeBitSet = true + rightsInt += 0x2000000 + rights = append(rights, mhfpacket.ClientRight{ID: 25}) + } rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0}) } update := &mhfpacket.MsgSysUpdateRight{ From bcb71536ec9977725fb55dc1739a58c60d816304 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 23:17:14 +1100 Subject: [PATCH 06/46] initial rights v4 concept --- common/mhfcourse/mhfcourse.go | 99 ++++++++++++++++++++ network/mhfpacket/msg_sys_update_right.go | 90 ++---------------- server/channelserver/handlers.go | 24 +---- server/channelserver/handlers_cafe.go | 3 +- server/channelserver/handlers_cast_binary.go | 29 +++--- server/channelserver/sys_session.go | 15 +-- server/signserver/dbutils.go | 4 +- 7 files changed, 135 insertions(+), 129 deletions(-) create mode 100644 common/mhfcourse/mhfcourse.go diff --git a/common/mhfcourse/mhfcourse.go b/common/mhfcourse/mhfcourse.go new file mode 100644 index 000000000..48b310489 --- /dev/null +++ b/common/mhfcourse/mhfcourse.go @@ -0,0 +1,99 @@ +package mhfcourse + +import ( + "golang.org/x/exp/slices" + "math" + "time" +) + +type Course struct { + ID uint16 + Expiry time.Time +} + +func (c Course) Aliases() []string { + aliases := make(map[uint16][]string) + aliases[1] = []string{"Trial", "TL"} + aliases[2] = []string{"HunterLife", "HL"} + aliases[3] = []string{"Extra", "ExtraA", "EX"} + aliases[4] = []string{"ExtraB"} + aliases[5] = []string{"Mobile"} + aliases[6] = []string{"Premium"} + aliases[7] = []string{"Pallone", "ExtraC"} + aliases[8] = []string{"Assist", "***ist", "Legend", "Rasta"} + aliases[9] = []string{"N"} + aliases[10] = []string{"Hiden", "Secret"} + aliases[11] = []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"} + aliases[12] = []string{"NBoost", "NetCafeBoost", "Boost"} + aliases[20] = []string{"DEBUG"} + aliases[21] = []string{"COG_LINK_EXPIRED"} + aliases[22] = []string{"360_GOLD"} + aliases[23] = []string{"PS3_TROP"} + aliases[24] = []string{"COG"} + aliases[25] = []string{"CAFE_SP"} + aliases[26] = []string{"NetCafe", "Cafe", "OfficialCafe", "Official"} + aliases[27] = []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew", "CardHL"} + aliases[28] = []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew", "CardEX"} + aliases[29] = []string{"Free"} + return aliases[c.ID] +} + +func Courses() []Course { + courses := make([]Course, 32) + for i := range courses { + courses[i].ID = uint16(i) + courses[i].Expiry = time.Time{} + } + return courses +} + +func (c Course) Value() uint32 { + return uint32(math.Pow(2, float64(c.ID))) +} + +// CourseExists returns true if the named course exists in the given slice +func CourseExists(ID uint16, c []Course) bool { + for _, course := range c { + if course.ID == ID { + return true + } + } + return false +} + +// GetCourseStruct returns a slice of Course(s) from a rights integer +func GetCourseStruct(rights uint32) ([]Course, uint32) { + resp := []Course{{ID: 1, Expiry: time.Time{}}} + s := Courses() + slices.SortStableFunc(s, func(i, j Course) bool { + return i.ID > j.ID + }) + var normalCafeCourseSet, netcafeCourseSet bool + for _, course := range s { + if rights-course.Value() < 0x80000000 { + switch course.ID { + case 26: + if normalCafeCourseSet { + break + } + normalCafeCourseSet = true + resp = append(resp, Course{ID: 25, Expiry: time.Time{}}) + fallthrough + case 9: + if netcafeCourseSet { + break + } + netcafeCourseSet = true + resp = append(resp, Course{ID: 30, Expiry: time.Time{}}) + } + course.Expiry = time.Date(2030, 1, 1, 0, 0, 0, 0, time.FixedZone("UTC+9", 9*60*60)) + resp = append(resp, course) + rights -= course.Value() + } + } + rights = 0 + for _, course := range resp { + rights += course.Value() + } + return resp, rights +} diff --git a/network/mhfpacket/msg_sys_update_right.go b/network/mhfpacket/msg_sys_update_right.go index 8364e37bf..c384deece 100644 --- a/network/mhfpacket/msg_sys_update_right.go +++ b/network/mhfpacket/msg_sys_update_right.go @@ -3,50 +3,17 @@ package mhfpacket import ( "errors" "erupe-ce/common/byteframe" + "erupe-ce/common/mhfcourse" ps "erupe-ce/common/pascalstring" "erupe-ce/network" "erupe-ce/network/clientctx" - "golang.org/x/exp/slices" - "math" ) -/* -00 58 // Opcode - -00 00 00 00 -00 00 00 4e - -00 04 // Count -00 00 // Skipped(padding?) - -00 01 00 00 00 00 00 00 -00 02 00 00 5d fa 14 c0 -00 03 00 00 5d fa 14 c0 -00 06 00 00 5d e7 05 10 - -00 00 // Count of some buf up to 0x800 bytes following it. - -00 10 // Trailer -*/ - -// ClientRight represents a right that the client has. -type ClientRight struct { - ID uint16 - Unk0 uint16 - Timestamp uint32 -} - -type Course struct { - Aliases []string - ID uint16 - Value uint32 -} - // MsgSysUpdateRight represents the MSG_SYS_UPDATE_RIGHT type MsgSysUpdateRight struct { ClientRespAckHandle uint32 // If non-0, requests the client to send back a MSG_SYS_ACK packet with this value. Bitfield uint32 - Rights []ClientRight + Rights []mhfcourse.Course UnkSize uint16 // Count of some buf up to 0x800 bytes following it. } @@ -68,54 +35,13 @@ func (m *MsgSysUpdateRight) Build(bf *byteframe.ByteFrame, ctx *clientctx.Client bf.WriteUint16(0) for _, v := range m.Rights { bf.WriteUint16(v.ID) - bf.WriteUint16(v.Unk0) - bf.WriteUint32(v.Timestamp) + bf.WriteUint16(0) + if v.Expiry.IsZero() { + bf.WriteUint32(0) + } else { + bf.WriteUint32(uint32(v.Expiry.Unix())) + } } ps.Uint16(bf, "", false) // update client login token / password in the game's launcherstate struct return nil } - -func Courses() []Course { - var courses = []Course{ - {Aliases: []string{"Trial", "TL"}, ID: 1}, - {Aliases: []string{"HunterLife", "HL"}, ID: 2}, // BASIC - {Aliases: []string{"Extra", "ExtraA", "EX"}, ID: 3}, - {Aliases: []string{"ExtraB"}, ID: 4}, - {Aliases: []string{"Mobile"}, ID: 5}, - {Aliases: []string{"Premium"}, ID: 6}, - {Aliases: []string{"Pallone", "ExtraC"}, ID: 7}, - {Aliases: []string{"Assist", "Legend", "Rasta"}, ID: 8}, // LEGEND - {Aliases: []string{"N"}, ID: 9}, - {Aliases: []string{"Hiden", "Secret"}, ID: 10}, // SECRET - {Aliases: []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, ID: 11}, // ROYAL - {Aliases: []string{"NBoost", "NetCafeBoost", "Boost"}, ID: 12}, - // 13-19 = (unknown), 20 = DEBUG, 21 = COG_LINK_EXPIRED, 22 = 360_GOLD, 23 = PS3_TROP - {Aliases: []string{"COG"}, ID: 24}, - // 25 = CAFE_SP, active with 26 but useless on it's own? Just use OFFICIAL and set bit - {Aliases: []string{"NetCafe", "Cafe", "OfficialCafe", "Official"}, ID: 26}, - {Aliases: []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew"}, ID: 27}, // CARD - {Aliases: []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew"}, ID: 28}, // CARD_EX - {Aliases: []string{"Free"}, ID: 29}, - // 30 = NETCAFE, what actually gives you any NetCafe gameplay benefits - } - for i := range courses { - courses[i].Value = uint32(math.Pow(2, float64(courses[i].ID))) - } - return courses -} - -// GetCourseStruct returns a slice of Course(s) from a rights integer -func GetCourseStruct(rights uint32) []Course { - var resp []Course - s := Courses() - slices.SortStableFunc(s, func(i, j Course) bool { - return i.ID > j.ID - }) - for _, course := range s { - if rights-course.Value < 0x80000000 { - resp = append(resp, course) - rights -= course.Value - } - } - return resp -} diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 343b12094..d22f8be3b 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -3,6 +3,7 @@ package channelserver import ( "encoding/binary" "encoding/hex" + "erupe-ce/common/mhfcourse" ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" "fmt" @@ -74,28 +75,13 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) { } func updateRights(s *Session) { - rightsInt := uint32(0x0E) + rightsInt := uint32(2) 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) - s.courses = mhfpacket.GetCourseStruct(rightsInt) - rights := []mhfpacket.ClientRight{{1, 0, 0}} - var normalCafeBitSet, netcafeBitSet bool - for _, course := range s.courses { - if (course.ID == 9 || course.ID == 26) && !netcafeBitSet { - netcafeBitSet = true - rightsInt += 0x40000000 - rights = append(rights, mhfpacket.ClientRight{ID: 30}) - } - if (course.ID == 26) && !normalCafeBitSet { - normalCafeBitSet = true - rightsInt += 0x2000000 - rights = append(rights, mhfpacket.ClientRight{ID: 25}) - } - rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0}) - } + s.courses, rightsInt = mhfcourse.GetCourseStruct(rightsInt) update := &mhfpacket.MsgSysUpdateRight{ ClientRespAckHandle: 0, Bitfield: rightsInt, - Rights: rights, + Rights: s.courses, UnkSize: 0, } s.QueueSendMHF(update) @@ -226,7 +212,7 @@ func logoutPlayer(s *Session) { timePlayed += sessionTime var rpGained int - if s.FindCourse("NetCafe").ID != 0 || s.FindCourse("N").ID != 0 { + if mhfcourse.CourseExists(30, s.courses) { rpGained = timePlayed / 900 timePlayed = timePlayed % 900 s.server.db.Exec("UPDATE characters SET cafe_time=cafe_time+$1 WHERE id=$2", sessionTime, s.charID) diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go index 2973472de..46a6425a0 100644 --- a/server/channelserver/handlers_cafe.go +++ b/server/channelserver/handlers_cafe.go @@ -2,6 +2,7 @@ package channelserver import ( "erupe-ce/common/byteframe" + "erupe-ce/common/mhfcourse" ps "erupe-ce/common/pascalstring" "erupe-ce/network/mhfpacket" "fmt" @@ -88,7 +89,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) { if err != nil { panic(err) } - if s.FindCourse("NetCafe").ID != 0 || s.FindCourse("N").ID != 0 { + if mhfcourse.CourseExists(30, s.courses) { cafeTime = uint32(TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime } bf.WriteUint32(cafeTime) // Total cafe time diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 9ef5eec4e..7c4066d1d 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -3,6 +3,7 @@ package channelserver import ( "encoding/hex" "erupe-ce/common/byteframe" + "erupe-ce/common/mhfcourse" "erupe-ce/config" "erupe-ce/network/binpacket" "erupe-ce/network/mhfpacket" @@ -192,13 +193,14 @@ func parseChatCommand(s *Session, command string) { sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix)) } else { name = strings.ToLower(name) - for _, course := range mhfpacket.Courses() { - for _, alias := range course.Aliases { + for _, course := range mhfcourse.Courses() { + for _, alias := range course.Aliases() { if strings.ToLower(name) == strings.ToLower(alias) { - if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) { - if s.FindCourse(name).ID != 0 { - ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool { - for _, alias := range c.Aliases { + 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) { return true } @@ -206,21 +208,22 @@ func parseChatCommand(s *Session, command string) { return false }) if ei != -1 { + delta = uint32(-1 * math.Pow(2, float64(course.ID))) s.courses = append(s.courses[:ei], s.courses[ei+1:]...) - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseDisabled"], course.Aliases[0])) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseDisabled"], course.Aliases()[0])) } } else { + delta = uint32(math.Pow(2, float64(course.ID))) s.courses = append(s.courses, course) - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases[0])) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases()[0])) } - var newInt uint32 - for _, course := range s.courses { - newInt += uint32(math.Pow(2, float64(course.ID))) + 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 rightsInt > 0 { + 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) } - s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID) updateRights(s) } else { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseLocked"], course.Aliases[0])) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseLocked"], course.Aliases()[0])) } } } diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index 0bdf8e335..40d54fdb3 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -3,10 +3,10 @@ package channelserver import ( "encoding/binary" "encoding/hex" + "erupe-ce/common/mhfcourse" "fmt" "io" "net" - "strings" "sync" "time" @@ -43,7 +43,7 @@ type Session struct { charID uint32 logKey []byte sessionStart int64 - courses []mhfpacket.Course + courses []mhfcourse.Course token string kqf []byte kqfOverride bool @@ -268,14 +268,3 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data)) } } - -func (s *Session) FindCourse(name string) mhfpacket.Course { - for _, course := range s.courses { - for _, alias := range course.Aliases { - if strings.ToLower(name) == strings.ToLower(alias) { - return course - } - } - } - return mhfpacket.Course{} -} diff --git a/server/signserver/dbutils.go b/server/signserver/dbutils.go index 213a74a14..ee4dcc493 100644 --- a/server/signserver/dbutils.go +++ b/server/signserver/dbutils.go @@ -1,6 +1,7 @@ package signserver import ( + "erupe-ce/common/mhfcourse" "strings" "time" @@ -119,8 +120,9 @@ func (s *Server) getLastCID(uid int) uint32 { } func (s *Server) getUserRights(uid int) uint32 { - var rights uint32 + rights := uint32(2) _ = s.db.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights) + _, rights = mhfcourse.GetCourseStruct(rights) return rights } From 0a98a651b1b4f29de885d85196f6260fe6187be5 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 23:33:48 +1100 Subject: [PATCH 07/46] simplify course alias definition --- common/mhfcourse/mhfcourse.go | 48 ++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/common/mhfcourse/mhfcourse.go b/common/mhfcourse/mhfcourse.go index 48b310489..848d84c48 100644 --- a/common/mhfcourse/mhfcourse.go +++ b/common/mhfcourse/mhfcourse.go @@ -11,30 +11,32 @@ type Course struct { Expiry time.Time } +var aliases = map[uint16][]string{ + 1: {"Trial", "TL"}, + 2: {"HunterLife", "HL"}, + 3: {"Extra", "ExtraA", "EX"}, + 4: {"ExtraB"}, + 5: {"Mobile"}, + 6: {"Premium"}, + 7: {"Pallone", "ExtraC"}, + 8: {"Assist", "***ist", "Legend", "Rasta"}, + 9: {"N"}, + 10: {"Hiden", "Secret"}, + 11: {"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, + 12: {"NBoost", "NetCafeBoost", "Boost"}, + 20: {"DEBUG"}, + 21: {"COG_LINK_EXPIRED"}, + 22: {"360_GOLD"}, + 23: {"PS3_TROP"}, + 24: {"COG"}, + 25: {"CAFE_SP"}, + 26: {"NetCafe", "Cafe", "OfficialCafe", "Official"}, + 27: {"HLRenewing", "HLR", "HLRenewal", "HLRenew", "CardHL"}, + 28: {"EXRenewing", "EXR", "EXRenewal", "EXRenew", "CardEX"}, + 29: {"Free"}, +} + func (c Course) Aliases() []string { - aliases := make(map[uint16][]string) - aliases[1] = []string{"Trial", "TL"} - aliases[2] = []string{"HunterLife", "HL"} - aliases[3] = []string{"Extra", "ExtraA", "EX"} - aliases[4] = []string{"ExtraB"} - aliases[5] = []string{"Mobile"} - aliases[6] = []string{"Premium"} - aliases[7] = []string{"Pallone", "ExtraC"} - aliases[8] = []string{"Assist", "***ist", "Legend", "Rasta"} - aliases[9] = []string{"N"} - aliases[10] = []string{"Hiden", "Secret"} - aliases[11] = []string{"HunterSupport", "HunterAid", "Support", "Aid", "Royal"} - aliases[12] = []string{"NBoost", "NetCafeBoost", "Boost"} - aliases[20] = []string{"DEBUG"} - aliases[21] = []string{"COG_LINK_EXPIRED"} - aliases[22] = []string{"360_GOLD"} - aliases[23] = []string{"PS3_TROP"} - aliases[24] = []string{"COG"} - aliases[25] = []string{"CAFE_SP"} - aliases[26] = []string{"NetCafe", "Cafe", "OfficialCafe", "Official"} - aliases[27] = []string{"HLRenewing", "HLR", "HLRenewal", "HLRenew", "CardHL"} - aliases[28] = []string{"EXRenewing", "EXR", "EXRenewal", "EXRenew", "CardEX"} - aliases[29] = []string{"Free"} return aliases[c.ID] } From 41df26928c3f7f31d6621fb62aed1335c8675679 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 23:34:19 +1100 Subject: [PATCH 08/46] remove useless time initialisers --- common/mhfcourse/mhfcourse.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common/mhfcourse/mhfcourse.go b/common/mhfcourse/mhfcourse.go index 848d84c48..a1c12f8b5 100644 --- a/common/mhfcourse/mhfcourse.go +++ b/common/mhfcourse/mhfcourse.go @@ -44,7 +44,6 @@ func Courses() []Course { courses := make([]Course, 32) for i := range courses { courses[i].ID = uint16(i) - courses[i].Expiry = time.Time{} } return courses } @@ -65,7 +64,7 @@ func CourseExists(ID uint16, c []Course) bool { // GetCourseStruct returns a slice of Course(s) from a rights integer func GetCourseStruct(rights uint32) ([]Course, uint32) { - resp := []Course{{ID: 1, Expiry: time.Time{}}} + resp := []Course{{ID: 1}} s := Courses() slices.SortStableFunc(s, func(i, j Course) bool { return i.ID > j.ID @@ -79,14 +78,14 @@ func GetCourseStruct(rights uint32) ([]Course, uint32) { break } normalCafeCourseSet = true - resp = append(resp, Course{ID: 25, Expiry: time.Time{}}) + resp = append(resp, Course{ID: 25}) fallthrough case 9: if netcafeCourseSet { break } netcafeCourseSet = true - resp = append(resp, Course{ID: 30, Expiry: time.Time{}}) + resp = append(resp, Course{ID: 30}) } course.Expiry = time.Date(2030, 1, 1, 0, 0, 0, 0, time.FixedZone("UTC+9", 9*60*60)) resp = append(resp, course) From c95d02ec82233e32b91882f6deaedb076326c4c7 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 23:34:43 +1100 Subject: [PATCH 09/46] fix edge case on 0 rights int --- server/channelserver/handlers_cast_binary.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 7c4066d1d..9143491e4 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -217,8 +217,8 @@ func parseChatCommand(s *Session, command string) { s.courses = append(s.courses, course) sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases()[0])) } - 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 rightsInt > 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) + 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) } updateRights(s) From baf53ea212b8799391b6d5bcc84c6f8ca70ef5c3 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 11 Mar 2023 23:40:49 +1100 Subject: [PATCH 10/46] flip error check in course command and remove unused code --- server/channelserver/handlers_cast_binary.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 9143491e4..ba6428386 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -209,16 +209,14 @@ func parseChatCommand(s *Session, command string) { }) if ei != -1 { delta = uint32(-1 * math.Pow(2, float64(course.ID))) - s.courses = append(s.courses[:ei], s.courses[ei+1:]...) sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseDisabled"], course.Aliases()[0])) } } else { delta = uint32(math.Pow(2, float64(course.ID))) - s.courses = append(s.courses, course) 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) - if err != nil { + 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) } updateRights(s) From 9a4204268647ed05460744458af547605a9c14da Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 01:59:21 +1100 Subject: [PATCH 11/46] improve course command responses --- server/channelserver/handlers_cast_binary.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index ba6428386..10d15938a 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -223,9 +223,11 @@ func parseChatCommand(s *Session, command string) { } else { sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseLocked"], course.Aliases()[0])) } + return } } } + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix)) } } else { sendDisabledCommandMessage(s, commands["Course"]) From 5761a38000ca97e06c28aeb822b94c4ac7e4e1a1 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 02:09:36 +1100 Subject: [PATCH 12/46] extra content --- common/mhfcourse/mhfcourse.go | 2 ++ patch-schema/rights-v4.sql | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 patch-schema/rights-v4.sql diff --git a/common/mhfcourse/mhfcourse.go b/common/mhfcourse/mhfcourse.go index a1c12f8b5..62b8d171f 100644 --- a/common/mhfcourse/mhfcourse.go +++ b/common/mhfcourse/mhfcourse.go @@ -24,6 +24,7 @@ var aliases = map[uint16][]string{ 10: {"Hiden", "Secret"}, 11: {"HunterSupport", "HunterAid", "Support", "Aid", "Royal"}, 12: {"NBoost", "NetCafeBoost", "Boost"}, + // 13-19 show up as (unknown) 20: {"DEBUG"}, 21: {"COG_LINK_EXPIRED"}, 22: {"360_GOLD"}, @@ -34,6 +35,7 @@ var aliases = map[uint16][]string{ 27: {"HLRenewing", "HLR", "HLRenewal", "HLRenew", "CardHL"}, 28: {"EXRenewing", "EXR", "EXRenewal", "EXRenew", "CardEX"}, 29: {"Free"}, + // 30 = Real NetCafe course } func (c Course) Aliases() []string { diff --git a/patch-schema/rights-v4.sql b/patch-schema/rights-v4.sql new file mode 100644 index 000000000..9732097ed --- /dev/null +++ b/patch-schema/rights-v4.sql @@ -0,0 +1,6 @@ +BEGIN; + +-- Remove Trial Course from all users +UPDATE users SET rights = rights-2; + +END; \ No newline at end of file From 40d5c6790232625ab6dadcf4d1afa27cd2462c1f Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 22:05:42 +1100 Subject: [PATCH 13/46] merge shop enumeration fixes from feature/diva --- patch-schema/shop-db.sql | 44 +++++-- server/channelserver/handlers_shop_gacha.go | 138 ++++++++++---------- 2 files changed, 103 insertions(+), 79 deletions(-) diff --git a/patch-schema/shop-db.sql b/patch-schema/shop-db.sql index b95b26ca1..75f086f05 100644 --- a/patch-schema/shop-db.sql +++ b/patch-schema/shop-db.sql @@ -1,39 +1,59 @@ BEGIN; ALTER TABLE IF EXISTS public.normal_shop_items + RENAME TO shop_items; + +ALTER TABLE IF EXISTS public.shop_items + RENAME COLUMN shoptype TO shop_type; + +ALTER TABLE IF EXISTS public.shop_items + RENAME COLUMN shopid TO shop_id; + +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemhash TO id; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items + RENAME COLUMN itemid TO item_id; + +ALTER TABLE IF EXISTS public.shop_items ALTER COLUMN points TYPE integer; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN points TO cost; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN tradequantity TO quantity; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqlow TO min_hr; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqhigh TO min_sr; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqg TO min_gr; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN storelevelreq TO req_store_level; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN maximumquantity TO max_quantity; -ALTER TABLE IF EXISTS public.normal_shop_items - DROP COLUMN boughtquantity; +ALTER TABLE IF EXISTS public.shop_items + DROP COLUMN IF EXISTS boughtquantity; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN roadfloorsrequired TO road_floors; -ALTER TABLE IF EXISTS public.normal_shop_items +ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN weeklyfataliskills TO road_fatalis; +DROP TABLE IF EXISTS public.shop_item_state; + +CREATE TABLE IF NOT EXISTS public.shop_items_bought ( + character_id INTEGER, + shop_item_id INTEGER, + bought INTEGER +); + END; \ No newline at end of file diff --git a/server/channelserver/handlers_shop_gacha.go b/server/channelserver/handlers_shop_gacha.go index 2b07b3168..2ebf209ea 100644 --- a/server/channelserver/handlers_shop_gacha.go +++ b/server/channelserver/handlers_shop_gacha.go @@ -1,7 +1,6 @@ package channelserver import ( - "encoding/hex" "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" "erupe-ce/network/mhfpacket" @@ -9,18 +8,18 @@ import ( ) type ShopItem struct { - ID uint32 `db:"id"` - ItemID uint16 `db:"itemid"` - Cost uint32 `db:"cost"` - Quantity uint16 `db:"quantity"` - MinHR uint16 `db:"min_hr"` - MinSR uint16 `db:"min_sr"` - MinGR uint16 `db:"min_gr"` - ReqStoreLevel uint16 `db:"req_store_level"` - MaxQuantity uint16 `db:"max_quantity"` - CharQuantity uint16 `db:"char_quantity"` - RoadFloors uint16 `db:"road_floors"` - RoadFatalis uint16 `db:"road_fatalis"` + ID uint32 `db:"id"` + ItemID uint16 `db:"item_id"` + Cost uint32 `db:"cost"` + Quantity uint16 `db:"quantity"` + MinHR uint16 `db:"min_hr"` + MinSR uint16 `db:"min_sr"` + MinGR uint16 `db:"min_gr"` + StoreLevel uint16 `db:"store_level"` + MaxQuantity uint16 `db:"max_quantity"` + UsedQuantity uint16 `db:"used_quantity"` + RoadFloors uint16 `db:"road_floors"` + RoadFatalis uint16 `db:"road_fatalis"` } type Gacha struct { @@ -56,6 +55,45 @@ type GachaItem struct { Quantity uint16 `db:"quantity"` } +func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) { + bf.WriteUint16(uint16(len(items))) + bf.WriteUint16(uint16(len(items))) + for _, item := range items { + bf.WriteUint32(item.ID) + bf.WriteUint16(0) + bf.WriteUint16(item.ItemID) + bf.WriteUint32(item.Cost) + bf.WriteUint16(item.Quantity) + bf.WriteUint16(item.MinHR) + bf.WriteUint16(item.MinSR) + bf.WriteUint16(item.MinGR) + bf.WriteUint16(item.StoreLevel) + bf.WriteUint16(item.MaxQuantity) + bf.WriteUint16(item.UsedQuantity) + bf.WriteUint16(item.RoadFloors) + bf.WriteUint16(item.RoadFatalis) + } +} + +func getShopItems(s *Session, shopType uint8, shopID uint32) []ShopItem { + var items []ShopItem + var temp ShopItem + rows, err := s.server.db.Queryx(`SELECT id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, + COALESCE((SELECT bought FROM shop_items_bought WHERE shop_item_id=si.id AND character_id=$3), 0) as used_quantity, + road_floors, road_fatalis FROM shop_items si WHERE shop_type=$1 AND shop_id=$2 + `, shopType, shopID, s.charID) + if err == nil { + for rows.Next() { + err = rows.StructScan(&temp) + if err != nil { + continue + } + items = append(items, temp) + } + } + return items +} + func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateShop) // Generic Shop IDs @@ -165,62 +203,25 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) { bf.Seek(4, 0) bf.WriteUint16(entryCount) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) + case 3: // Hunting Festival Exchange + fallthrough case 4: // N Points, 0-6 - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + fallthrough case 5: // GCP->Item, 0-6 - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + fallthrough case 6: // Gacha coin->Item - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) + fallthrough case 7: // Item->GCP - data, _ := hex.DecodeString("000300033a9186fb000033860000000a000100000000000000000000000000000000097fdb1c0000067e0000000a0001000000000000000000000000000000001374db29000027c300000064000100000000000000000000000000000000") - doAckBufSucceed(s, pkt.AckHandle, data) + fallthrough case 8: // Diva - switch pkt.ShopID { - case 0: // Normal exchange - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) - case 5: // GCP skills - data, _ := hex.DecodeString("001f001f2c9365c1000000010000001e000a0000000000000000000a0000000000001979f1c2000000020000003c000a0000000000000000000a0000000000003e5197df000000030000003c000a0000000000000000000a000000000000219337c0000000040000001e000a0000000000000000000a00000000000009b24c9d000000140000001e000a0000000000000000000a0000000000001f1d496e000000150000001e000a0000000000000000000a0000000000003b918fcb000000160000003c000a0000000000000000000a0000000000000b7fd81c000000170000003c000a0000000000000000000a0000000000001374f239000000180000003c000a0000000000000000000a00000000000026950cba0000001c0000003c000a0000000000000000000a0000000000003797eae70000001d0000003c000a012b000000000000000a00000000000015758ad8000000050000003c00000000000000000000000a0000000000003c7035050000000600000050000a0000000000000001000a00000000000024f3b5560000000700000050000a0000000000000001000a00000000000000b600330000000800000050000a0000000000000001000a0000000000002efdce840000001900000050000a0000000000000001000a0000000000002d9365f10000001a00000050000a0000000000000001000a0000000000001979f3420000001f00000050000a012b000000000001000a0000000000003f5397cf0000002000000050000a012b000000000001000a000000000000319337c00000002100000050000a012b000000000001000a00000000000008b04cbd0000000900000064000a0000000000000002000a0000000000000b1d4b6e0000000a00000064000a0000000000000002000a0000000000003b918feb0000000b00000064000a0000000000000002000a0000000000001b7fd81c0000000c00000064000a0000000000000002000a0000000000001276f2290000000d00000064000a0000000000000002000a00000000000022950cba0000000e000000c8000a0000000000000002000a0000000000003697ead70000000f000001f4000a0000000000000003000a00000000000005758a5800000010000003e8000a0000000000000003000a0000000000003c7035250000001b000001f4000a0000000000010003000a00000000000034f3b5d60000001e00000064000a012b000000000003000a00000000000000b600030000002200000064000a0000000000010003000a000000000000") - doAckBufSucceed(s, pkt.AckHandle, data) - case 7: // Note exchange - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) - } + fallthrough + case 9: // Diva song shop + fallthrough case 10: // Item shop, 0-8 - shopEntries, err := s.server.db.Queryx(`SELECT id, itemid, cost, quantity, min_hr, min_sr, min_gr, req_store_level, max_quantity, - COALESCE((SELECT usedquantity FROM shop_item_state WHERE itemhash=nsi.id AND char_id=$3), 0) as char_quantity, - road_floors, road_fatalis FROM normal_shop_items nsi WHERE shoptype=$1 AND shopid=$2 - `, pkt.ShopType, pkt.ShopID, s.charID) - if err != nil { - doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) - return - } - var count uint16 - resp := byteframe.NewByteFrame() - resp.WriteBytes(make([]byte, 4)) - var shopItem ShopItem - for shopEntries.Next() { - err = shopEntries.StructScan(&shopItem) - if err != nil { - continue - } - resp.WriteUint32(shopItem.ID) - resp.WriteUint16(0) - resp.WriteUint16(shopItem.ItemID) - resp.WriteUint32(shopItem.Cost) - resp.WriteUint16(shopItem.Quantity) - resp.WriteUint16(shopItem.MinHR) - resp.WriteUint16(shopItem.MinSR) - resp.WriteUint16(shopItem.MinGR) - resp.WriteUint16(shopItem.ReqStoreLevel) - resp.WriteUint16(shopItem.MaxQuantity) - resp.WriteUint16(shopItem.CharQuantity) - resp.WriteUint16(shopItem.RoadFloors) - resp.WriteUint16(shopItem.RoadFatalis) - count++ - } - resp.Seek(0, 0) - resp.WriteUint16(count) - resp.WriteUint16(count) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + bf := byteframe.NewByteFrame() + items := getShopItems(s, pkt.ShopType, pkt.ShopID) + writeShopItems(bf, items) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } } @@ -230,11 +231,14 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) { exchanges := int(bf.ReadUint16()) for i := 0; i < exchanges; i++ { itemHash := bf.ReadUint32() + if itemHash == 0 { + continue + } buyCount := bf.ReadUint32() - s.server.db.Exec(`INSERT INTO shop_item_state (char_id, itemhash, usedquantity) - VALUES ($1,$2,$3) ON CONFLICT (char_id, itemhash) - DO UPDATE SET usedquantity = shop_item_state.usedquantity + $3 - WHERE EXCLUDED.char_id=$1 AND EXCLUDED.itemhash=$2 + s.server.db.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought) + VALUES ($1,$2,$3) ON CONFLICT (character_id, shop_item_id) + DO UPDATE SET bought = bought + $3 + WHERE EXCLUDED.character_id=$1 AND EXCLUDED.shop_item_id=$2 `, s.charID, itemHash, buyCount) } doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) From 2136638c37f74688b9d1b9b634ffe091f22ff3d4 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 22:08:07 +1100 Subject: [PATCH 14/46] fix missing primary key --- patch-schema/shop-db.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/patch-schema/shop-db.sql b/patch-schema/shop-db.sql index 75f086f05..dfca1574f 100644 --- a/patch-schema/shop-db.sql +++ b/patch-schema/shop-db.sql @@ -12,6 +12,9 @@ ALTER TABLE IF EXISTS public.shop_items ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemhash TO id; +ALTER TABLE IF EXISTS public.shop_items + ADD PRIMARY KEY (id); + ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemid TO item_id; From a2d24837bdedcc8a43654bb72eb7496be997103e Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 22:10:13 +1100 Subject: [PATCH 15/46] correct minor mistake --- patch-schema/shop-db.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patch-schema/shop-db.sql b/patch-schema/shop-db.sql index dfca1574f..6e75d403a 100644 --- a/patch-schema/shop-db.sql +++ b/patch-schema/shop-db.sql @@ -37,7 +37,7 @@ ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqg TO min_gr; ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN storelevelreq TO req_store_level; + RENAME COLUMN storelevelreq TO store_level; ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN maximumquantity TO max_quantity; From cce558db9c11e9d6b6bdca902b061829978112bc Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 22:28:27 +1100 Subject: [PATCH 16/46] amend comment --- server/channelserver/handlers_guild.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 7a9a128b8..08a00ebbe 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1060,7 +1060,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) { uint32 guild id uint32 guild leader id (for mail) uint32 unk (always null in pcap) - uint16 unk (always 0001 in pcap) + uint16 member count uint16 len guild name string nullterm guild name uint16 len guild leader name From ccfd2ac36f61e306698e25e1252a5836980e85f8 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 23:29:50 +1100 Subject: [PATCH 17/46] create RNG in token module --- common/token/token.go | 13 +++++++++++-- server/channelserver/handlers_cast_binary.go | 5 ++--- server/channelserver/handlers_event.go | 6 +++--- server/channelserver/handlers_festa.go | 5 ++--- server/signserver/dsgn_resp.go | 5 +---- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/common/token/token.go b/common/token/token.go index 73568bcbc..c474fdaf5 100644 --- a/common/token/token.go +++ b/common/token/token.go @@ -1,13 +1,22 @@ package token -import "math/rand" +import ( + "math/rand" + "time" +) // Generate returns an alphanumeric token of specified length func Generate(length int) string { + rng := RNG() var chars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") b := make([]rune, length) for i := range b { - b[i] = chars[rand.Intn(len(chars))] + b[i] = chars[rng.Intn(len(chars))] } return string(b) } + +// RNG returns a new RNG generator +func RNG() *rand.Rand { + return rand.New(rand.NewSource(time.Now().UnixNano())) +} diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 10d15938a..1b6b9a6ba 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -4,13 +4,13 @@ import ( "encoding/hex" "erupe-ce/common/byteframe" "erupe-ce/common/mhfcourse" + "erupe-ce/common/token" "erupe-ce/config" "erupe-ce/network/binpacket" "erupe-ce/network/mhfpacket" "fmt" "golang.org/x/exp/slices" "math" - "math/rand" "strings" "time" @@ -370,8 +370,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { roll.SetLE() roll.WriteUint16(4) // Unk roll.WriteUint16(authorLen) - rand.Seed(time.Now().UnixNano()) - dice := fmt.Sprintf("%d", rand.Intn(100)+1) + dice := fmt.Sprintf("%d", token.RNG().Intn(100)+1) roll.WriteUint16(uint16(len(dice) + 1)) roll.WriteNullTerminatedBytes([]byte(dice)) roll.WriteNullTerminatedBytes(tmp.ReadNullTerminatedBytes()) diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index 1c8d3f319..bd44e8a10 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -1,8 +1,8 @@ package channelserver import ( + "erupe-ce/common/token" "math" - "math/rand" "time" "erupe-ce/common/byteframe" @@ -95,9 +95,9 @@ func generateFeatureWeapons(count int) activeFeature { } nums := make([]int, 0) var result int - r := rand.New(rand.NewSource(time.Now().UnixNano())) + rng := token.RNG() for len(nums) < count { - num := r.Intn(14) + num := rng.Intn(14) exist := false for _, v := range nums { if v == num { diff --git a/server/channelserver/handlers_festa.go b/server/channelserver/handlers_festa.go index 2659aae1d..155cee3d8 100644 --- a/server/channelserver/handlers_festa.go +++ b/server/channelserver/handlers_festa.go @@ -4,8 +4,8 @@ import ( "encoding/hex" "erupe-ce/common/byteframe" ps "erupe-ce/common/pascalstring" + "erupe-ce/common/token" "erupe-ce/network/mhfpacket" - "math/rand" "sort" "time" ) @@ -336,8 +336,7 @@ func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } - rand.Seed(time.Now().UnixNano()) - team := uint32(rand.Intn(2)) + team := uint32(token.RNG().Intn(2)) switch team { case 0: s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID) diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index 1fc78f3d9..3df3bdf71 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -7,11 +7,9 @@ import ( "erupe-ce/common/token" "erupe-ce/server/channelserver" "fmt" - "math/rand" + "go.uber.org/zap" "strings" "time" - - "go.uber.org/zap" ) func makeSignInFailureResp(respID RespID) []byte { @@ -29,7 +27,6 @@ func (s *Session) makeSignInResp(uid int) []byte { s.logger.Warn("Error getting characters from DB", zap.Error(err)) } - rand.Seed(time.Now().UnixNano()) sessToken := token.Generate(16) s.server.registerToken(uid, sessToken) From 6aa075009ea80d67b081ebc5f6b344b9623d52fa Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 23:31:39 +1100 Subject: [PATCH 18/46] timestamp fixes --- server/channelserver/handlers_guild_scout.go | 8 +++----- server/channelserver/sys_stage.go | 4 ---- server/signserver/dsgn_resp.go | 11 +++++------ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/server/channelserver/handlers_guild_scout.go b/server/channelserver/handlers_guild_scout.go index 4b45cc93b..d171750d4 100644 --- a/server/channelserver/handlers_guild_scout.go +++ b/server/channelserver/handlers_guild_scout.go @@ -1,14 +1,12 @@ package channelserver import ( - "fmt" - "io" - "time" - "erupe-ce/common/byteframe" "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" + "fmt" "go.uber.org/zap" + "io" ) func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) { @@ -247,7 +245,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(charID) bf.WriteUint32(actorID) bf.WriteUint32(charID) - bf.WriteUint32(uint32(time.Now().Unix())) + bf.WriteUint32(uint32(TimeAdjusted().Unix())) bf.WriteUint16(0x00) // HR? bf.WriteUint16(0x00) // GR? diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go index 532ae60d4..b69995724 100644 --- a/server/channelserver/sys_stage.go +++ b/server/channelserver/sys_stage.go @@ -3,8 +3,6 @@ package channelserver import ( "sync" - "time" - "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" ) @@ -49,7 +47,6 @@ type Stage struct { host *Session maxPlayers uint16 password string - createdAt string } // NewStage creates a new stage with intialized values. @@ -62,7 +59,6 @@ func NewStage(ID string) *Stage { objectIndex: 0, rawBinaryData: make(map[stageBinaryKey][]byte), maxPlayers: 4, - createdAt: time.Now().Format("01-02-2006 15:04:05"), } return s } diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index 3df3bdf71..7e9305434 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -9,7 +9,6 @@ import ( "fmt" "go.uber.org/zap" "strings" - "time" ) func makeSignInFailureResp(respID RespID) []byte { @@ -38,11 +37,11 @@ func (s *Session) makeSignInResp(uid int) []byte { } else { bf.WriteUint8(0) } - bf.WriteUint8(1) // entrance server count - bf.WriteUint8(uint8(len(chars))) // character count - bf.WriteUint32(0xFFFFFFFF) // login_token_number - bf.WriteBytes([]byte(sessToken)) // login_token - bf.WriteUint32(uint32(time.Now().Unix())) // current time + bf.WriteUint8(1) // entrance server count + bf.WriteUint8(uint8(len(chars))) + bf.WriteUint32(0xFFFFFFFF) // login_token_number + bf.WriteBytes([]byte(sessToken)) + bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix())) if s.server.erupeConfig.DevMode { if s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "" { ps.Uint8(bf, s.server.erupeConfig.PatchServerManifest, false) From a2a4989cdadb79423680bbad70f63c0b5d634923 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 23:36:26 +1100 Subject: [PATCH 19/46] replace outdated code --- common/stringsupport/string_convert.go | 44 -------------------- server/channelserver/handlers_guild_scout.go | 6 +-- 2 files changed, 1 insertion(+), 49 deletions(-) diff --git a/common/stringsupport/string_convert.go b/common/stringsupport/string_convert.go index ab91311ac..337588479 100644 --- a/common/stringsupport/string_convert.go +++ b/common/stringsupport/string_convert.go @@ -58,31 +58,6 @@ func (sc *StringConverter) MustEncode(data string) []byte { return encoded } -/* -func MustConvertShiftJISToUTF8(text string) string { - result, err := ConvertShiftJISToUTF8(text) - if err != nil { - panic(err) - } - return result -} -func MustConvertUTF8ToShiftJIS(text string) string { - result, err := ConvertUTF8ToShiftJIS(text) - if err != nil { - panic(err) - } - return result -} -func ConvertShiftJISToUTF8(text string) (string, error) { - r := bytes.NewBuffer([]byte(text)) - decoded, err := ioutil.ReadAll(transform.NewReader(r, japanese.ShiftJIS.NewDecoder())) - if err != nil { - return "", err - } - return string(decoded), nil -} -*/ - func UTF8ToSJIS(x string) []byte { e := japanese.ShiftJIS.NewEncoder() xt, _, err := transform.String(e, x) @@ -169,22 +144,3 @@ func CSVElems(csv string) []int { } return r } - -// ConvertUTF8ToShiftJIS converts a UTF8 string to a Shift-JIS []byte. -func ConvertUTF8ToShiftJIS(text string) ([]byte, error) { - r := bytes.NewBuffer([]byte(text)) - encoded, err := ioutil.ReadAll(transform.NewReader(r, japanese.ShiftJIS.NewEncoder())) - if err != nil { - return nil, err - } - - return encoded, nil -} - -func ConvertUTF8ToSJIS(text string) (string, error) { - r, _, err := transform.String(japanese.ShiftJIS.NewEncoder(), text) - if err != nil { - return "", err - } - return r, nil -} diff --git a/server/channelserver/handlers_guild_scout.go b/server/channelserver/handlers_guild_scout.go index d171750d4..8d0266de9 100644 --- a/server/channelserver/handlers_guild_scout.go +++ b/server/channelserver/handlers_guild_scout.go @@ -248,11 +248,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(uint32(TimeAdjusted().Unix())) bf.WriteUint16(0x00) // HR? bf.WriteUint16(0x00) // GR? - - charNameBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(charName) - - bf.WriteBytes(charNameBytes) - bf.WriteBytes(make([]byte, 32-len(charNameBytes))) // Fixed length string + bf.WriteBytes(stringsupport.PaddedString(charName, 32, true)) count++ } From c344fdd4c9b5605369e549ee22dccf5711ccb300 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 12 Mar 2023 23:43:30 +1100 Subject: [PATCH 20/46] fix scout enumeration data --- server/channelserver/handlers_guild_scout.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/channelserver/handlers_guild_scout.go b/server/channelserver/handlers_guild_scout.go index 8d0266de9..fceeb037d 100644 --- a/server/channelserver/handlers_guild_scout.go +++ b/server/channelserver/handlers_guild_scout.go @@ -204,7 +204,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { } rows, err := s.server.db.Queryx(` - SELECT c.id, c.name, ga.actor_id + SELECT c.id, c.name, c.hrp, c.gr, ga.actor_id FROM guild_applications ga JOIN characters c ON c.id = ga.character_id WHERE ga.guild_id = $1 AND ga.application_type = 'invited' @@ -229,14 +229,14 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { for rows.Next() { var charName string - var charID uint32 - var actorID uint32 + var charID, actorID uint32 + var hrp, gr uint16 - err = rows.Scan(&charID, &charName, &actorID) + err = rows.Scan(&charID, &charName, &hrp, &gr, &actorID) if err != nil { doAckSimpleFail(s, pkt.AckHandle, nil) - panic(err) + continue } // This seems to be used as a unique ID for the invitation sent @@ -246,8 +246,8 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint32(actorID) bf.WriteUint32(charID) bf.WriteUint32(uint32(TimeAdjusted().Unix())) - bf.WriteUint16(0x00) // HR? - bf.WriteUint16(0x00) // GR? + bf.WriteUint16(hrp) // HR? + bf.WriteUint16(gr) // GR? bf.WriteBytes(stringsupport.PaddedString(charName, 32, true)) count++ } From c204813be284765fb5df92ce59e63e307355626b Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 13 Mar 2023 14:31:52 +1100 Subject: [PATCH 21/46] merge optional shop items from feature/diva --- bundled-schema/DivaShops.sql | 45 +++++++++++++++++++++++++++++++++++ bundled-schema/OtherShops.sql | 12 ++++++++++ 2 files changed, 57 insertions(+) create mode 100644 bundled-schema/DivaShops.sql create mode 100644 bundled-schema/OtherShops.sql diff --git a/bundled-schema/DivaShops.sql b/bundled-schema/DivaShops.sql new file mode 100644 index 000000000..c1a1d850b --- /dev/null +++ b/bundled-schema/DivaShops.sql @@ -0,0 +1,45 @@ +BEGIN; + +INSERT INTO public.shop_items +(shop_type, shop_id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, road_floors, road_fatalis) +VALUES + (8,5,1,30,10,0,0,0,0,10,0,0), + (8,5,2,60,10,0,0,0,0,10,0,0), + (8,5,3,60,10,0,0,0,0,10,0,0), + (8,5,4,30,10,0,0,0,0,10,0,0), + (8,5,5,60,10,0,0,0,0,10,0,0), + (8,5,6,80,10,0,0,0,1,10,0,0), + (8,5,7,80,10,0,0,0,1,10,0,0), + (8,5,8,80,10,0,0,0,1,10,0,0), + (8,5,9,100,10,0,0,0,2,10,0,0), + (8,5,10,100,10,0,0,0,2,10,0,0), + (8,5,11,100,10,0,0,0,2,10,0,0), + (8,5,12,100,10,0,0,0,2,10,0,0), + (8,5,13,100,10,0,0,0,2,10,0,0), + (8,5,14,200,10,0,0,0,2,10,0,0), + (8,5,15,500,10,0,0,0,3,10,0,0), + (8,5,16,1000,10,0,0,0,3,10,0,0), + (8,5,20,30,10,0,0,0,0,10,0,0), + (8,5,21,30,10,0,0,0,0,10,0,0), + (8,5,22,60,10,0,0,0,0,10,0,0), + (8,5,23,60,10,0,0,0,0,10,0,0), + (8,5,24,60,10,0,0,0,0,10,0,0), + (8,5,25,80,10,0,0,0,1,10,0,0), + (8,5,26,80,10,0,0,0,1,10,0,0), + (8,5,27,500,10,0,0,1,3,10,0,0), + (8,5,28,60,10,0,0,0,0,10,0,0), + (8,5,29,60,10,299,0,0,0,10,0,0), + (8,5,30,100,10,0,0,1,3,10,0,0), + (8,5,31,80,10,299,0,0,1,10,0,0), + (8,5,32,80,10,299,0,0,1,10,0,0), + (8,5,33,80,10,299,0,0,1,10,0,0), + (8,7,2209,400,1,299,0,0,2,5,0,0), + (8,7,2208,400,1,299,0,0,2,5,0,0), + (8,7,5113,400,1,299,0,0,2,5,0,0), + (8,7,3571,400,1,299,0,0,2,5,0,0), + (8,7,3572,400,1,299,0,0,2,5,0,0), + (8,7,3738,400,1,299,0,0,2,5,0,0), + (8,7,3737,400,1,299,0,0,2,5,0,0), + (8,7,4399,400,1,299,0,0,2,5,0,0); + +END; \ No newline at end of file diff --git a/bundled-schema/OtherShops.sql b/bundled-schema/OtherShops.sql new file mode 100644 index 000000000..d25e453b0 --- /dev/null +++ b/bundled-schema/OtherShops.sql @@ -0,0 +1,12 @@ +BEGIN; + +INSERT INTO public.shop_items +(shop_type, shop_id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, road_floors, road_fatalis) +VALUES + (5,5,16516,100,1,0,0,1,0,0,0,0), + (5,5,16517,100,1,0,0,1,0,0,0,0), + (7,0,13190,10,1,0,0,0,0,0,0,0), + (7,0,1662,10,1,0,0,0,0,0,0,0), + (7,0,10179,100,1,0,0,0,0,0,0,0); + +END; \ No newline at end of file From 265b74b6b06b82b8a530bbac998fb39c890cbf85 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 13 Mar 2023 23:25:12 +1100 Subject: [PATCH 22/46] fix shop-db schema --- patch-schema/shop-db.sql | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/patch-schema/shop-db.sql b/patch-schema/shop-db.sql index 6e75d403a..4c5634e88 100644 --- a/patch-schema/shop-db.sql +++ b/patch-schema/shop-db.sql @@ -12,9 +12,6 @@ ALTER TABLE IF EXISTS public.shop_items ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemhash TO id; -ALTER TABLE IF EXISTS public.shop_items - ADD PRIMARY KEY (id); - ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemid TO item_id; @@ -51,6 +48,20 @@ ALTER TABLE IF EXISTS public.shop_items ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN weeklyfataliskills TO road_fatalis; +ALTER TABLE public.shop_items + RENAME CONSTRAINT normal_shop_items_pkey TO shop_items_pkey; + +ALTER TABLE IF EXISTS public.shop_items + DROP CONSTRAINT IF EXISTS normal_shop_items_itemhash_key; + +CREATE SEQUENCE public.shop_items_id_seq; + +ALTER SEQUENCE public.shop_items_id_seq + OWNER TO postgres; + +ALTER TABLE IF EXISTS public.shop_items + ALTER COLUMN id SET DEFAULT nextval('shop_items_id_seq'::regclass); + DROP TABLE IF EXISTS public.shop_item_state; CREATE TABLE IF NOT EXISTS public.shop_items_bought ( From 8189f90031c4b103b4f2519382f22ffb0d91c0f9 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 13 Mar 2023 23:37:00 +1100 Subject: [PATCH 23/46] fix shop-db schema --- patch-schema/shop-db.sql | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/patch-schema/shop-db.sql b/patch-schema/shop-db.sql index 4c5634e88..543c373db 100644 --- a/patch-schema/shop-db.sql +++ b/patch-schema/shop-db.sql @@ -62,6 +62,11 @@ ALTER SEQUENCE public.shop_items_id_seq ALTER TABLE IF EXISTS public.shop_items ALTER COLUMN id SET DEFAULT nextval('shop_items_id_seq'::regclass); +ALTER SEQUENCE IF EXISTS public.shop_items_id_seq + OWNED BY shop_items.id; + +SELECT setval('shop_items_id_seq', (SELECT MAX(id) FROM public.shop_items)); + DROP TABLE IF EXISTS public.shop_item_state; CREATE TABLE IF NOT EXISTS public.shop_items_bought ( From f85be55a6d720b24f0a3ec3d5fc1ad47a4763683 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 14 Mar 2023 02:16:09 +1100 Subject: [PATCH 24/46] fix login boost creating hanging connections --- server/channelserver/handlers_event.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index bd44e8a10..30511259b 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -131,6 +131,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { var loginBoosts []loginBoost rows, err := s.server.db.Queryx("SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", s.charID) if err != nil || s.server.erupeConfig.GameplayOptions.DisableLoginBoost { + rows.Close() doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35)) return } From 107eddfea58c0dca6e350b70a7dde2db17752a6d Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 27 Mar 2023 21:29:23 +1100 Subject: [PATCH 25/46] stub interception map packets --- .../msg_mhf_get_ud_tactics_remaining_point.go | 21 +++++++++++++------ server/channelserver/handlers_guild.go | 10 ++++----- server/channelserver/handlers_tactics.go | 8 ++++++- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/network/mhfpacket/msg_mhf_get_ud_tactics_remaining_point.go b/network/mhfpacket/msg_mhf_get_ud_tactics_remaining_point.go index acb3e23ab..94cf7e9f0 100644 --- a/network/mhfpacket/msg_mhf_get_ud_tactics_remaining_point.go +++ b/network/mhfpacket/msg_mhf_get_ud_tactics_remaining_point.go @@ -1,15 +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" ) // MsgMhfGetUdTacticsRemainingPoint represents the MSG_MHF_GET_UD_TACTICS_REMAINING_POINT -type MsgMhfGetUdTacticsRemainingPoint struct{} +type MsgMhfGetUdTacticsRemainingPoint struct { + AckHandle uint32 + Unk0 uint32 // GuildID? + Unk1 uint32 + Unk2 uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgMhfGetUdTacticsRemainingPoint) Opcode() network.PacketID { @@ -18,7 +23,11 @@ func (m *MsgMhfGetUdTacticsRemainingPoint) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfGetUdTacticsRemainingPoint) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - return errors.New("NOT IMPLEMENTED") + m.AckHandle = bf.ReadUint32() + m.Unk0 = bf.ReadUint32() + m.Unk1 = bf.ReadUint32() + m.Unk2 = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index 08a00ebbe..a804932d0 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1498,10 +1498,7 @@ func handleMsgMhfGetGuildManageRight(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetUdGuildMapInfo(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetUdGuildMapInfo) - - data, _ := hex.DecodeString("00050000013600000137013500000000E2DF000000000204000000640100000001019901350000E2DF0000000001000000044C000000000001FE01FF00000000000000000D0000001036000000000001FC01FD00000000000000000B0000000F0A000000000001FB01FC00000000000000000A0000000E740000000000019B013700000000000000000F00000011620000000000019601FB0000000000000000090000000DDE0000000000013700D400000000000000001000000011F80000000000013201960000000000000000080000000D48000000000000D40070000000000000000011000000128E000000000000CE01320000000000000000070000000CB200000000000070006F00000000000000001200000013240000000000006F006E00000000000000001300000013BA0000000000006E006D00000000000000001400000014500000000000006D0000000000000000000015020000157C0000000000006A00CE0000000000000000060000000C1C00000000000069006A0000000000000000050000000B860000000000006800690000000000000000040000000AF00000000000006700680000000000000000030000000A5A00000000000066006700000000000000000200000009C4000000000001FD01FE01990000000000000C0300000FA00000000000006500660000000000000000010100000000000000000001FF019B00000000000000000E00000010CC0000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013700000138013200000000E2E0000000000204000000640100000002019701320000E2E00000000001000000044C00000000000193012E00000000000000000E000000319C0000000000013701360000000000000000060000001EDC00000000000136019900000000000000000700000021340000000000012E012D00000000000000000F00000033F40000000000019801FB01970000000000000903000025E4000000000001F9019400000000000000000C0000002CEC0000000000012D00C9000000000000000010000000364C000000000000D401370000000000000000050000001C84000000000000C9006600000000000000001100000036B00000000000007000D40000000000000000040000001A2C000000000001FA01F900000000000000000B0000002A940000000000006F007000000000000000000300000017D40000000000006E006F000000000000000002000000157C0000000000006D006E00000000000000000101000000000000000000006900000000000000000000150200004362000000000001FB01FA00000000000000000A000000283C0000000000006800690000000000000000140000003B6000000000000067006800000000000000001300000039D0000000000001990198000000000000000008000000238C000000000000660067000000000000000012000000390800000000000194019300000000000000000D0000002F44000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000013901FF00000000E2E10000000001040000044C0000000003019B013601FF0000000000000D0300003BC4000000000001FA000000000000000000001502000055F0000000000001F901FA00000000000000001400000051A400000000000199013400000000000000000F00000042040000000000019501F90000000000000000130000004E8400000000000138019B00000000000000000C00000038A400000000000136019900000000000000000E0000003EE4000000000001340133000000000000000010000000452400000000000133013200000000000000001100000048440000000000013201950000000000000000120000004B64000000000000D4013800000000000000000B0000003584000000000000D1006E0000000000000000070000002904000000000000CD006A0000000000000000030000001C840000000000007000D400000000000000000A00000032640000000000006F00700000000000000000090000002F440000000000006E006F0000000000000000080000002C240000000000006C00D100000000000000000600000025E40000000000006B006C00000000000000000500000022C40000000000006A006B0000000000000000040000001FA40000000000006800CD000000000000000002000000196400000000000067006800000000000000000101000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001390000013A006500000000E2E200000000020400000064010000000500C900650000E2E20000000001000000044C00000000000133019700000000000000000C040000445C0000000004013700D20000000000000000130000005FB4000000000000CA00CB00C9000000000000060300002CEC000000000001FF019B00000000000000001100000057E4000000000001FE01FF00000000000000001000000053FC000000000001FD01FE00000000000000000F0000005014000000000001FA01F90000000000000000010100000000000000000001F901940000000000000000020000001D4C0000000000019B01370000000000000000120000005BCC0000000000019801FD00000000000000000E0000004C2C00000000000197019800000000000000000D0000004844000000000001940193000000000000000003000000213400000000000193012E000000000000000004000000251C0000000000012E00CA0000000000000000050000002904000000000000D2006E000000000000000014000000639C000000000000CF013300000000000000000B0000004074000000000000CB006800000000000000000700000030D40000000000006E000000000000000000001502000075300000000000006A00CF00000000000000000A0000003C8C00000000000069006A00000000000000000900000038A400000000000068006900000000000000000800000034BC0000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013A0000013701F800000000E2E30000000001040000044C000000000601FD01FC00000000000000000700000034BC000000000001FC01FB00000000000000000800000038A4000000000001FB01FA0000000000000000090000003C8C000000000001FA01F900000000000000000A00000040740000000000019B019A0000000000000000050000002CEC0000000000019A01FD00000000000000000600000030D400000000000195013200000000000000000C000000484400000000000138019B00000000000000000400000029040000000000013300CF00000000000000000E000000501400000000000132013300000000000000000D0000004C2C000000000000D40138000000000000000003000000251C000000000000D300D40000000000000000020000002134000000000000CF006A00000000000000000F00000053FC000000000000CD00CC0000000000000000110000005BCC000000000000CC00CB0000000000000000120000005FB4000000000000CB00CA000000000000000013000000639C000000000000CA00C90000000000000000140000006784000000000000C90000000000000000000015020000FDE80000000000006E00D30000000000000000010100000000000000000001F9019501F80000000000000B030000445C0000000000006A00CD00000000000000001000000057E400000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000010738AD00010001000102000000011A000007D00002006302000000020738AD00020001000102000000021A000007D00002006302000000031A000003E80001006301000000041A000003E80001006301000000050738AD00020001000102000000051A000007D00002006302000000061A000003E800010063010100000136000117000000000000044C019901350000E2DF000000000100000000000000000064013500000000E2DF00000000020400000000000000000000650066000000000000000001010100000000000009C40066006700000000000000000200000000000000000A5A0067006800000000000000000300000000000000000AF00068006900000000000000000400000000000000000B860069006A00000000000000000500000000000000000C1C006A00CE00000000000000000600000000000000000CB200CE013200000000000000000700000000000000000D480132019600000000000000000800000000000000000DDE019601FB00000000000000000900000000000000000E7401FB01FC00000000000000000A00000000000000000F0A01FC01FD00000000000000000B00000000000000000FA001FD01FE01990000000000000C0300000000000000103601FE01FF00000000000000000D000000000000000010CC01FF019B00000000000000000E00000000000000001162019B013700000000000000000F000000000000000011F8013700D40000000000000000100000000000000000128E00D40070000000000000000011000000000000000013240070006F000000000000000012000000000000000013BA006F006E00000000000000001300000000000000001450006E006D0000000000000000140000000000000000157C006D000000000000000000001502000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - - doAckBufSucceed(s, pkt.AckHandle, data) + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgMhfGetGuildTargetMemberNum(s *Session, p mhfpacket.MHFPacket) { @@ -1952,7 +1949,10 @@ func handleMsgMhfAddGuildWeeklyBonusExceptionalUser(s *Session, p mhfpacket.MHFP doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } -func handleMsgMhfGenerateUdGuildMap(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfGenerateUdGuildMap(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGenerateUdGuildMap) + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) +} func handleMsgMhfUpdateGuild(s *Session, p mhfpacket.MHFPacket) {} diff --git a/server/channelserver/handlers_tactics.go b/server/channelserver/handlers_tactics.go index 4991ce846..5ef45913c 100644 --- a/server/channelserver/handlers_tactics.go +++ b/server/channelserver/handlers_tactics.go @@ -2,6 +2,7 @@ package channelserver import ( "encoding/hex" + "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" ) @@ -45,7 +46,12 @@ func handleMsgMhfGetUdTacticsFirstQuestBonus(s *Session, p mhfpacket.MHFPacket) doAckBufSucceed(s, pkt.AckHandle, data) } -func handleMsgMhfGetUdTacticsRemainingPoint(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfGetUdTacticsRemainingPoint(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfGetUdTacticsRemainingPoint) + bf := byteframe.NewByteFrame() + bf.WriteUint32(0) // Points until Special Guild Hall earned + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) +} func handleMsgMhfGetUdTacticsRanking(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetUdTacticsRanking) From 61d15ddd43e8e9f6aedb415253287c62303cfc39 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 30 Mar 2023 21:48:23 +1100 Subject: [PATCH 26/46] remove mail item workaround --- config.json | 1 - config/config.go | 1 - server/channelserver/handlers_mail.go | 11 ++--------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/config.json b/config.json index cd86056a3..03dca44e5 100644 --- a/config.json +++ b/config.json @@ -24,7 +24,6 @@ "TournamentEvent": 0, "MezFesEvent": true, "MezFesAlt": false, - "DisableMailItems": true, "DisableTokenCheck": false, "QuestDebugTools": false, "SaveDumps": { diff --git a/config/config.go b/config/config.go index 61ae99d42..1e91b24b7 100644 --- a/config/config.go +++ b/config/config.go @@ -50,7 +50,6 @@ type DevModeOptions struct { MezFesEvent bool // MezFes status MezFesAlt bool // Swaps out Volpakkun for Tokotoko DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!) - DisableMailItems bool // Hack to prevent english versions of MHF from crashing QuestDebugTools bool // Enable various quest debug logs SaveDumps SaveDumpOptions } diff --git a/server/channelserver/handlers_mail.go b/server/channelserver/handlers_mail.go index 1df4711c6..7e9784ee3 100644 --- a/server/channelserver/handlers_mail.go +++ b/server/channelserver/handlers_mail.go @@ -326,15 +326,8 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) { flags |= 0x04 } - // Workaround until EN mail items are patched - if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DisableMailItems { - if itemAttached { - flags |= 0x08 - } - } else { - if m.AttachedItemReceived { - flags |= 0x08 - } + if m.AttachedItemReceived { + flags |= 0x08 } if m.IsGuildInvite { From 8749674a63e32ca3bbe78e6325f9ce45dbe2673c Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 30 Mar 2023 21:59:51 +1100 Subject: [PATCH 27/46] replace deprecated rand call --- server/channelserver/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index d22f8be3b..dc285d9aa 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -12,11 +12,11 @@ import ( "strings" "time" + "crypto/rand" "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" "go.uber.org/zap" "math/bits" - "math/rand" ) // Temporary function to just return no results for a MSG_MHF_ENUMERATE* packet From 84c3944e1914bd3482db2cd1c5da80a472cfddd9 Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 30 Mar 2023 22:17:44 +1100 Subject: [PATCH 28/46] update default rights integer --- patch-schema/rights-v4.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/patch-schema/rights-v4.sql b/patch-schema/rights-v4.sql index 9732097ed..54e895f06 100644 --- a/patch-schema/rights-v4.sql +++ b/patch-schema/rights-v4.sql @@ -3,4 +3,7 @@ BEGIN; -- Remove Trial Course from all users UPDATE users SET rights = rights-2; +ALTER TABLE IF EXISTS public.users + ALTER COLUMN rights SET DEFAULT 12; + END; \ No newline at end of file From a042cef5b1f589be61e401cdc1f46e42b54fa5ce Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 30 Mar 2023 23:32:10 +1100 Subject: [PATCH 29/46] fix possible infinite loop in gacha rolls --- server/channelserver/handlers_shop_gacha.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/channelserver/handlers_shop_gacha.go b/server/channelserver/handlers_shop_gacha.go index 2ebf209ea..1341e341c 100644 --- a/server/channelserver/handlers_shop_gacha.go +++ b/server/channelserver/handlers_shop_gacha.go @@ -358,6 +358,9 @@ func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry totalWeight += entries[i].Weight } for { + if rolls == len(chosen) { + break + } if !isBox { result := rand.Float64() * totalWeight for _, entry := range entries { @@ -373,9 +376,6 @@ func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry entries[result] = entries[len(entries)-1] entries = entries[:len(entries)-1] } - if rolls == len(chosen) { - break - } } return chosen, nil } From 759b8e47d1fd88aa024b6fe2e123a042829622cc Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 30 Mar 2023 23:42:39 +1100 Subject: [PATCH 30/46] create schema for gacha demos --- bundled-schema/GachaDemo.sql | 98 ++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 bundled-schema/GachaDemo.sql diff --git a/bundled-schema/GachaDemo.sql b/bundled-schema/GachaDemo.sql new file mode 100644 index 000000000..57f4e94b8 --- /dev/null +++ b/bundled-schema/GachaDemo.sql @@ -0,0 +1,98 @@ +BEGIN; + +-- Start Normal Demo +INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden) +VALUES (0, 0, 'Normal Demo', '', '', '', false, false, 0, false); + +-- Create two different 'rolls', the first rolls once for 1z, the second rolls eleven times for 10z +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) +VALUES + ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 0, 10, 1, 0, 0, 0, 1, 0, 0), + ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 1, 10, 10, 0, 0, 0, 11, 0, 0); + +-- Creates a prize of 1z with a weighted chance of 100 +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 100, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0); + +-- Creates a prize of 2z with a weighted chance of 70 +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 70, 1, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 2, 0); + +-- Creates a prize of 3z with a weighted chance of 10 +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 10, 2, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0); +-- End Normal Demo + +-- Start Step-Up Demo +INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden) +VALUES (0, 0, 'Step-Up Demo', '', '', '', false, false, 1, false); + +-- Create two 'steps', the first costs 1z, the second costs 2z +-- The first step has zero rolls so it will only give the prizes directly linked to the entry ID, being 1z +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 0, 10, 1, 0, 0, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0); + +-- The second step has one roll on the random prize list as will as the direct prize, being 3z +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 1, 10, 2, 0, 0, 0, 1, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0); + +-- Set up two random prizes, the first gives 1z, the second gives 2z +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 100, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0); + +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 90, 1, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 2, 0); +-- End Step-Up Demo + +-- Start Box Demo +INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden) +VALUES (0, 0, 'Box Demo', '', '', '', false, false, 4, false); + +-- Create two different 'rolls', the first rolls once for 1z, the second rolls twice for 2z +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) +VALUES + ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 0, 10, 1, 0, 0, 0, 1, 0, 0), + ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 1, 10, 2, 0, 0, 0, 2, 0, 0); + +-- Create five different 'Box' items, weight is always 0 for these +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0); + +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0); + +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 1, 0); + +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 2, 0); + +INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) + VALUES ((SELECT id FROM gacha_shop ORDER BY id DESC LIMIT 1), 100, 0, 0, 0, 0, 0, 0, 0, 0); +INSERT INTO gacha_items (entry_id, item_type, item_id, quantity) + VALUES ((SELECT id FROM gacha_entries ORDER BY id DESC LIMIT 1), 10, 3, 0); +-- End Box Demo + +END; \ No newline at end of file From 29f91bcd9b2616b87532e67d75aad662248231fb Mon Sep 17 00:00:00 2001 From: wish Date: Thu, 30 Mar 2023 23:50:54 +1100 Subject: [PATCH 31/46] link gacha demo templates --- bundled-schema/GachaDemo.sql | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bundled-schema/GachaDemo.sql b/bundled-schema/GachaDemo.sql index 57f4e94b8..b32c1c3ac 100644 --- a/bundled-schema/GachaDemo.sql +++ b/bundled-schema/GachaDemo.sql @@ -2,7 +2,11 @@ BEGIN; -- Start Normal Demo INSERT INTO gacha_shop (min_gr, min_hr, name, url_banner, url_feature, url_thumbnail, wide, recommended, gacha_type, hidden) -VALUES (0, 0, 'Normal Demo', '', '', '', false, false, 0, false); + VALUES (0, 0, 'Normal Demo', + 'http://img4.imagetitan.com/img4/QeRWNAviFD8UoTx/26/26_template_innerbanner.png', + 'http://img4.imagetitan.com/img4/QeRWNAviFD8UoTx/26/26_template_feature.png', + 'http://img4.imagetitan.com/img4/small/26/26_template_outerbanner.png', + false, false, 0, false); -- Create two different 'rolls', the first rolls once for 1z, the second rolls eleven times for 10z INSERT INTO gacha_entries (gacha_id, entry_type, item_type, item_number, item_quantity, weight, rarity, rolls, daily_limit, frontier_points) From 7d884da93823efbdc130927a66a74fecfd95ae12 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 31 Mar 2023 00:04:51 +1100 Subject: [PATCH 32/46] replace deprecated code --- server/channelserver/handlers_data.go | 3 +-- server/channelserver/handlers_mercenary.go | 3 +-- server/channelserver/handlers_rengoku.go | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/server/channelserver/handlers_data.go b/server/channelserver/handlers_data.go index 36dd2e596..64b14072c 100644 --- a/server/channelserver/handlers_data.go +++ b/server/channelserver/handlers_data.go @@ -5,7 +5,6 @@ import ( "erupe-ce/common/stringsupport" "fmt" "io" - "io/ioutil" "os" "path/filepath" @@ -260,7 +259,7 @@ func dumpSaveData(s *Session, data []byte, suffix string) { func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoaddata) if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin")); err == nil { - data, _ := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin")) + data, _ := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin")) doAckBufSucceed(s, pkt.AckHandle, data) return } diff --git a/server/channelserver/handlers_mercenary.go b/server/channelserver/handlers_mercenary.go index e44d9f1f2..251bc107b 100644 --- a/server/channelserver/handlers_mercenary.go +++ b/server/channelserver/handlers_mercenary.go @@ -8,7 +8,6 @@ import ( "erupe-ce/server/channelserver/compression/nullcomp" "go.uber.org/zap" "io" - "io/ioutil" "os" "path/filepath" "time" @@ -292,7 +291,7 @@ 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, _ := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin")) + data, _ := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin")) resp.WriteBytes(data) doAckBufSucceed(s, pkt.AckHandle, resp.Data()) return diff --git a/server/channelserver/handlers_rengoku.go b/server/channelserver/handlers_rengoku.go index 732cb77ef..63a591fd2 100644 --- a/server/channelserver/handlers_rengoku.go +++ b/server/channelserver/handlers_rengoku.go @@ -4,7 +4,7 @@ import ( ps "erupe-ce/common/pascalstring" "fmt" "github.com/jmoiron/sqlx" - "io/ioutil" + "os" "path/filepath" "erupe-ce/common/byteframe" @@ -92,7 +92,7 @@ func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetRengokuBinary) // a (massively out of date) version resides in the game's /dat/ folder or up to date can be pulled from packets - data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "rengoku_data.bin")) + data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "rengoku_data.bin")) if err != nil { panic(err) } From 31adb0b1d645e4eb7f27855bd57e5ea0b0437c01 Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 31 Mar 2023 00:46:48 +1100 Subject: [PATCH 33/46] add miscellaneous cleanup queries --- patch-schema/misc.sql | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 patch-schema/misc.sql diff --git a/patch-schema/misc.sql b/patch-schema/misc.sql new file mode 100644 index 000000000..3bc212ec4 --- /dev/null +++ b/patch-schema/misc.sql @@ -0,0 +1,19 @@ +BEGIN; + +CREATE TABLE IF NOT EXISTS public.feature_weapon +( + start_time TIMESTAMP WITH TIME ZONE NOT NULL, + featured INTEGER NOT NULL +); + +ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS cafe_time; + +ALTER TABLE IF EXISTS public.characters ADD COLUMN IF NOT EXISTS cafe_reset TIMESTAMP WITH TIME ZONE; + +DROP TABLE IF EXISTS public.user_binaries; + +DROP PROCEDURE IF EXISTS raviinit; + +DROP PROCEDURE IF EXISTS ravireset; + +END; \ No newline at end of file From 006f44f3a68658597a780f2d1af7371f5cb861fb Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 31 Mar 2023 00:53:50 +1100 Subject: [PATCH 34/46] fix feature weapon RNG --- server/channelserver/handlers_event.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index 30511259b..bba4c1065 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -95,8 +95,8 @@ func generateFeatureWeapons(count int) activeFeature { } nums := make([]int, 0) var result int - rng := token.RNG() for len(nums) < count { + rng := token.RNG() num := rng.Intn(14) exist := false for _, v := range nums { From 0345fb6da9f76dbf89eb8ab191066a8bdc68854b Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 31 Mar 2023 23:43:07 +1100 Subject: [PATCH 35/46] undo drop column --- patch-schema/misc.sql | 2 -- 1 file changed, 2 deletions(-) diff --git a/patch-schema/misc.sql b/patch-schema/misc.sql index 3bc212ec4..29ec38102 100644 --- a/patch-schema/misc.sql +++ b/patch-schema/misc.sql @@ -6,8 +6,6 @@ CREATE TABLE IF NOT EXISTS public.feature_weapon featured INTEGER NOT NULL ); -ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS cafe_time; - ALTER TABLE IF EXISTS public.characters ADD COLUMN IF NOT EXISTS cafe_reset TIMESTAMP WITH TIME ZONE; DROP TABLE IF EXISTS public.user_binaries; From 7c5b027457e00ec709621cda04c08296224cc36f Mon Sep 17 00:00:00 2001 From: wish Date: Fri, 31 Mar 2023 23:43:48 +1100 Subject: [PATCH 36/46] fix schema --- patch-schema/misc.sql | 2 -- 1 file changed, 2 deletions(-) diff --git a/patch-schema/misc.sql b/patch-schema/misc.sql index 29ec38102..93749d8db 100644 --- a/patch-schema/misc.sql +++ b/patch-schema/misc.sql @@ -6,8 +6,6 @@ CREATE TABLE IF NOT EXISTS public.feature_weapon featured INTEGER NOT NULL ); -ALTER TABLE IF EXISTS public.characters ADD COLUMN IF NOT EXISTS cafe_reset TIMESTAMP WITH TIME ZONE; - DROP TABLE IF EXISTS public.user_binaries; DROP PROCEDURE IF EXISTS raviinit; From f0db7f0a19163fa3161f4ee8e520c61cf414a886 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 1 Apr 2023 17:58:26 +1100 Subject: [PATCH 37/46] finalise 9.2 --- main.go | 2 +- patch-schema/etc-points.sql | 9 ---- patch-schema/gacha-db-2.sql | 77 -------------------------------- patch-schema/gacha-db.sql | 29 ------------ patch-schema/guild-event-rp.sql | 7 --- patch-schema/login-boost.sql | 12 ----- patch-schema/mezfes-save.sql | 6 --- patch-schema/misc.sql | 15 ------- patch-schema/rasta-id.sql | 9 ---- patch-schema/rights-v4.sql | 9 ---- patch-schema/shop-db.sql | 78 --------------------------------- patch-schema/stampcard.sql | 5 --- patch-schema/time-fix.sql | 69 ----------------------------- patch-schema/unused-tables.sql | 17 ------- 14 files changed, 1 insertion(+), 343 deletions(-) delete mode 100644 patch-schema/etc-points.sql delete mode 100644 patch-schema/gacha-db-2.sql delete mode 100644 patch-schema/gacha-db.sql delete mode 100644 patch-schema/guild-event-rp.sql delete mode 100644 patch-schema/login-boost.sql delete mode 100644 patch-schema/mezfes-save.sql delete mode 100644 patch-schema/misc.sql delete mode 100644 patch-schema/rasta-id.sql delete mode 100644 patch-schema/rights-v4.sql delete mode 100644 patch-schema/shop-db.sql delete mode 100644 patch-schema/stampcard.sql delete mode 100644 patch-schema/time-fix.sql delete mode 100644 patch-schema/unused-tables.sql diff --git a/main.go b/main.go index 33cbbfdd7..a93d532fa 100644 --- a/main.go +++ b/main.go @@ -54,7 +54,7 @@ func main() { defer zapLogger.Sync() logger := zapLogger.Named("main") - logger.Info(fmt.Sprintf("Starting Erupe (9.2b-%s)", Commit())) + logger.Info(fmt.Sprintf("Starting Erupe (9.2-%s)", Commit())) if config.ErupeConfig.Database.Password == "" { preventClose("Database password is blank") diff --git a/patch-schema/etc-points.sql b/patch-schema/etc-points.sql deleted file mode 100644 index 88062922f..000000000 --- a/patch-schema/etc-points.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN; - -ALTER TABLE characters ADD bonus_quests INT NOT NULL DEFAULT 0; - -ALTER TABLE characters ADD daily_quests INT NOT NULL DEFAULT 0; - -ALTER TABLE characters ADD promo_points INT NOT NULL DEFAULT 0; - -END; \ No newline at end of file diff --git a/patch-schema/gacha-db-2.sql b/patch-schema/gacha-db-2.sql deleted file mode 100644 index d3faa1ed9..000000000 --- a/patch-schema/gacha-db-2.sql +++ /dev/null @@ -1,77 +0,0 @@ -BEGIN; - -ALTER TABLE characters - DROP COLUMN IF EXISTS gacha_prem; - -ALTER TABLE characters - DROP COLUMN IF EXISTS gacha_trial; - -ALTER TABLE characters - DROP COLUMN IF EXISTS frontier_points; - -ALTER TABLE users - ADD IF NOT EXISTS gacha_premium INT; - -ALTER TABLE users - ADD IF NOT EXISTS gacha_trial INT; - -ALTER TABLE users - ADD IF NOT EXISTS frontier_points INT; - -DROP TABLE IF EXISTS public.gacha_shop; - -CREATE TABLE IF NOT EXISTS public.gacha_shop ( - id SERIAL PRIMARY KEY, - min_gr INTEGER, - min_hr INTEGER, - name TEXT, - url_banner TEXT, - url_feature TEXT, - url_thumbnail TEXT, - wide BOOLEAN, - recommended BOOLEAN, - gacha_type INTEGER, - hidden BOOLEAN -); - -DROP TABLE IF EXISTS public.gacha_shop_items; - -CREATE TABLE IF NOT EXISTS public.gacha_entries ( - id SERIAL PRIMARY KEY, - gacha_id INTEGER, - entry_type INTEGER, - item_type INTEGER, - item_number INTEGER, - item_quantity INTEGER, - weight INTEGER, - rarity INTEGER, - rolls INTEGER, - frontier_points INTEGER, - daily_limit INTEGER -); - -CREATE TABLE IF NOT EXISTS public.gacha_items ( - id SERIAL PRIMARY KEY, - entry_id INTEGER, - item_type INTEGER, - item_id INTEGER, - quantity INTEGER -); - -DROP TABLE IF EXISTS public.stepup_state; - -CREATE TABLE IF NOT EXISTS public.gacha_stepup ( - gacha_id INTEGER, - step INTEGER, - character_id INTEGER -); - -DROP TABLE IF EXISTS public.lucky_box_state; - -CREATE TABLE IF NOT EXISTS public.gacha_box ( - gacha_id INTEGER, - entry_id INTEGER, - character_id INTEGER -); - -END; \ No newline at end of file diff --git a/patch-schema/gacha-db.sql b/patch-schema/gacha-db.sql deleted file mode 100644 index 2fab717fe..000000000 --- a/patch-schema/gacha-db.sql +++ /dev/null @@ -1,29 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS public.gacha_shop; - -CREATE TABLE IF NOT EXISTS public.gacha_shop ( - id serial PRIMARY KEY, - min_gr integer, - min_hr integer, - name text, - link1 text, - link2 text, - link3 text, - icon integer, - type integer, - hide boolean -); - -DROP TABLE IF EXISTS public.fpoint_items; - -CREATE TABLE IF NOT EXISTS public.fpoint_items ( - id serial PRIMARY KEY, - item_type integer, - item_id integer, - quantity integer, - fpoints integer, - trade_type integer -); - -END; \ No newline at end of file diff --git a/patch-schema/guild-event-rp.sql b/patch-schema/guild-event-rp.sql deleted file mode 100644 index 1dca6aae1..000000000 --- a/patch-schema/guild-event-rp.sql +++ /dev/null @@ -1,7 +0,0 @@ -BEGIN; - -ALTER TABLE IF EXISTS public.guild_characters ADD rp_today INT DEFAULT 0; - -ALTER TABLE IF EXISTS public.guild_characters ADD rp_yesterday INT DEFAULT 0; - -END; \ No newline at end of file diff --git a/patch-schema/login-boost.sql b/patch-schema/login-boost.sql deleted file mode 100644 index 3b451a65f..000000000 --- a/patch-schema/login-boost.sql +++ /dev/null @@ -1,12 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS public.login_boost_state; - -CREATE TABLE IF NOT EXISTS public.login_boost ( - char_id INTEGER, - week_req INTEGER, - expiration TIMESTAMP WITH TIME ZONE, - reset TIMESTAMP WITH TIME ZONE -); - -END; \ No newline at end of file diff --git a/patch-schema/mezfes-save.sql b/patch-schema/mezfes-save.sql deleted file mode 100644 index a4445dc15..000000000 --- a/patch-schema/mezfes-save.sql +++ /dev/null @@ -1,6 +0,0 @@ -BEGIN; - -ALTER TABLE public.characters - ADD COLUMN mezfes BYTEA; - -END; \ No newline at end of file diff --git a/patch-schema/misc.sql b/patch-schema/misc.sql deleted file mode 100644 index 93749d8db..000000000 --- a/patch-schema/misc.sql +++ /dev/null @@ -1,15 +0,0 @@ -BEGIN; - -CREATE TABLE IF NOT EXISTS public.feature_weapon -( - start_time TIMESTAMP WITH TIME ZONE NOT NULL, - featured INTEGER NOT NULL -); - -DROP TABLE IF EXISTS public.user_binaries; - -DROP PROCEDURE IF EXISTS raviinit; - -DROP PROCEDURE IF EXISTS ravireset; - -END; \ No newline at end of file diff --git a/patch-schema/rasta-id.sql b/patch-schema/rasta-id.sql deleted file mode 100644 index 14541e378..000000000 --- a/patch-schema/rasta-id.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN; - -UPDATE characters SET savemercenary = NULL; - -ALTER TABLE characters ADD rasta_id INT; - -ALTER TABLE characters ADD pact_id INT; - -END; \ No newline at end of file diff --git a/patch-schema/rights-v4.sql b/patch-schema/rights-v4.sql deleted file mode 100644 index 54e895f06..000000000 --- a/patch-schema/rights-v4.sql +++ /dev/null @@ -1,9 +0,0 @@ -BEGIN; - --- Remove Trial Course from all users -UPDATE users SET rights = rights-2; - -ALTER TABLE IF EXISTS public.users - ALTER COLUMN rights SET DEFAULT 12; - -END; \ No newline at end of file diff --git a/patch-schema/shop-db.sql b/patch-schema/shop-db.sql deleted file mode 100644 index 543c373db..000000000 --- a/patch-schema/shop-db.sql +++ /dev/null @@ -1,78 +0,0 @@ -BEGIN; - -ALTER TABLE IF EXISTS public.normal_shop_items - RENAME TO shop_items; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN shoptype TO shop_type; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN shopid TO shop_id; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN itemhash TO id; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN itemid TO item_id; - -ALTER TABLE IF EXISTS public.shop_items - ALTER COLUMN points TYPE integer; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN points TO cost; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN tradequantity TO quantity; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN rankreqlow TO min_hr; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN rankreqhigh TO min_sr; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN rankreqg TO min_gr; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN storelevelreq TO store_level; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN maximumquantity TO max_quantity; - -ALTER TABLE IF EXISTS public.shop_items - DROP COLUMN IF EXISTS boughtquantity; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN roadfloorsrequired TO road_floors; - -ALTER TABLE IF EXISTS public.shop_items - RENAME COLUMN weeklyfataliskills TO road_fatalis; - -ALTER TABLE public.shop_items - RENAME CONSTRAINT normal_shop_items_pkey TO shop_items_pkey; - -ALTER TABLE IF EXISTS public.shop_items - DROP CONSTRAINT IF EXISTS normal_shop_items_itemhash_key; - -CREATE SEQUENCE public.shop_items_id_seq; - -ALTER SEQUENCE public.shop_items_id_seq - OWNER TO postgres; - -ALTER TABLE IF EXISTS public.shop_items - ALTER COLUMN id SET DEFAULT nextval('shop_items_id_seq'::regclass); - -ALTER SEQUENCE IF EXISTS public.shop_items_id_seq - OWNED BY shop_items.id; - -SELECT setval('shop_items_id_seq', (SELECT MAX(id) FROM public.shop_items)); - -DROP TABLE IF EXISTS public.shop_item_state; - -CREATE TABLE IF NOT EXISTS public.shop_items_bought ( - character_id INTEGER, - shop_item_id INTEGER, - bought INTEGER -); - -END; \ No newline at end of file diff --git a/patch-schema/stampcard.sql b/patch-schema/stampcard.sql deleted file mode 100644 index f2c6b7d10..000000000 --- a/patch-schema/stampcard.sql +++ /dev/null @@ -1,5 +0,0 @@ -BEGIN; - -ALTER TABLE characters ADD stampcard INT NOT NULL DEFAULT 0; - -END; \ No newline at end of file diff --git a/patch-schema/time-fix.sql b/patch-schema/time-fix.sql deleted file mode 100644 index 8c5d890c0..000000000 --- a/patch-schema/time-fix.sql +++ /dev/null @@ -1,69 +0,0 @@ -BEGIN; - -ALTER TABLE IF EXISTS public.characters - ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.characters - ALTER COLUMN guild_post_checked TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.characters - ALTER COLUMN boost_time TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.characters - ALTER COLUMN cafe_reset TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.distribution - ALTER COLUMN deadline TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.events - ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.feature_weapon - ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.guild_alliances - ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.guild_applications - ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.guild_characters - ALTER COLUMN joined_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.guild_posts - ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.characters - ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.guilds - ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.mail - ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.stamps - ALTER COLUMN hl_next TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.stamps - ALTER COLUMN ex_next TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.titles - ALTER COLUMN unlocked_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.titles - ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.users - ALTER COLUMN last_login TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.users - ALTER COLUMN return_expires TYPE TIMESTAMP WITH TIME ZONE; - -ALTER TABLE IF EXISTS public.guild_meals - DROP COLUMN expires; - -ALTER TABLE IF EXISTS public.guild_meals - ADD COLUMN created_at TIMESTAMP WITH TIME ZONE; - -END; \ No newline at end of file diff --git a/patch-schema/unused-tables.sql b/patch-schema/unused-tables.sql deleted file mode 100644 index a3411d517..000000000 --- a/patch-schema/unused-tables.sql +++ /dev/null @@ -1,17 +0,0 @@ -BEGIN; - -DROP TABLE IF EXISTS public.account_ban; - -DROP TABLE IF EXISTS public.account_history; - -DROP TABLE IF EXISTS public.account_moderation; - -DROP TABLE IF EXISTS public.account_sub; - -DROP TABLE IF EXISTS public.history; - -DROP TABLE IF EXISTS public.questlists; - -DROP TABLE IF EXISTS public.schema_migrations; - -END; \ No newline at end of file From 13522ef2c95b5341c7851cf54b4b090446d84376 Mon Sep 17 00:00:00 2001 From: Sophie R Date: Thu, 6 Apr 2023 14:44:27 +0200 Subject: [PATCH 38/46] Fix pointerGender offset being wrong Every character seems to be assigned as male no matter what and changing the offset to 0x51 fixes this. --- server/channelserver/handlers_character.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/channelserver/handlers_character.go b/server/channelserver/handlers_character.go index 7de800e04..165580fe7 100644 --- a/server/channelserver/handlers_character.go +++ b/server/channelserver/handlers_character.go @@ -12,7 +12,7 @@ import ( ) const ( - pointerGender = 0x81 // +1 + pointerGender = 0x51 // +1 pointerRP = 0x22D16 // +2 pointerHouseTier = 0x1FB6C // +5 pointerHouseData = 0x1FE01 // +195 From 4ffb17604982eb60963e88b4f304a9a3c9ad787f Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 10 Apr 2023 18:52:12 +1000 Subject: [PATCH 39/46] prevent reading past message board packet --- .../msg_mhf_update_guild_message_board.go | 42 ++++++++++++++++--- server/channelserver/handlers_guild.go | 36 ++++------------ 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/network/mhfpacket/msg_mhf_update_guild_message_board.go b/network/mhfpacket/msg_mhf_update_guild_message_board.go index b8c4ee5e0..94316cc52 100644 --- a/network/mhfpacket/msg_mhf_update_guild_message_board.go +++ b/network/mhfpacket/msg_mhf_update_guild_message_board.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + "erupe-ce/common/stringsupport" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -10,9 +11,16 @@ import ( // MsgMhfUpdateGuildMessageBoard represents the MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD type MsgMhfUpdateGuildMessageBoard struct { - AckHandle uint32 - MessageOp uint32 - Request []byte + AckHandle uint32 + MessageOp uint32 + PostType uint32 + StampID uint32 + TitleLength uint32 + BodyLength uint32 + Title string + Body string + PostID uint32 + LikeState bool } // Opcode returns the ID associated with this packet type. @@ -24,9 +32,31 @@ func (m *MsgMhfUpdateGuildMessageBoard) Opcode() network.PacketID { func (m *MsgMhfUpdateGuildMessageBoard) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.MessageOp = bf.ReadUint32() - if m.MessageOp != 5 { - m.Request = bf.DataFromCurrent() - bf.Seek(int64(len(bf.Data())-2), 0) + switch m.MessageOp { + case 0: + m.PostType = bf.ReadUint32() + m.StampID = bf.ReadUint32() + m.TitleLength = bf.ReadUint32() + m.BodyLength = bf.ReadUint32() + m.Title = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.TitleLength))) + m.Body = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.BodyLength))) + case 1: + m.PostID = bf.ReadUint32() + case 2: + m.PostID = bf.ReadUint32() + bf.ReadBytes(8) + m.TitleLength = bf.ReadUint32() + m.BodyLength = bf.ReadUint32() + m.Title = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.TitleLength))) + m.Body = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.BodyLength))) + case 3: + m.PostID = bf.ReadUint32() + bf.ReadBytes(8) + m.StampID = bf.ReadUint32() + case 4: + m.PostID = bf.ReadUint32() + bf.ReadBytes(8) + m.LikeState = bf.ReadBool() } return nil } diff --git a/server/channelserver/handlers_guild.go b/server/channelserver/handlers_guild.go index a804932d0..7eca11a16 100644 --- a/server/channelserver/handlers_guild.go +++ b/server/channelserver/handlers_guild.go @@ -1867,7 +1867,6 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateGuildMessageBoard) - bf := byteframe.NewByteFrameFromBytes(pkt.Request) guild, err := GetGuildInfoByCharacterId(s, s.charID) applicant := false if guild != nil { @@ -1879,45 +1878,26 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) { } switch pkt.MessageOp { case 0: // Create message - postType := bf.ReadUint32() // 0 = message, 1 = news - stampID := bf.ReadUint32() - titleLength := bf.ReadUint32() - bodyLength := bf.ReadUint32() - title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength))) - body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength))) - s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, stampID, postType, title, body) + s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, pkt.StampID, pkt.PostType, pkt.Title, pkt.Body) // TODO: if there are too many messages, purge excess case 1: // Delete message - postID := bf.ReadUint32() - s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", postID) + s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", pkt.PostID) case 2: // Update message - postID := bf.ReadUint32() - bf.ReadBytes(8) - titleLength := bf.ReadUint32() - bodyLength := bf.ReadUint32() - title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength))) - body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength))) - s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", title, body, postID) + s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", pkt.Title, pkt.Body, pkt.PostID) case 3: // Update stamp - postID := bf.ReadUint32() - bf.ReadBytes(8) - stampID := bf.ReadUint32() - s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", stampID, postID) + s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", pkt.StampID, pkt.PostID) case 4: // Like message - postID := bf.ReadUint32() - bf.ReadBytes(8) - likeState := bf.ReadBool() var likedBy string - err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", postID).Scan(&likedBy) + err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", pkt.PostID).Scan(&likedBy) if err != nil { s.logger.Error("Failed to get guild message like data from db", zap.Error(err)) } else { - if likeState { + if pkt.LikeState { likedBy = stringsupport.CSVAdd(likedBy, int(s.charID)) - s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID) + s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID) } else { likedBy = stringsupport.CSVRemove(likedBy, int(s.charID)) - s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID) + s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID) } } case 5: // Check for new messages From 3be014ba7ffd283f27657594fdd23143719d2399 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 11 Apr 2023 21:07:43 +1000 Subject: [PATCH 40/46] remove unused code --- common/stringsupport/string_convert.go | 52 +------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/common/stringsupport/string_convert.go b/common/stringsupport/string_convert.go index 337588479..53ed2ec69 100644 --- a/common/stringsupport/string_convert.go +++ b/common/stringsupport/string_convert.go @@ -2,62 +2,14 @@ package stringsupport import ( "bytes" - "io/ioutil" + "io" "strconv" "strings" - "golang.org/x/text/encoding" "golang.org/x/text/encoding/japanese" "golang.org/x/text/transform" ) -// StringConverter is a small helper for encoding/decoding strings. -type StringConverter struct { - Encoding encoding.Encoding -} - -// Decode decodes the given bytes as the set encoding. -func (sc *StringConverter) Decode(data []byte) (string, error) { - decoded, err := ioutil.ReadAll(transform.NewReader(bytes.NewBuffer(data), sc.Encoding.NewDecoder())) - - if err != nil { - return "", err - } - - return string(decoded), nil -} - -// MustDecode decodes the given bytes as the set encoding. Panics on decode failure. -func (sc *StringConverter) MustDecode(data []byte) string { - decoded, err := sc.Decode(data) - if err != nil { - panic(err) - } - - return decoded -} - -// Encode encodes the given string as the set encoding. -func (sc *StringConverter) Encode(data string) ([]byte, error) { - encoded, err := ioutil.ReadAll(transform.NewReader(bytes.NewBuffer([]byte(data)), sc.Encoding.NewEncoder())) - - if err != nil { - return nil, err - } - - return encoded, nil -} - -// MustEncode encodes the given string as the set encoding. Panics on encode failure. -func (sc *StringConverter) MustEncode(data string) []byte { - encoded, err := sc.Encode(data) - if err != nil { - panic(err) - } - - return encoded -} - func UTF8ToSJIS(x string) []byte { e := japanese.ShiftJIS.NewEncoder() xt, _, err := transform.String(e, x) @@ -69,7 +21,7 @@ func UTF8ToSJIS(x string) []byte { func SJISToUTF8(b []byte) string { d := japanese.ShiftJIS.NewDecoder() - result, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(b), d)) + result, err := io.ReadAll(transform.NewReader(bytes.NewReader(b), d)) if err != nil { panic(err) } From 23138b2d5b484bf5228c7b2d9c64829247a82144 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 11 Apr 2023 21:08:00 +1000 Subject: [PATCH 41/46] update versioning --- config.json | 2 +- main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 03dca44e5..5571a2890 100644 --- a/config.json +++ b/config.json @@ -5,7 +5,7 @@ "DisableSoftCrash": false, "HideLoginNotice": true, "LoginNotices": [ - "
Welcome to Erupe SU9.2!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!

■Report bugs on Discord!

■Test everything!

■Don't talk to softlocking NPCs!

■Fork the code on GitHub!

Thank you to all of the contributors,

this wouldn't exist without you." + "
Welcome to Erupe SU9.3!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!

■Report bugs on Discord!

■Test everything!

■Don't talk to softlocking NPCs!

■Fork the code on GitHub!

Thank you to all of the contributors,

this wouldn't exist without you." ], "PatchServerManifest": "", "PatchServerFile": "", diff --git a/main.go b/main.go index a93d532fa..0f104eccf 100644 --- a/main.go +++ b/main.go @@ -54,7 +54,7 @@ func main() { defer zapLogger.Sync() logger := zapLogger.Named("main") - logger.Info(fmt.Sprintf("Starting Erupe (9.2-%s)", Commit())) + logger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit())) if config.ErupeConfig.Database.Password == "" { preventClose("Database password is blank") From 2ede81925affa21288ce69b198e9fd17ef453cf2 Mon Sep 17 00:00:00 2001 From: wish Date: Wed, 12 Apr 2023 05:37:41 +1000 Subject: [PATCH 42/46] rewrite signserver --- server/signserver/dsgn_resp.go | 19 +++--- server/signserver/respid.go | 5 +- server/signserver/session.go | 119 +++++++++++++++------------------ 3 files changed, 64 insertions(+), 79 deletions(-) diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index 7e9305434..ad224f48f 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -11,15 +11,7 @@ import ( "strings" ) -func makeSignInFailureResp(respID RespID) []byte { - bf := byteframe.NewByteFrame() - bf.WriteUint8(uint8(respID)) - return bf.Data() -} - -func (s *Session) makeSignInResp(uid int) []byte { - returnExpiry := s.server.getReturnExpiry(uid) - +func (s *Session) makeSignResponse(uid int) []byte { // Get the characters from the DB. chars, err := s.server.getCharactersForUser(uid) if err != nil { @@ -27,7 +19,7 @@ func (s *Session) makeSignInResp(uid int) []byte { } sessToken := token.Generate(16) - s.server.registerToken(uid, sessToken) + _ = s.server.registerToken(uid, sessToken) bf := byteframe.NewByteFrame() @@ -116,6 +108,11 @@ func (s *Session) makeSignInResp(uid int) []byte { bf.WriteUint32(s.server.getLastCID(uid)) bf.WriteUint32(s.server.getUserRights(uid)) ps.Uint16(bf, "", false) // filters + if s.client == VITA { + var psnUser string + s.server.db.QueryRow("SELECT username FROM users WHERE id = $1", uid).Scan(&psnUser) + stringsupport.PaddedString(psnUser, 20, true) + } bf.WriteUint16(0xCA10) bf.WriteUint16(0x4E20) ps.Uint16(bf, "", false) // unk key @@ -124,7 +121,7 @@ func (s *Session) makeSignInResp(uid int) []byte { bf.WriteUint16(0x0001) bf.WriteUint16(0x4E20) ps.Uint16(bf, "", false) // unk ipv4 - bf.WriteUint32(uint32(returnExpiry.Unix())) + bf.WriteUint32(uint32(s.server.getReturnExpiry(uid).Unix())) bf.WriteUint32(0x00000000) bf.WriteUint32(0x0A5197DF) // unk id diff --git a/server/signserver/respid.go b/server/signserver/respid.go index 47e7683d4..014daa862 100644 --- a/server/signserver/respid.go +++ b/server/signserver/respid.go @@ -1,10 +1,7 @@ package signserver -//revive:disable +type RespID uint8 -type RespID uint16 - -//go:generate stringer -type=RespID const ( SIGN_UNKNOWN RespID = iota SIGN_SUCCESS diff --git a/server/signserver/session.go b/server/signserver/session.go index 19270fafc..3e35708a6 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -13,6 +13,13 @@ import ( "golang.org/x/crypto/bcrypt" ) +type Client int + +const ( + PC100 Client = iota + VITA +) + // Session holds state for the sign server connection. type Session struct { sync.Mutex @@ -20,6 +27,7 @@ type Session struct { server *Server rawConn net.Conn cryptConn *network.CryptConn + client Client } func (s *Session) work() { @@ -42,91 +50,65 @@ func (s *Session) handlePacket(pkt []byte) error { bf := byteframe.NewByteFrameFromBytes(pkt) reqType := string(bf.ReadNullTerminatedBytes()) switch reqType { - case "DLTSKEYSIGN:100": - fallthrough - case "DSGN:100": - err := s.handleDSGNRequest(bf) - if err != nil { - return nil - } + case "DLTSKEYSIGN:100", "DSGN:100": + s.handleDSGN(bf) + case "VITASGN:100": + s.client = VITA + s.handleVITASGN(bf) case "DELETE:100": loginTokenString := string(bf.ReadNullTerminatedBytes()) characterID := int(bf.ReadUint32()) _ = int(bf.ReadUint32()) // login_token_number - s.server.deleteCharacter(characterID, loginTokenString) - s.logger.Info("Deleted character", zap.Int("CharacterID", characterID)) - err := s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS - if err != nil { - return nil + err := s.server.deleteCharacter(characterID, loginTokenString) + if err == nil { + s.logger.Info("Deleted character", zap.Int("CharacterID", characterID)) + s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS } default: - s.logger.Warn("Unknown sign request", zap.String("reqType", reqType)) + s.logger.Warn("Unknown request", zap.String("reqType", reqType)) if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogInboundMessages { fmt.Printf("\n[Client] -> [Server]\nData [%d bytes]:\n%s\n", len(pkt), hex.Dump(pkt)) } } - return nil } -func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error { - - reqUsername := string(bf.ReadNullTerminatedBytes()) - reqPassword := string(bf.ReadNullTerminatedBytes()) - _ = string(bf.ReadNullTerminatedBytes()) // Unk - +func (s *Session) authenticate(username string, password string) { newCharaReq := false - if reqUsername[len(reqUsername)-1] == 43 { // '+' - reqUsername = reqUsername[:len(reqUsername)-1] + if username[len(username)-1] == 43 { // '+' + username = username[:len(username)-1] newCharaReq = true } - var ( - id int - password string - ) - err := s.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", reqUsername).Scan(&id, &password) - var serverRespBytes []byte + var id int + var hash string + bf := byteframe.NewByteFrame() + + err := s.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", username).Scan(&id, &hash) switch { case err == sql.ErrNoRows: - s.logger.Info("User not found", zap.String("Username", reqUsername)) - serverRespBytes = makeSignInFailureResp(SIGN_EAUTH) - + s.logger.Info("User not found", zap.String("Username", username)) if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.AutoCreateAccount { - s.logger.Info("Creating user", zap.String("Username", reqUsername)) - err = s.server.registerDBAccount(reqUsername, reqPassword) - if err != nil { - s.logger.Error("Error registering new user", zap.Error(err)) - serverRespBytes = makeSignInFailureResp(SIGN_EABORT) - break + s.logger.Info("Creating user", zap.String("Username", username)) + err = s.server.registerDBAccount(username, password) + if err == nil { + bf.WriteBytes(s.makeSignResponse(id)) } } else { - break + bf.WriteUint8(uint8(SIGN_EAUTH)) } - - var id int - err = s.server.db.QueryRow("SELECT id FROM users WHERE username = $1", reqUsername).Scan(&id) - if err != nil { - s.logger.Error("Error getting new user ID", zap.Error(err)) - serverRespBytes = makeSignInFailureResp(SIGN_EABORT) - break - } - - serverRespBytes = s.makeSignInResp(id) - break case err != nil: - serverRespBytes = makeSignInFailureResp(SIGN_EABORT) + bf.WriteUint8(uint8(SIGN_EABORT)) s.logger.Error("Error getting user details", zap.Error(err)) - break default: - if bcrypt.CompareHashAndPassword([]byte(password), []byte(reqPassword)) == nil { + if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil { s.logger.Debug("Passwords match!") if newCharaReq { - err = s.server.newUserChara(reqUsername) + err = s.server.newUserChara(username) if err != nil { s.logger.Error("Error adding new character to user", zap.Error(err)) - serverRespBytes = makeSignInFailureResp(SIGN_EABORT) + bf.WriteUint8(uint8(SIGN_EABORT)) break } } @@ -137,22 +119,31 @@ func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error { // serverRespBytes = makeSignInFailureResp(SIGN_EABORT) // break // } - serverRespBytes = s.makeSignInResp(id) + bf.WriteBytes(s.makeSignResponse(id)) } else { s.logger.Warn("Incorrect password") - serverRespBytes = makeSignInFailureResp(SIGN_EPASS) + bf.WriteUint8(uint8(SIGN_EPASS)) } - } if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogOutboundMessages { - fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(serverRespBytes), hex.Dump(serverRespBytes)) + fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(bf.Data()), hex.Dump(bf.Data())) } - err = s.cryptConn.SendPacket(serverRespBytes) - if err != nil { - return err - } - - return nil + err = s.cryptConn.SendPacket(bf.Data()) +} + +func (s *Session) handleVITASGN(bf *byteframe.ByteFrame) { + _ = bf.ReadNullTerminatedBytes() // 0000000256 + _ = bf.ReadNullTerminatedBytes() // 1 + _ = bf.ReadBytes(82) + psnUser := string(bf.ReadNullTerminatedBytes()) + s.authenticate(psnUser, "") +} + +func (s *Session) handleDSGN(bf *byteframe.ByteFrame) { + reqUsername := string(bf.ReadNullTerminatedBytes()) + reqPassword := string(bf.ReadNullTerminatedBytes()) + _ = string(bf.ReadNullTerminatedBytes()) // Unk + s.authenticate(reqUsername, reqPassword) } From 69edc6f9612650cb042e9ca85478391d37402fd8 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 15 Apr 2023 10:49:20 +1000 Subject: [PATCH 43/46] fix mezfes --- server/signserver/dsgn_resp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index ad224f48f..c6a4031ce 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -110,8 +110,8 @@ func (s *Session) makeSignResponse(uid int) []byte { ps.Uint16(bf, "", false) // filters if s.client == VITA { var psnUser string - s.server.db.QueryRow("SELECT username FROM users WHERE id = $1", uid).Scan(&psnUser) - stringsupport.PaddedString(psnUser, 20, true) + s.server.db.QueryRow("SELECT psn_id FROM users WHERE id = $1", uid).Scan(&psnUser) + bf.WriteBytes(stringsupport.PaddedString(psnUser, 20, true)) } bf.WriteUint16(0xCA10) bf.WriteUint16(0x4E20) From f5ae129cad8d1d3ace5602f29fccf2eaf284a31a Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 15 Apr 2023 11:00:49 +1000 Subject: [PATCH 44/46] implement psn linking capability --- common/mhfcourse/mhfcourse.go | 2 +- config.json | 4 ++++ patch-schema/psn-id.sql | 5 +++++ server/channelserver/handlers_cast_binary.go | 15 +++++++++++++++ server/channelserver/sys_language.go | 4 ++++ server/signserver/session.go | 12 ++++++++++-- 6 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 patch-schema/psn-id.sql diff --git a/common/mhfcourse/mhfcourse.go b/common/mhfcourse/mhfcourse.go index 62b8d171f..13496119b 100644 --- a/common/mhfcourse/mhfcourse.go +++ b/common/mhfcourse/mhfcourse.go @@ -66,7 +66,7 @@ func CourseExists(ID uint16, c []Course) bool { // GetCourseStruct returns a slice of Course(s) from a rights integer func GetCourseStruct(rights uint32) ([]Course, uint32) { - resp := []Course{{ID: 1}} + resp := []Course{{ID: 1}, {ID: 24}} s := Courses() slices.SortStableFunc(s, func(i, j Course) bool { return i.ID > j.ID diff --git a/config.json b/config.json index 5571a2890..c29b0f31e 100644 --- a/config.json +++ b/config.json @@ -72,6 +72,10 @@ "Name": "Course", "Enabled": true, "Prefix": "!course" + }, { + "Name": "LinkPSN", + "Enabled": true, + "Prefix": "!linkpsn" } ], "Courses": [ diff --git a/patch-schema/psn-id.sql b/patch-schema/psn-id.sql new file mode 100644 index 000000000..49ae1bdd8 --- /dev/null +++ b/patch-schema/psn-id.sql @@ -0,0 +1,5 @@ +BEGIN; + +ALTER TABLE users ADD COLUMN IF NOT EXISTS psn_id TEXT; + +END; \ No newline at end of file diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 1b6b9a6ba..5db1e846f 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -82,6 +82,21 @@ func sendServerChatMessage(s *Session, message string) { } func parseChatCommand(s *Session, command string) { + if strings.HasPrefix(command, commands["LinkPSN"].Prefix) { + if commands["LinkPSN"].Enabled { + var id string + n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%s", commands["LinkPSN"].Prefix), &id) + if err != nil || n != 1 { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandLinkPSNError"], commands["LinkPSN"].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 err == nil { + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandLinkPSNSuccess"], id)) + } + } + } + } + if strings.HasPrefix(command, commands["Reload"].Prefix) { // Flush all objects and users and reload if commands["Reload"].Enabled { diff --git a/server/channelserver/sys_language.go b/server/channelserver/sys_language.go index 5de05923f..4246a929a 100644 --- a/server/channelserver/sys_language.go +++ b/server/channelserver/sys_language.go @@ -20,6 +20,8 @@ func getLangStrings(s *Server) map[string]string { strings["commandCourseLocked"] = "%sコースはロックされています" strings["commandTeleportError"] = "テレポートコマンドエラー 構文:%s x y" strings["commandTeleportSuccess"] = "%d %dにテレポート" + strings["commandLinkPSNError"] = "PSN連携コマンドエラー 例:%s " + strings["commandLinkPSNSuccess"] = "PSN「%s」が連携されています" strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません" strings["commandRaviStartSuccess"] = "大討伐を開始します" @@ -68,6 +70,8 @@ func getLangStrings(s *Server) map[string]string { strings["commandCourseLocked"] = "%s Course is locked" strings["commandTeleportError"] = "Error in command. Format: %s x y" strings["commandTeleportSuccess"] = "Teleporting to %d %d" + strings["commandLinkPSNError"] = "Error in command. Format: %s " + strings["commandLinkPSNSuccess"] = "Connected PSN ID: %s" strings["commandRaviNoCommand"] = "No Raviente command specified!" strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment" diff --git a/server/signserver/session.go b/server/signserver/session.go index 3e35708a6..a3906481e 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -102,7 +102,7 @@ func (s *Session) authenticate(username string, password string) { bf.WriteUint8(uint8(SIGN_EABORT)) s.logger.Error("Error getting user details", zap.Error(err)) default: - if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil { + if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil || s.client == VITA { s.logger.Debug("Passwords match!") if newCharaReq { err = s.server.newUserChara(username) @@ -138,7 +138,15 @@ func (s *Session) handleVITASGN(bf *byteframe.ByteFrame) { _ = bf.ReadNullTerminatedBytes() // 1 _ = bf.ReadBytes(82) psnUser := string(bf.ReadNullTerminatedBytes()) - s.authenticate(psnUser, "") + var reqUsername string + err := s.server.db.QueryRow(`SELECT username FROM users WHERE psn_id = $1`, psnUser).Scan(&reqUsername) + if err == sql.ErrNoRows { + resp := byteframe.NewByteFrame() + resp.WriteUint8(uint8(SIGN_ECOGLINK)) + s.cryptConn.SendPacket(resp.Data()) + return + } + s.authenticate(reqUsername, "") } func (s *Session) handleDSGN(bf *byteframe.ByteFrame) { From aeab3352ae28942cdc4163f6484873025fc2cf75 Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 15 Apr 2023 11:19:19 +1000 Subject: [PATCH 45/46] rename psn command --- config.json | 4 ++-- server/channelserver/handlers_cast_binary.go | 10 +++++----- server/channelserver/sys_language.go | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/config.json b/config.json index c29b0f31e..2a62a3809 100644 --- a/config.json +++ b/config.json @@ -73,9 +73,9 @@ "Enabled": true, "Prefix": "!course" }, { - "Name": "LinkPSN", + "Name": "PSN", "Enabled": true, - "Prefix": "!linkpsn" + "Prefix": "!psn" } ], "Courses": [ diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index 5db1e846f..7c961b5e9 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -82,16 +82,16 @@ func sendServerChatMessage(s *Session, message string) { } func parseChatCommand(s *Session, command string) { - if strings.HasPrefix(command, commands["LinkPSN"].Prefix) { - if commands["LinkPSN"].Enabled { + if strings.HasPrefix(command, commands["PSN"].Prefix) { + if commands["PSN"].Enabled { var id string - n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%s", commands["LinkPSN"].Prefix), &id) + 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["commandLinkPSNError"], commands["LinkPSN"].Prefix)) + 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 err == nil { - sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandLinkPSNSuccess"], id)) + sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNSuccess"], id)) } } } diff --git a/server/channelserver/sys_language.go b/server/channelserver/sys_language.go index 4246a929a..f393c5689 100644 --- a/server/channelserver/sys_language.go +++ b/server/channelserver/sys_language.go @@ -20,8 +20,8 @@ func getLangStrings(s *Server) map[string]string { strings["commandCourseLocked"] = "%sコースはロックされています" strings["commandTeleportError"] = "テレポートコマンドエラー 構文:%s x y" strings["commandTeleportSuccess"] = "%d %dにテレポート" - strings["commandLinkPSNError"] = "PSN連携コマンドエラー 例:%s " - strings["commandLinkPSNSuccess"] = "PSN「%s」が連携されています" + strings["commandPSNError"] = "PSN連携コマンドエラー 例:%s " + strings["commandPSNSuccess"] = "PSN「%s」が連携されています" strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません" strings["commandRaviStartSuccess"] = "大討伐を開始します" @@ -70,8 +70,8 @@ func getLangStrings(s *Server) map[string]string { strings["commandCourseLocked"] = "%s Course is locked" strings["commandTeleportError"] = "Error in command. Format: %s x y" strings["commandTeleportSuccess"] = "Teleporting to %d %d" - strings["commandLinkPSNError"] = "Error in command. Format: %s " - strings["commandLinkPSNSuccess"] = "Connected PSN ID: %s" + strings["commandPSNError"] = "Error in command. Format: %s " + strings["commandPSNSuccess"] = "Connected PSN ID: %s" strings["commandRaviNoCommand"] = "No Raviente command specified!" strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment" From 90cb8525e55810e5dd0118819dc8227d988e7bef Mon Sep 17 00:00:00 2001 From: wish Date: Sat, 15 Apr 2023 11:27:43 +1000 Subject: [PATCH 46/46] add support for PS3SGN --- server/signserver/dsgn_resp.go | 2 +- server/signserver/session.go | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go index c6a4031ce..926711d57 100644 --- a/server/signserver/dsgn_resp.go +++ b/server/signserver/dsgn_resp.go @@ -108,7 +108,7 @@ func (s *Session) makeSignResponse(uid int) []byte { bf.WriteUint32(s.server.getLastCID(uid)) bf.WriteUint32(s.server.getUserRights(uid)) ps.Uint16(bf, "", false) // filters - if s.client == VITA { + if s.client == VITA || s.client == PS3 { var psnUser string s.server.db.QueryRow("SELECT psn_id FROM users WHERE id = $1", uid).Scan(&psnUser) bf.WriteBytes(stringsupport.PaddedString(psnUser, 20, true)) diff --git a/server/signserver/session.go b/server/signserver/session.go index a3906481e..dfe034226 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -18,6 +18,7 @@ type Client int const ( PC100 Client = iota VITA + PS3 ) // Session holds state for the sign server connection. @@ -52,9 +53,12 @@ func (s *Session) handlePacket(pkt []byte) error { switch reqType { case "DLTSKEYSIGN:100", "DSGN:100": s.handleDSGN(bf) + case "PS3SGN:100": + s.client = PS3 + s.handlePSSGN(bf) case "VITASGN:100": s.client = VITA - s.handleVITASGN(bf) + s.handlePSSGN(bf) case "DELETE:100": loginTokenString := string(bf.ReadNullTerminatedBytes()) characterID := int(bf.ReadUint32()) @@ -102,7 +106,7 @@ func (s *Session) authenticate(username string, password string) { bf.WriteUint8(uint8(SIGN_EABORT)) s.logger.Error("Error getting user details", zap.Error(err)) default: - if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil || s.client == VITA { + if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil || s.client == VITA || s.client == PS3 { s.logger.Debug("Passwords match!") if newCharaReq { err = s.server.newUserChara(username) @@ -133,7 +137,7 @@ func (s *Session) authenticate(username string, password string) { err = s.cryptConn.SendPacket(bf.Data()) } -func (s *Session) handleVITASGN(bf *byteframe.ByteFrame) { +func (s *Session) handlePSSGN(bf *byteframe.ByteFrame) { _ = bf.ReadNullTerminatedBytes() // 0000000256 _ = bf.ReadNullTerminatedBytes() // 1 _ = bf.ReadBytes(82)