From b8f5aa87a28673de19d07cf4b5a0da89ff8266b0 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 24 Jul 2022 12:32:41 +1000 Subject: [PATCH 01/14] implement basic my series functionality --- .../mhfpacket/msg_mhf_enumerate_house.go | 5 +- Erupe/network/mhfpacket/msg_mhf_load_house.go | 35 ++-- .../network/mhfpacket/msg_mhf_update_house.go | 18 +-- Erupe/server/channelserver/handlers_data.go | 2 + Erupe/server/channelserver/handlers_house.go | 150 +++++++++++++++++- Erupe/server/channelserver/sys_session.go | 7 + 6 files changed, 175 insertions(+), 42 deletions(-) diff --git a/Erupe/network/mhfpacket/msg_mhf_enumerate_house.go b/Erupe/network/mhfpacket/msg_mhf_enumerate_house.go index 3758a8c38..9bd1f30ef 100644 --- a/Erupe/network/mhfpacket/msg_mhf_enumerate_house.go +++ b/Erupe/network/mhfpacket/msg_mhf_enumerate_house.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + "erupe-ce/common/stringsupport" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -14,7 +15,7 @@ type MsgMhfEnumerateHouse struct { CharID uint32 Method uint8 Unk uint16 - Name []byte + Name string } // Opcode returns the ID associated with this packet type. @@ -29,7 +30,7 @@ func (m *MsgMhfEnumerateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cli m.Method = bf.ReadUint8() m.Unk = bf.ReadUint16() _ = bf.ReadUint8() // len - m.Name = bf.ReadNullTerminatedBytes() + m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/Erupe/network/mhfpacket/msg_mhf_load_house.go b/Erupe/network/mhfpacket/msg_mhf_load_house.go index db0a04307..ebc7cb0ee 100644 --- a/Erupe/network/mhfpacket/msg_mhf_load_house.go +++ b/Erupe/network/mhfpacket/msg_mhf_load_house.go @@ -1,29 +1,22 @@ package mhfpacket import ( - "errors" + "errors" + "erupe-ce/common/stringsupport" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfLoadHouse represents the MSG_MHF_LOAD_HOUSE type MsgMhfLoadHouse struct { - AckHandle uint32 - CharID uint32 - // dest? - // 0x3 = house - // 0x4 = bookshelf - // 0x5 = gallery - // 0x8 = tore - // 0x9 = own house - // 0xA = garden - Unk1 uint8 - // bool inMezSquare? - Unk2 uint8 - Unk3 uint16 // Hardcoded 0 in binary - Password []byte + AckHandle uint32 + CharID uint32 + Destination uint8 + InMezeporta bool + Unk3 uint16 // Hardcoded 0 in binary + Password string } // Opcode returns the ID associated with this packet type. @@ -35,11 +28,11 @@ func (m *MsgMhfLoadHouse) Opcode() network.PacketID { func (m *MsgMhfLoadHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() m.CharID = bf.ReadUint32() - m.Unk1 = bf.ReadUint8() - m.Unk2 = bf.ReadUint8() + m.Destination = bf.ReadUint8() + m.InMezeporta = bf.ReadBool() _ = bf.ReadUint16() - _ = bf.ReadUint8() // Password length - m.Password = bf.ReadNullTerminatedBytes() + _ = bf.ReadUint8() // Password length + m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/Erupe/network/mhfpacket/msg_mhf_update_house.go b/Erupe/network/mhfpacket/msg_mhf_update_house.go index 47354a23f..320972673 100644 --- a/Erupe/network/mhfpacket/msg_mhf_update_house.go +++ b/Erupe/network/mhfpacket/msg_mhf_update_house.go @@ -2,6 +2,7 @@ package mhfpacket import ( "errors" + "erupe-ce/common/stringsupport" "erupe-ce/common/byteframe" "erupe-ce/network" @@ -11,15 +12,10 @@ import ( // MsgMhfUpdateHouse represents the MSG_MHF_UPDATE_HOUSE type MsgMhfUpdateHouse struct { AckHandle uint32 - // 01 = closed - // 02 = open anyone - // 03 = open friends - // 04 = open guild - // 05 = open friends guild - State uint8 - Unk1 uint8 // Always 0x01 - Unk2 uint16 // Always 0x0000 - Password string + State uint8 + Unk1 uint8 // Always 0x01 + Unk2 uint16 // Always 0x0000 + Password string } // Opcode returns the ID associated with this packet type. @@ -33,8 +29,8 @@ func (m *MsgMhfUpdateHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client m.State = bf.ReadUint8() m.Unk1 = bf.ReadUint8() m.Unk2 = bf.ReadUint16() - _ = bf.ReadUint8() - m.Password = string(bf.ReadNullTerminatedBytes()) + _ = bf.ReadUint8() // Password length + m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/Erupe/server/channelserver/handlers_data.go b/Erupe/server/channelserver/handlers_data.go index ea6724eec..88f634ba3 100644 --- a/Erupe/server/channelserver/handlers_data.go +++ b/Erupe/server/channelserver/handlers_data.go @@ -61,6 +61,8 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) } + s.house.tier = decompressedData[129904] + isMale := uint8(decompressedData[80]) // 0x50 if isMale == 1 { _, err = s.server.db.Exec("UPDATE characters SET is_female=true WHERE id=$1", s.charID) diff --git a/Erupe/server/channelserver/handlers_house.go b/Erupe/server/channelserver/handlers_house.go index 94ce5e3b4..30a016abb 100644 --- a/Erupe/server/channelserver/handlers_house.go +++ b/Erupe/server/channelserver/handlers_house.go @@ -2,6 +2,8 @@ package channelserver import ( "erupe-ce/common/byteframe" + ps "erupe-ce/common/pascalstring" + "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" "go.uber.org/zap" ) @@ -15,28 +17,160 @@ func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } -func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) +type HouseData struct { + CharID uint32 `db:"id"` + HRP uint16 `db:"hrp"` + GR uint16 `db:"gr"` + Name string `db:"name"` } -func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateHouse) + bf := byteframe.NewByteFrame() + var houses []HouseData + switch pkt.Method { + case 1: + var friendsList string + s.server.db.QueryRow("SELECT friends FROM characters WHERE id=$1", s.charID).Scan(&friendsList) + cids := stringsupport.CSVElems(friendsList) + for _, cid := range cids { + house := HouseData{} + row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", cid) + err := row.StructScan(&house) + if err != nil { + panic(err) + } else { + houses = append(houses, house) + } + } + case 2: + guild, err := GetGuildInfoByCharacterId(s, s.charID) + if err != nil { + break + } + guildMembers, err := GetGuildMembers(s, guild.ID, false) + if err != nil { + break + } + for _, member := range guildMembers { + house := HouseData{} + row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", member.CharID) + err := row.StructScan(&house) + if err != nil { + panic(err) + } else { + houses = append(houses, house) + } + } + case 3: + house := HouseData{} + row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE name=$1", pkt.Name) + err := row.StructScan(&house) + if err != nil { + panic(err) + } else { + houses = append(houses, house) + } + case 4: + house := HouseData{} + row := s.server.db.QueryRowx("SELECT id, hrp, gr, name FROM characters WHERE id=$1", pkt.CharID) + err := row.StructScan(&house) + if err != nil { + panic(err) + } else { + houses = append(houses, house) + } + case 5: // Recent visitors + break + } + var exists int + for _, house := range houses { + for _, session := range s.server.sessions { + if session.charID == house.CharID { + exists++ + bf.WriteUint32(house.CharID) + bf.WriteUint8(session.house.state) + if len(session.house.password) > 0 { + bf.WriteUint8(3) + } else { + bf.WriteUint8(0) + } + bf.WriteUint16(house.HRP) + bf.WriteUint16(house.GR) + ps.Uint8(bf, house.Name, true) + break + } + } + } + resp := byteframe.NewByteFrame() + resp.WriteUint16(uint16(exists)) + resp.WriteBytes(bf.Data()) + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) +} + +func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfUpdateHouse) + // 01 = closed + // 02 = open anyone + // 03 = open friends + // 04 = open guild + // 05 = open friends+guild + s.house.state = pkt.State + s.house.password = pkt.Password + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) +} func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadHouse) bf := byteframe.NewByteFrame() var data []byte - err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", s.charID).Scan(&data) + err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&data) if err != nil { panic(err) } if data == nil { data = make([]byte, 20) } - if pkt.CharID != s.charID { - bf.WriteBytes(make([]byte, 219)) + // TODO: Find where the missing data comes from, savefile offset? + switch pkt.Destination { + case 3: // Others house + houseTier := uint8(2) // Fallback if can't find + for _, session := range s.server.sessions { + if session.charID == pkt.CharID { + if pkt.Password != session.house.password { + // Not the correct error code but works + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } + houseTier = session.house.tier + } + } + bf.WriteBytes(make([]byte, 4)) + bf.WriteUint8(houseTier) // House tier 0x1FB70 + // Item box style + // Rastae + // Partner + bf.WriteBytes(make([]byte, 214)) + bf.WriteBytes(data) + case 4: // Bookshelf + // Hunting log + // Street names/Aliases + bf.WriteBytes(make([]byte, 5576)) + case 5: // Gallery + // Furniture placement + bf.WriteBytes(make([]byte, 1748)) + case 8: // Tore + // Sister + // Cat shops + // Pugis + bf.WriteBytes(make([]byte, 240)) + case 9: // Own house + bf.WriteBytes(data) + case 10: // Garden + // Gardening upgrades + // Gooks + bf.WriteBytes(make([]byte, 72)) } - bf.WriteBytes(data) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } diff --git a/Erupe/server/channelserver/sys_session.go b/Erupe/server/channelserver/sys_session.go index a023381ff..d4de598a5 100644 --- a/Erupe/server/channelserver/sys_session.go +++ b/Erupe/server/channelserver/sys_session.go @@ -27,6 +27,7 @@ type Session struct { sendPackets chan []byte clientContext *clientctx.ClientContext + house House stageID string stage *Stage reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. @@ -54,6 +55,12 @@ type Session struct { Name string } +type House struct { + tier uint8 + state uint8 + password string +} + // NewSession creates a new Session type. func NewSession(server *Server, conn net.Conn) *Session { s := &Session{ From d073a728264a567e1050b992f254826cfcafd9f3 Mon Sep 17 00:00:00 2001 From: wish Date: Sun, 24 Jul 2022 15:54:56 +1000 Subject: [PATCH 02/14] parse enumerate title further --- .../mhfpacket/msg_mhf_enumerate_title.go | 16 +++++++------- Erupe/server/channelserver/handlers_house.go | 21 +++++++++++-------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Erupe/network/mhfpacket/msg_mhf_enumerate_title.go b/Erupe/network/mhfpacket/msg_mhf_enumerate_title.go index e7bc8398e..8506e7071 100644 --- a/Erupe/network/mhfpacket/msg_mhf_enumerate_title.go +++ b/Erupe/network/mhfpacket/msg_mhf_enumerate_title.go @@ -1,17 +1,17 @@ package mhfpacket import ( - "errors" + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgMhfEnumerateTitle represents the MSG_MHF_ENUMERATE_TITLE type MsgMhfEnumerateTitle struct { - AckHandle uint32 - Unk0 uint32 + AckHandle uint32 + CharID uint32 } // Opcode returns the ID associated with this packet type. @@ -21,9 +21,9 @@ func (m *MsgMhfEnumerateTitle) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgMhfEnumerateTitle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint32() - return nil + m.AckHandle = bf.ReadUint32() + m.CharID = bf.ReadUint32() + return nil } // Build builds a binary packet from the current data. diff --git a/Erupe/server/channelserver/handlers_house.go b/Erupe/server/channelserver/handlers_house.go index 30a016abb..7e77df565 100644 --- a/Erupe/server/channelserver/handlers_house.go +++ b/Erupe/server/channelserver/handlers_house.go @@ -154,7 +154,6 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { bf.WriteBytes(data) case 4: // Bookshelf // Hunting log - // Street names/Aliases bf.WriteBytes(make([]byte, 5576)) case 5: // Gallery // Furniture placement @@ -279,14 +278,18 @@ func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfEnumerateTitle(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateTitle) bf := byteframe.NewByteFrame() - titleCount := 114 // all titles unlocked - bf.WriteUint16(uint16(titleCount)) // title count - bf.WriteUint16(0) // unk - for i := 0; i < titleCount; i++ { - bf.WriteUint16(uint16(i)) - bf.WriteUint16(0) // unk - bf.WriteUint32(0) // timestamp acquired - bf.WriteUint32(0) // timestamp updated + if pkt.CharID == s.charID { + titleCount := 114 // all titles unlocked + bf.WriteUint16(uint16(titleCount)) // title count + bf.WriteUint16(0) // unk + for i := 0; i < titleCount; i++ { + bf.WriteUint16(uint16(i)) + bf.WriteUint16(0) // unk + bf.WriteUint32(0) // timestamp acquired + bf.WriteUint32(0) // timestamp updated + } + } else { + bf.WriteUint16(0) } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } From bfdcca44e1ee2d982acb2d9541c00da7bbef172d Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 02:27:36 +1000 Subject: [PATCH 03/14] fix gook enumeration --- .../mhfpacket/msg_mhf_update_guacot.go | 127 ++++----------- Erupe/server/channelserver/handlers.go | 145 +++++------------- 2 files changed, 63 insertions(+), 209 deletions(-) diff --git a/Erupe/network/mhfpacket/msg_mhf_update_guacot.go b/Erupe/network/mhfpacket/msg_mhf_update_guacot.go index 5c220aad2..c5a73944e 100644 --- a/Erupe/network/mhfpacket/msg_mhf_update_guacot.go +++ b/Erupe/network/mhfpacket/msg_mhf_update_guacot.go @@ -1,42 +1,22 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) -// GuacotUpdateEntry represents an entry inside the MsgMhfUpdateGuacot packet. -type GuacotUpdateEntry struct { - Unk0 uint32 - Unk1 uint16 - Unk2 uint16 - Unk3 uint16 - Unk4 uint16 - Unk5 uint16 - Unk6 uint16 - Unk7 uint16 - Unk8 uint16 - Unk9 uint16 - Unk10 uint16 - Unk11 uint16 - Unk12 uint16 - Unk13 uint16 - Unk14 uint16 - Unk15 uint16 - Unk16 uint16 - Unk17 uint16 - Unk18 uint16 - Unk19 uint16 - Unk20 uint16 - Unk21 uint16 - Unk22 uint16 - Unk23 uint32 - Unk24 uint32 - DataSize uint8 - RawDataPayload []byte +type Gook struct { + Exists bool + Index uint32 + Type uint16 + Data []byte + Birthday1 uint32 + Birthday2 uint32 + NameLen uint8 + Name []byte } // MsgMhfUpdateGuacot represents the MSG_MHF_UPDATE_GUACOT @@ -44,7 +24,7 @@ type MsgMhfUpdateGuacot struct { AckHandle uint32 EntryCount uint16 Unk0 uint16 // Hardcoded 0 in binary - Entries []*GuacotUpdateEntry + Gooks []Gook } // Opcode returns the ID associated with this packet type. @@ -58,38 +38,20 @@ func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien m.EntryCount = bf.ReadUint16() m.Unk0 = bf.ReadUint16() for i := 0; i < int(m.EntryCount); i++ { - // Yikes. - e := &GuacotUpdateEntry{} - - e.Unk0 = bf.ReadUint32() - e.Unk1 = bf.ReadUint16() - e.Unk2 = bf.ReadUint16() - e.Unk3 = bf.ReadUint16() - e.Unk4 = bf.ReadUint16() - e.Unk5 = bf.ReadUint16() - e.Unk6 = bf.ReadUint16() - e.Unk7 = bf.ReadUint16() - e.Unk8 = bf.ReadUint16() - e.Unk9 = bf.ReadUint16() - e.Unk10 = bf.ReadUint16() - e.Unk11 = bf.ReadUint16() - e.Unk12 = bf.ReadUint16() - e.Unk13 = bf.ReadUint16() - e.Unk14 = bf.ReadUint16() - e.Unk15 = bf.ReadUint16() - e.Unk16 = bf.ReadUint16() - e.Unk17 = bf.ReadUint16() - e.Unk18 = bf.ReadUint16() - e.Unk19 = bf.ReadUint16() - e.Unk20 = bf.ReadUint16() - e.Unk21 = bf.ReadUint16() - e.Unk22 = bf.ReadUint16() - e.Unk23 = bf.ReadUint32() - e.Unk24 = bf.ReadUint32() - e.DataSize = bf.ReadUint8() - e.RawDataPayload = bf.ReadBytes(uint(e.DataSize)) - - m.Entries = append(m.Entries, e) + e := Gook{} + e.Index = bf.ReadUint32() + e.Type = bf.ReadUint16() + e.Data = bf.ReadBytes(42) + e.Birthday1 = bf.ReadUint32() + e.Birthday2 = bf.ReadUint32() + e.NameLen = bf.ReadUint8() + e.Name = bf.ReadBytes(uint(e.NameLen)) + if e.Type > 0 { + e.Exists = true + } else { + e.Exists = false + } + m.Gooks = append(m.Gooks, e) } return nil } @@ -98,36 +60,3 @@ func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien func (m *MsgMhfUpdateGuacot) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { return errors.New("NOT IMPLEMENTED") } - -func (m *MsgMhfUpdateGuacot) GuacotUpdateEntryToBytes(Entry *GuacotUpdateEntry) []byte { - resp:= byteframe.NewByteFrame() - resp.WriteUint32(Entry.Unk0) - resp.WriteUint16(Entry.Unk1) - resp.WriteUint16(Entry.Unk1) - resp.WriteUint16(Entry.Unk2) - resp.WriteUint16(Entry.Unk3) - resp.WriteUint16(Entry.Unk4) - resp.WriteUint16(Entry.Unk5) - resp.WriteUint16(Entry.Unk6) - resp.WriteUint16(Entry.Unk7) - resp.WriteUint16(Entry.Unk8) - resp.WriteUint16(Entry.Unk9) - resp.WriteUint16(Entry.Unk10) - resp.WriteUint16(Entry.Unk11) - resp.WriteUint16(Entry.Unk12) - resp.WriteUint16(Entry.Unk13) - resp.WriteUint16(Entry.Unk14) - resp.WriteUint16(Entry.Unk15) - resp.WriteUint16(Entry.Unk16) - resp.WriteUint16(Entry.Unk17) - resp.WriteUint16(Entry.Unk18) - resp.WriteUint16(Entry.Unk19) - resp.WriteUint16(Entry.Unk20) - resp.WriteUint16(Entry.Unk21) - resp.WriteUint16(Entry.Unk22) - resp.WriteUint32(Entry.Unk23) - resp.WriteUint32(Entry.Unk24) - resp.WriteUint8(Entry.DataSize) - resp.WriteBytes(Entry.RawDataPayload) - return resp.Data() -} \ No newline at end of file diff --git a/Erupe/server/channelserver/handlers.go b/Erupe/server/channelserver/handlers.go index 1a0f12ae1..4381d8ca2 100644 --- a/Erupe/server/channelserver/handlers.go +++ b/Erupe/server/channelserver/handlers.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/binary" "encoding/hex" - "fmt" + "io/ioutil" "math/bits" "math/rand" @@ -579,123 +579,48 @@ func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot) - var data bool - err := s.server.db.QueryRow("SELECT gook0status FROM gook WHERE id = $1", s.charID).Scan(&data) - if err == nil { - tempresp := byteframe.NewByteFrame() - count := uint16(0) - var gook0 []byte - var gook1 []byte - var gook2 []byte - var gook3 []byte - var gook4 []byte - var gook5 []byte - var gook0status bool - var gook1status bool - var gook2status bool - var gook3status bool - var gook4status bool - var gook5status bool - _ = s.server.db.QueryRow("SELECT gook0 FROM gook WHERE id = $1", s.charID).Scan(&gook0) - _ = s.server.db.QueryRow("SELECT gook1 FROM gook WHERE id = $1", s.charID).Scan(&gook1) - _ = s.server.db.QueryRow("SELECT gook2 FROM gook WHERE id = $1", s.charID).Scan(&gook2) - _ = s.server.db.QueryRow("SELECT gook3 FROM gook WHERE id = $1", s.charID).Scan(&gook3) - _ = s.server.db.QueryRow("SELECT gook4 FROM gook WHERE id = $1", s.charID).Scan(&gook4) - _ = s.server.db.QueryRow("SELECT gook5 FROM gook WHERE id = $1", s.charID).Scan(&gook5) - _ = s.server.db.QueryRow("SELECT gook0status FROM gook WHERE id = $1", s.charID).Scan(&gook0status) - _ = s.server.db.QueryRow("SELECT gook1status FROM gook WHERE id = $1", s.charID).Scan(&gook1status) - _ = s.server.db.QueryRow("SELECT gook2status FROM gook WHERE id = $1", s.charID).Scan(&gook2status) - _ = s.server.db.QueryRow("SELECT gook3status FROM gook WHERE id = $1", s.charID).Scan(&gook3status) - _ = s.server.db.QueryRow("SELECT gook4status FROM gook WHERE id = $1", s.charID).Scan(&gook4status) - _ = s.server.db.QueryRow("SELECT gook5status FROM gook WHERE id = $1", s.charID).Scan(&gook5status) - if gook0status == true { + var data []byte + var count uint16 + bf := byteframe.NewByteFrame() + for i := 0; i < 5; i++ { + err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), s.charID).Scan(&data) + if err == nil && data != nil { count++ - tempresp.WriteBytes(gook0) + bf.WriteBytes(data) } - if gook1status == true { - count++ - tempresp.WriteBytes(gook1) - } - if gook2status == true { - count++ - tempresp.WriteBytes(gook2) - } - if gook3status == true { - count++ - tempresp.WriteBytes(gook3) - } - if gook4status == true { - count++ - tempresp.WriteBytes(gook4) - } - if gook5status == true { - count++ - tempresp.WriteBytes(gook5) - } - if count == uint16(0) { - doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) - } else { - resp := byteframe.NewByteFrame() - resp.WriteUint16(count) - resp.WriteBytes(tempresp.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - } - } else { - doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } + resp := byteframe.NewByteFrame() + resp.WriteUint16(count) + resp.WriteBytes(bf.Data()) + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfUpdateGuacot) - count := int(pkt.EntryCount) - fmt.Printf("handleMsgMhfUpdateGuacot:%d\n", count) - if count == 0 { - _, err := s.server.db.Exec("INSERT INTO gook(id,gook0status,gook1status,gook2status,gook3status,gook4status,gook5status) VALUES($1,bool(false),bool(false),bool(false),bool(false),bool(false),bool(false))", s.charID) - if err != nil { - fmt.Printf("INSERT INTO gook failure\n") - } - } else { - for i := 0; i < int(pkt.EntryCount); i++ { - gookindex := int(pkt.Entries[i].Unk0) - buf := pkt.GuacotUpdateEntryToBytes(pkt.Entries[i]) - //fmt.Printf("gookindex:%d\n", gookindex) - switch gookindex { - case 0: - s.server.db.Exec("UPDATE gook SET gook0 = $1 WHERE id = $2", buf, s.charID) - if pkt.Entries[i].Unk1 != uint16(0) { - s.server.db.Exec("UPDATE gook SET gook0status = $1 WHERE id = $2", bool(true), s.charID) - } else { - s.server.db.Exec("UPDATE gook SET gook0status = $1 WHERE id = $2", bool(false), s.charID) - } - case 1: - s.server.db.Exec("UPDATE gook SET gook1 = $1 WHERE id = $2", buf, s.charID) - if pkt.Entries[i].Unk1 != uint16(0) { - s.server.db.Exec("UPDATE gook SET gook1status = $1 WHERE id = $2", bool(true), s.charID) - } else { - s.server.db.Exec("UPDATE gook SET gook1status = $1 WHERE id = $2", bool(false), s.charID) - } - case 2: - s.server.db.Exec("UPDATE gook SET gook2 = $1 WHERE id = $2", buf, s.charID) - if pkt.Entries[i].Unk1 != uint16(0) { - s.server.db.Exec("UPDATE gook SET gook2status = $1 WHERE id = $2", bool(true), s.charID) - } else { - s.server.db.Exec("UPDATE gook SET gook2status = $1 WHERE id = $2", bool(false), s.charID) - } - case 3: - s.server.db.Exec("UPDATE gook SET gook3 = $1 WHERE id = $2", buf, s.charID) - if pkt.Entries[i].Unk1 != uint16(0) { - s.server.db.Exec("UPDATE gook SET gook3status = $1 WHERE id = $2", bool(true), s.charID) - } else { - s.server.db.Exec("UPDATE gook SET gook3status = $1 WHERE id = $2", bool(false), s.charID) - } - case 4: - s.server.db.Exec("UPDATE gook SET gook4 = $1 WHERE id = $2", buf, s.charID) - if pkt.Entries[i].Unk1 != uint16(0) { - s.server.db.Exec("UPDATE gook SET gook4status = $1 WHERE id = $2", bool(true), s.charID) - } else { - s.server.db.Exec("UPDATE gook SET gook4status = $1 WHERE id = $2", bool(false), s.charID) - } + for _, gook := range pkt.Gooks { + if !gook.Exists { + s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=NULL WHERE id=$1", gook.Index), s.charID) + } else { + // TODO: Birthdays are still 7 years in the past + //var data []byte + //err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", gook.Index), s.charID).Scan(&data) + //if err != nil && data == nil { // If index doesn't exist + // // Give gook a birthday not 7 years ago + // gook.Birthday1 = uint32(time.Now().Unix()) + // gook.Birthday2 = uint32(time.Now().Unix()) + //} + bf := byteframe.NewByteFrame() + bf.WriteUint32(gook.Index) + if gook.Index == 0 { + bf.WriteUint16(gook.Type) } + bf.WriteUint16(gook.Type) + bf.WriteBytes(gook.Data) + bf.WriteUint32(gook.Birthday1) + bf.WriteUint32(gook.Birthday2) + bf.WriteUint8(gook.NameLen) + bf.WriteBytes(gook.Name) + s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=$1 WHERE id=$2", gook.Index), bf.Data(), s.charID) } } doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) From 9dcb68e8e71f4e9da41cde322c354cc2e1ede222 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 02:32:16 +1000 Subject: [PATCH 04/14] add cleanup query --- Erupe/gook.sql | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Erupe/gook.sql diff --git a/Erupe/gook.sql b/Erupe/gook.sql new file mode 100644 index 000000000..af70efd86 --- /dev/null +++ b/Erupe/gook.sql @@ -0,0 +1,24 @@ +BEGIN; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook0status; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook1status; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook2status; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook3status; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook4status; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook5status; + +ALTER TABLE IF EXISTS public.gook + DROP COLUMN IF EXISTS gook5; + +END; \ No newline at end of file From 23e2e25c724eebd6da204cb5f03b6cd3b1c4e15c Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 12:59:45 +1000 Subject: [PATCH 05/14] improve house entry handling --- Erupe/network/mhfpacket/msg_mhf_load_house.go | 9 ++-- Erupe/server/channelserver/handlers_house.go | 45 +++++++++++++------ 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Erupe/network/mhfpacket/msg_mhf_load_house.go b/Erupe/network/mhfpacket/msg_mhf_load_house.go index ebc7cb0ee..a012b2f1c 100644 --- a/Erupe/network/mhfpacket/msg_mhf_load_house.go +++ b/Erupe/network/mhfpacket/msg_mhf_load_house.go @@ -14,9 +14,10 @@ type MsgMhfLoadHouse struct { AckHandle uint32 CharID uint32 Destination uint8 - InMezeporta bool - Unk3 uint16 // Hardcoded 0 in binary - Password string + // False if already in hosts My Series, in case host updates PW + CheckPass bool + Unk3 uint16 // Hardcoded 0 in binary + Password string } // Opcode returns the ID associated with this packet type. @@ -29,7 +30,7 @@ func (m *MsgMhfLoadHouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientCo m.AckHandle = bf.ReadUint32() m.CharID = bf.ReadUint32() m.Destination = bf.ReadUint8() - m.InMezeporta = bf.ReadBool() + m.CheckPass = bf.ReadBool() _ = bf.ReadUint16() _ = bf.ReadUint8() // Password length m.Password = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) diff --git a/Erupe/server/channelserver/handlers_house.go b/Erupe/server/channelserver/handlers_house.go index 7e77df565..8aaeeb9fa 100644 --- a/Erupe/server/channelserver/handlers_house.go +++ b/Erupe/server/channelserver/handlers_house.go @@ -123,35 +123,54 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfLoadHouse) bf := byteframe.NewByteFrame() - var data []byte - err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&data) + if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { + for _, session := range s.server.sessions { + if session.charID == pkt.CharID && pkt.Password != session.house.password { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + return + } + } + } + + var furniture []byte + err := s.server.db.QueryRow("SELECT house FROM characters WHERE id=$1", pkt.CharID).Scan(&furniture) if err != nil { panic(err) } - if data == nil { - data = make([]byte, 20) + if furniture == nil { + furniture = make([]byte, 20) } + // TODO: Find where the missing data comes from, savefile offset? switch pkt.Destination { case 3: // Others house houseTier := uint8(2) // Fallback if can't find for _, session := range s.server.sessions { if session.charID == pkt.CharID { - if pkt.Password != session.house.password { - // Not the correct error code but works - doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) - return - } houseTier = session.house.tier } } bf.WriteBytes(make([]byte, 4)) bf.WriteUint8(houseTier) // House tier 0x1FB70 - // Item box style + bf.WriteBytes(make([]byte, 80)) + // Item box style bitfield + // tier 1 = 0x09FE + // tier 2 = 0x69FF + // tier 3 = 0xE9FF + // unused = 0x0001 + // unused = 0x6000 + switch houseTier { + case 0: + bf.WriteUint16(0x0000) + case 1: + bf.WriteUint16(0x69FF) + case 2: + bf.WriteUint16(0xE9FF) + } // Rastae // Partner - bf.WriteBytes(make([]byte, 214)) - bf.WriteBytes(data) + bf.WriteBytes(make([]byte, 132)) + bf.WriteBytes(furniture) case 4: // Bookshelf // Hunting log bf.WriteBytes(make([]byte, 5576)) @@ -164,7 +183,7 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { // Pugis bf.WriteBytes(make([]byte, 240)) case 9: // Own house - bf.WriteBytes(data) + bf.WriteBytes(furniture) case 10: // Garden // Gardening upgrades // Gooks From fffb2623225786644ac654a6f2fa0b3fdc5cb7d9 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 17:18:06 +1000 Subject: [PATCH 06/14] share all my series data --- Erupe/server/channelserver/handlers_data.go | 11 ++- Erupe/server/channelserver/handlers_house.go | 85 +++++++++++--------- Erupe/server/channelserver/sys_session.go | 15 ++-- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/Erupe/server/channelserver/handlers_data.go b/Erupe/server/channelserver/handlers_data.go index 88f634ba3..cc5c66889 100644 --- a/Erupe/server/channelserver/handlers_data.go +++ b/Erupe/server/channelserver/handlers_data.go @@ -1,15 +1,15 @@ package channelserver import ( - "encoding/hex" "encoding/binary" + "encoding/hex" "fmt" "io/ioutil" "os" "path/filepath" - "erupe-ce/common/byteframe" "erupe-ce/common/bfutil" + "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" "erupe-ce/server/channelserver/compression/deltacomp" "erupe-ce/server/channelserver/compression/nullcomp" @@ -61,7 +61,12 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) } - s.house.tier = decompressedData[129904] + s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5 + s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195 + // Gallery data also exists at 0x21578, is this the contest submission? + s.myseries.galleryData = decompressedData[140064:141812] // 0x22320 + 1748 + s.myseries.toreData = decompressedData[130228:130468] // 0x1FCB4 + 240 + s.myseries.gardenData = decompressedData[142424:142492] // 0x22C58 + 68 isMale := uint8(decompressedData[80]) // 0x50 if isMale == 1 { diff --git a/Erupe/server/channelserver/handlers_house.go b/Erupe/server/channelserver/handlers_house.go index 8aaeeb9fa..eeda39a5e 100644 --- a/Erupe/server/channelserver/handlers_house.go +++ b/Erupe/server/channelserver/handlers_house.go @@ -5,6 +5,7 @@ import ( ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" + "fmt" "go.uber.org/zap" ) @@ -89,8 +90,8 @@ func handleMsgMhfEnumerateHouse(s *Session, p mhfpacket.MHFPacket) { if session.charID == house.CharID { exists++ bf.WriteUint32(house.CharID) - bf.WriteUint8(session.house.state) - if len(session.house.password) > 0 { + bf.WriteUint8(session.myseries.state) + if len(session.myseries.password) > 0 { bf.WriteUint8(3) } else { bf.WriteUint8(0) @@ -115,8 +116,8 @@ func handleMsgMhfUpdateHouse(s *Session, p mhfpacket.MHFPacket) { // 03 = open friends // 04 = open guild // 05 = open friends+guild - s.house.state = pkt.State - s.house.password = pkt.Password + s.myseries.state = pkt.State + s.myseries.password = pkt.Password doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } @@ -125,7 +126,7 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() if pkt.Destination != 9 && len(pkt.Password) > 0 && pkt.CheckPass { for _, session := range s.server.sessions { - if session.charID == pkt.CharID && pkt.Password != session.house.password { + if session.charID == pkt.CharID && pkt.Password != session.myseries.password { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } @@ -141,55 +142,59 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { furniture = make([]byte, 20) } - // TODO: Find where the missing data comes from, savefile offset? switch pkt.Destination { case 3: // Others house - houseTier := uint8(2) // Fallback if can't find for _, session := range s.server.sessions { if session.charID == pkt.CharID { - houseTier = session.house.tier + bf.WriteBytes(session.myseries.houseTier) + bf.WriteBytes(session.myseries.houseData) + bf.WriteBytes(make([]byte, 19)) // Padding? + bf.WriteBytes(furniture) } } - bf.WriteBytes(make([]byte, 4)) - bf.WriteUint8(houseTier) // House tier 0x1FB70 - bf.WriteBytes(make([]byte, 80)) - // Item box style bitfield - // tier 1 = 0x09FE - // tier 2 = 0x69FF - // tier 3 = 0xE9FF - // unused = 0x0001 - // unused = 0x6000 - switch houseTier { - case 0: - bf.WriteUint16(0x0000) - case 1: - bf.WriteUint16(0x69FF) - case 2: - bf.WriteUint16(0xE9FF) - } - // Rastae - // Partner - bf.WriteBytes(make([]byte, 132)) - bf.WriteBytes(furniture) case 4: // Bookshelf - // Hunting log + // TODO: Find where the hunting log data offset is in the savefile bf.WriteBytes(make([]byte, 5576)) case 5: // Gallery - // Furniture placement - bf.WriteBytes(make([]byte, 1748)) + for _, session := range s.server.sessions { + if session.charID == pkt.CharID { + bf.WriteBytes(session.myseries.galleryData) + } + } case 8: // Tore - // Sister - // Cat shops - // Pugis - bf.WriteBytes(make([]byte, 240)) + for _, session := range s.server.sessions { + if session.charID == pkt.CharID { + bf.WriteBytes(session.myseries.toreData) + } + } case 9: // Own house bf.WriteBytes(furniture) case 10: // Garden - // Gardening upgrades - // Gooks - bf.WriteBytes(make([]byte, 72)) + for _, session := range s.server.sessions { + if session.charID == pkt.CharID { + bf.WriteBytes(session.myseries.gardenData) + // TODO: Convert EnumerateGuacot to function this can also call + var data []byte + var count uint16 + gooks := byteframe.NewByteFrame() + for i := 0; i < 5; i++ { + err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), pkt.CharID).Scan(&data) + if err == nil && data != nil { + count++ + gooks.WriteBytes(data) + } + } + bf.WriteUint16(count) + bf.WriteUint16(0) + bf.WriteBytes(gooks.Data()) + } + } + } + if len(bf.Data()) == 0 { + doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) + } else { + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfGetMyhouseInfo(s *Session, p mhfpacket.MHFPacket) { diff --git a/Erupe/server/channelserver/sys_session.go b/Erupe/server/channelserver/sys_session.go index d4de598a5..d3c7aa676 100644 --- a/Erupe/server/channelserver/sys_session.go +++ b/Erupe/server/channelserver/sys_session.go @@ -27,7 +27,7 @@ type Session struct { sendPackets chan []byte clientContext *clientctx.ClientContext - house House + myseries MySeries stageID string stage *Stage reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. @@ -55,10 +55,15 @@ type Session struct { Name string } -type House struct { - tier uint8 - state uint8 - password string +type MySeries struct { + houseTier []byte + houseData []byte + bookshelfData []byte + galleryData []byte + toreData []byte + gardenData []byte + state uint8 + password string } // NewSession creates a new Session type. From 9d4d820f8647cb6722b05f45f40412ab4d27a8ab Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 19:39:20 +1000 Subject: [PATCH 07/14] revise gook enumeration --- Erupe/gook.sql | 2 ++ .../mhfpacket/msg_mhf_update_guacot.go | 18 ++++------ Erupe/server/channelserver/handlers.go | 36 +++++++++---------- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/Erupe/gook.sql b/Erupe/gook.sql index af70efd86..d9b2f1f05 100644 --- a/Erupe/gook.sql +++ b/Erupe/gook.sql @@ -21,4 +21,6 @@ ALTER TABLE IF EXISTS public.gook ALTER TABLE IF EXISTS public.gook DROP COLUMN IF EXISTS gook5; +UPDATE public.gook SET gook1=NULL, gook2=NULL, gook3=NULL, gook4=NULL; + END; \ No newline at end of file diff --git a/Erupe/network/mhfpacket/msg_mhf_update_guacot.go b/Erupe/network/mhfpacket/msg_mhf_update_guacot.go index c5a73944e..99aa215e2 100644 --- a/Erupe/network/mhfpacket/msg_mhf_update_guacot.go +++ b/Erupe/network/mhfpacket/msg_mhf_update_guacot.go @@ -9,14 +9,12 @@ import ( ) type Gook struct { - Exists bool - Index uint32 - Type uint16 - Data []byte - Birthday1 uint32 - Birthday2 uint32 - NameLen uint8 - Name []byte + Exists bool + Index uint32 + Type uint16 + Data []byte + NameLen uint8 + Name []byte } // MsgMhfUpdateGuacot represents the MSG_MHF_UPDATE_GUACOT @@ -41,9 +39,7 @@ func (m *MsgMhfUpdateGuacot) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clien e := Gook{} e.Index = bf.ReadUint32() e.Type = bf.ReadUint16() - e.Data = bf.ReadBytes(42) - e.Birthday1 = bf.ReadUint32() - e.Birthday2 = bf.ReadUint32() + e.Data = bf.ReadBytes(50) e.NameLen = bf.ReadUint8() e.Name = bf.ReadBytes(uint(e.NameLen)) if e.Type > 0 { diff --git a/Erupe/server/channelserver/handlers.go b/Erupe/server/channelserver/handlers.go index 4381d8ca2..3adab427f 100644 --- a/Erupe/server/channelserver/handlers.go +++ b/Erupe/server/channelserver/handlers.go @@ -577,22 +577,35 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { - pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot) +func getGookData(s *Session, cid uint32) []byte { var data []byte var count uint16 bf := byteframe.NewByteFrame() for i := 0; i < 5; i++ { - err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), s.charID).Scan(&data) + err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), cid).Scan(&data) if err == nil && data != nil { count++ - bf.WriteBytes(data) + if s.charID == cid && count == 1 { + gook := byteframe.NewByteFrameFromBytes(data) + bf.WriteBytes(gook.ReadBytes(4)) + d := gook.ReadBytes(2) + bf.WriteBytes(d) + bf.WriteBytes(d) + bf.WriteBytes(gook.DataFromCurrent()) + } else { + bf.WriteBytes(data) + } } } resp := byteframe.NewByteFrame() resp.WriteUint16(count) resp.WriteBytes(bf.Data()) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + return resp.Data() +} + +func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot) + doAckBufSucceed(s, pkt.AckHandle, getGookData(s, s.charID)) } func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { @@ -601,23 +614,10 @@ func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { if !gook.Exists { s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=NULL WHERE id=$1", gook.Index), s.charID) } else { - // TODO: Birthdays are still 7 years in the past - //var data []byte - //err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", gook.Index), s.charID).Scan(&data) - //if err != nil && data == nil { // If index doesn't exist - // // Give gook a birthday not 7 years ago - // gook.Birthday1 = uint32(time.Now().Unix()) - // gook.Birthday2 = uint32(time.Now().Unix()) - //} bf := byteframe.NewByteFrame() bf.WriteUint32(gook.Index) - if gook.Index == 0 { - bf.WriteUint16(gook.Type) - } bf.WriteUint16(gook.Type) bf.WriteBytes(gook.Data) - bf.WriteUint32(gook.Birthday1) - bf.WriteUint32(gook.Birthday2) bf.WriteUint8(gook.NameLen) bf.WriteBytes(gook.Name) s.server.db.Exec(fmt.Sprintf("UPDATE gook SET gook%d=$1 WHERE id=$2", gook.Index), bf.Data(), s.charID) From 15440fcac643b0acda278272ec62491912e84d71 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 19:55:40 +1000 Subject: [PATCH 08/14] merge gook simplification --- Erupe/server/channelserver/handlers.go | 13 +++++++------ Erupe/server/channelserver/handlers_house.go | 17 +++-------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/Erupe/server/channelserver/handlers.go b/Erupe/server/channelserver/handlers.go index 3adab427f..6dd69381b 100644 --- a/Erupe/server/channelserver/handlers.go +++ b/Erupe/server/channelserver/handlers.go @@ -577,7 +577,7 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {} -func getGookData(s *Session, cid uint32) []byte { +func getGookData(s *Session, cid uint32) (uint16, []byte) { var data []byte var count uint16 bf := byteframe.NewByteFrame() @@ -597,15 +597,16 @@ func getGookData(s *Session, cid uint32) []byte { } } } - resp := byteframe.NewByteFrame() - resp.WriteUint16(count) - resp.WriteBytes(bf.Data()) - return resp.Data() + return count, bf.Data() } func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfEnumerateGuacot) - doAckBufSucceed(s, pkt.AckHandle, getGookData(s, s.charID)) + bf := byteframe.NewByteFrame() + count, data := getGookData(s, s.charID) + bf.WriteUint16(count) + bf.WriteBytes(data) + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) { diff --git a/Erupe/server/channelserver/handlers_house.go b/Erupe/server/channelserver/handlers_house.go index eeda39a5e..3408d356f 100644 --- a/Erupe/server/channelserver/handlers_house.go +++ b/Erupe/server/channelserver/handlers_house.go @@ -5,7 +5,6 @@ import ( ps "erupe-ce/common/pascalstring" "erupe-ce/common/stringsupport" "erupe-ce/network/mhfpacket" - "fmt" "go.uber.org/zap" ) @@ -173,20 +172,10 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { for _, session := range s.server.sessions { if session.charID == pkt.CharID { bf.WriteBytes(session.myseries.gardenData) - // TODO: Convert EnumerateGuacot to function this can also call - var data []byte - var count uint16 - gooks := byteframe.NewByteFrame() - for i := 0; i < 5; i++ { - err := s.server.db.QueryRow(fmt.Sprintf("SELECT gook%d FROM gook WHERE id=$1", i), pkt.CharID).Scan(&data) - if err == nil && data != nil { - count++ - gooks.WriteBytes(data) - } - } - bf.WriteUint16(count) + c, d := getGookData(s, pkt.CharID) + bf.WriteUint16(c) bf.WriteUint16(0) - bf.WriteBytes(gooks.Data()) + bf.WriteBytes(d) } } } From 101e2b4399c70b34cc5fdd9189cabc0b95d5ab16 Mon Sep 17 00:00:00 2001 From: wish Date: Mon, 25 Jul 2022 21:31:27 +1000 Subject: [PATCH 09/14] include bookshelf data --- Erupe/server/channelserver/handlers_data.go | 5 +++-- Erupe/server/channelserver/handlers_house.go | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Erupe/server/channelserver/handlers_data.go b/Erupe/server/channelserver/handlers_data.go index cc5c66889..9d1bf0c6a 100644 --- a/Erupe/server/channelserver/handlers_data.go +++ b/Erupe/server/channelserver/handlers_data.go @@ -61,8 +61,9 @@ func handleMsgMhfSavedata(s *Session, p mhfpacket.MHFPacket) { s.logger.Fatal("Failed to character weapon type in db", zap.Error(err)) } - s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5 - s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195 + s.myseries.houseTier = decompressedData[129900:129905] // 0x1FB6C + 5 + s.myseries.houseData = decompressedData[130561:130756] // 0x1FE01 + 195 + s.myseries.bookshelfData = decompressedData[139928:145504] // 0x22298 + 5576 // Gallery data also exists at 0x21578, is this the contest submission? s.myseries.galleryData = decompressedData[140064:141812] // 0x22320 + 1748 s.myseries.toreData = decompressedData[130228:130468] // 0x1FCB4 + 240 diff --git a/Erupe/server/channelserver/handlers_house.go b/Erupe/server/channelserver/handlers_house.go index 3408d356f..9af91074e 100644 --- a/Erupe/server/channelserver/handlers_house.go +++ b/Erupe/server/channelserver/handlers_house.go @@ -152,8 +152,11 @@ func handleMsgMhfLoadHouse(s *Session, p mhfpacket.MHFPacket) { } } case 4: // Bookshelf - // TODO: Find where the hunting log data offset is in the savefile - bf.WriteBytes(make([]byte, 5576)) + for _, session := range s.server.sessions { + if session.charID == pkt.CharID { + bf.WriteBytes(session.myseries.bookshelfData) + } + } case 5: // Gallery for _, session := range s.server.sessions { if session.charID == pkt.CharID { From ff5d32ef7f1751ff9f7858ddf2b8cf791138980d Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 26 Jul 2022 04:14:19 +1000 Subject: [PATCH 10/14] implement semaphore indexes --- .../mhfpacket/msg_sys_operate_register.go | 6 +- .../server/channelserver/handlers_register.go | 398 +++++++++--------- .../channelserver/handlers_semaphore.go | 141 +++---- Erupe/server/channelserver/handlers_stage.go | 5 +- .../channelserver/sys_channel_server.go | 56 ++- Erupe/server/channelserver/sys_semaphore.go | 12 +- 6 files changed, 305 insertions(+), 313 deletions(-) diff --git a/Erupe/network/mhfpacket/msg_sys_operate_register.go b/Erupe/network/mhfpacket/msg_sys_operate_register.go index 62e551d78..e4213d45d 100644 --- a/Erupe/network/mhfpacket/msg_sys_operate_register.go +++ b/Erupe/network/mhfpacket/msg_sys_operate_register.go @@ -11,7 +11,7 @@ import ( // MsgSysOperateRegister represents the MSG_SYS_OPERATE_REGISTER type MsgSysOperateRegister struct { AckHandle uint32 - RegisterID uint32 + SemaphoreID uint32 fixedZero uint16 RawDataPayload []byte } @@ -24,7 +24,7 @@ func (m *MsgSysOperateRegister) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.RegisterID = bf.ReadUint32() + m.SemaphoreID = bf.ReadUint32() m.fixedZero = bf.ReadUint16() if m.fixedZero != 0 { @@ -39,7 +39,7 @@ func (m *MsgSysOperateRegister) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl // Build builds a binary packet from the current data. func (m *MsgSysOperateRegister) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { bf.WriteUint32(m.AckHandle) - bf.WriteUint32(m.RegisterID) + bf.WriteUint32(m.SemaphoreID) bf.WriteUint16(0) bf.WriteUint16(uint16(len(m.RawDataPayload))) bf.WriteBytes(m.RawDataPayload) diff --git a/Erupe/server/channelserver/handlers_register.go b/Erupe/server/channelserver/handlers_register.go index 7d8293cbe..4da6e9a8c 100644 --- a/Erupe/server/channelserver/handlers_register.go +++ b/Erupe/server/channelserver/handlers_register.go @@ -1,7 +1,6 @@ package channelserver import ( - "encoding/hex" "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" ) @@ -10,129 +9,7 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysOperateRegister) bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload) s.server.raviente.Lock() - switch pkt.RegisterID { - case 786461: - resp := byteframe.NewByteFrame() - size := 6 - for i := 0; i < len(bf.Data())-1; i += size { - op := bf.ReadUint8() - dest := bf.ReadUint8() - data := bf.ReadUint32() - resp.WriteUint8(1) - resp.WriteUint8(dest) - switch dest { - case 0: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.nextTime = data - case 1: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.startTime = data - case 2: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.killedTime = data - case 3: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.postTime = data - case 4: - ref := &s.server.raviente.register.register[0] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + uint32(data)) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 5: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.carveQuest = data - case 6: - ref := &s.server.raviente.register.register[1] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + uint32(data)) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 7: - ref := &s.server.raviente.register.register[2] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + uint32(data)) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 8: - ref := &s.server.raviente.register.register[3] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + uint32(data)) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - case 9: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.maxPlayers = data - case 10: - resp.WriteUint32(0) - resp.WriteUint32(data) - s.server.raviente.register.ravienteType = data - case 11: - ref := &s.server.raviente.register.register[4] - switch op { - case 2: - resp.WriteUint32(*ref) - resp.WriteUint32(*ref + uint32(data)) - *ref += data - case 13: - resp.WriteUint32(0) - resp.WriteUint32(data) - *ref = data - case 14: - resp.WriteUint32(0) - resp.WriteUint32(data) - } - default: - resp.WriteUint32(0) - resp.WriteUint32(0) - } - } - resp.WriteUint8(0) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - - case 917533: + if pkt.SemaphoreID == s.server.raviente.state.semaphoreID { resp := byteframe.NewByteFrame() size := 6 for i := 0; i < len(bf.Data())-1; i += size { @@ -152,12 +29,12 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { } else if dest == 17 { // Berserk poison tracker if damageMultiplier == 1 { resp.WriteUint32(*ref + data) + *ref += data } else { resp.WriteUint32(*ref + data) - *ref += data } } else { - resp.WriteUint32(*ref + data * damageMultiplier) + resp.WriteUint32(*ref + data*damageMultiplier) *ref += data * damageMultiplier } case 13: @@ -170,8 +47,7 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { } resp.WriteUint8(0) doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - - case 851997: + } else if pkt.SemaphoreID == s.server.raviente.support.semaphoreID { resp := byteframe.NewByteFrame() size := 6 for i := 0; i < len(bf.Data())-1; i += size { @@ -196,6 +72,126 @@ func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) { } resp.WriteUint8(0) doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + } else if pkt.SemaphoreID == s.server.raviente.register.semaphoreID { + resp := byteframe.NewByteFrame() + size := 6 + for i := 0; i < len(bf.Data())-1; i += size { + op := bf.ReadUint8() + dest := bf.ReadUint8() + data := bf.ReadUint32() + resp.WriteUint8(1) + resp.WriteUint8(dest) + switch dest { + case 0: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.nextTime = data + case 1: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.startTime = data + case 2: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.killedTime = data + case 3: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.postTime = data + case 4: + ref := &s.server.raviente.register.register[0] + switch op { + case 2: + resp.WriteUint32(*ref) + resp.WriteUint32(*ref + uint32(data)) + *ref += data + case 13: + resp.WriteUint32(0) + resp.WriteUint32(data) + *ref = data + case 14: + resp.WriteUint32(0) + resp.WriteUint32(data) + } + case 5: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.carveQuest = data + case 6: + ref := &s.server.raviente.register.register[1] + switch op { + case 2: + resp.WriteUint32(*ref) + resp.WriteUint32(*ref + uint32(data)) + *ref += data + case 13: + resp.WriteUint32(0) + resp.WriteUint32(data) + *ref = data + case 14: + resp.WriteUint32(0) + resp.WriteUint32(data) + } + case 7: + ref := &s.server.raviente.register.register[2] + switch op { + case 2: + resp.WriteUint32(*ref) + resp.WriteUint32(*ref + uint32(data)) + *ref += data + case 13: + resp.WriteUint32(0) + resp.WriteUint32(data) + *ref = data + case 14: + resp.WriteUint32(0) + resp.WriteUint32(data) + } + case 8: + ref := &s.server.raviente.register.register[3] + switch op { + case 2: + resp.WriteUint32(*ref) + resp.WriteUint32(*ref + uint32(data)) + *ref += data + case 13: + resp.WriteUint32(0) + resp.WriteUint32(data) + *ref = data + case 14: + resp.WriteUint32(0) + resp.WriteUint32(data) + } + case 9: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.maxPlayers = data + case 10: + resp.WriteUint32(0) + resp.WriteUint32(data) + s.server.raviente.register.ravienteType = data + case 11: + ref := &s.server.raviente.register.register[4] + switch op { + case 2: + resp.WriteUint32(*ref) + resp.WriteUint32(*ref + uint32(data)) + *ref += data + case 13: + resp.WriteUint32(0) + resp.WriteUint32(data) + *ref = data + case 14: + resp.WriteUint32(0) + resp.WriteUint32(data) + } + default: + resp.WriteUint32(0) + resp.WriteUint32(0) + } + } + resp.WriteUint8(0) + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } s.notifyall() s.server.raviente.Unlock() @@ -205,74 +201,66 @@ func handleMsgSysLoadRegister(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysLoadRegister) r := pkt.Unk1 switch r { - case 12: - if pkt.RegisterID == 983077 { - data, _ := hex.DecodeString("000C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - doAckBufFail(s, pkt.AckHandle, data) - } else if pkt.RegisterID == 983069 { - data, _ := hex.DecodeString("000C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") - doAckBufFail(s, pkt.AckHandle, data) - } - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(12) - resp.WriteUint32(s.server.raviente.register.nextTime) - resp.WriteUint32(s.server.raviente.register.startTime) - resp.WriteUint32(s.server.raviente.register.killedTime) - resp.WriteUint32(s.server.raviente.register.postTime) - resp.WriteUint32(s.server.raviente.register.register[0]) - resp.WriteUint32(s.server.raviente.register.carveQuest) - resp.WriteUint32(s.server.raviente.register.register[1]) - resp.WriteUint32(s.server.raviente.register.register[2]) - resp.WriteUint32(s.server.raviente.register.register[3]) - resp.WriteUint32(s.server.raviente.register.maxPlayers) - resp.WriteUint32(s.server.raviente.register.ravienteType) - resp.WriteUint32(s.server.raviente.register.register[4]) - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 29: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(29) - for _, v := range s.server.raviente.state.stateData { - resp.WriteUint32(v) - } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) - case 25: - resp := byteframe.NewByteFrame() - resp.WriteUint8(0) - resp.WriteUint8(25) - for _, v := range s.server.raviente.support.supportData { - resp.WriteUint32(v) - } - doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + case 12: + resp := byteframe.NewByteFrame() + resp.WriteUint8(0) + resp.WriteUint8(12) + resp.WriteUint32(s.server.raviente.register.nextTime) + resp.WriteUint32(s.server.raviente.register.startTime) + resp.WriteUint32(s.server.raviente.register.killedTime) + resp.WriteUint32(s.server.raviente.register.postTime) + resp.WriteUint32(s.server.raviente.register.register[0]) + resp.WriteUint32(s.server.raviente.register.carveQuest) + resp.WriteUint32(s.server.raviente.register.register[1]) + resp.WriteUint32(s.server.raviente.register.register[2]) + resp.WriteUint32(s.server.raviente.register.register[3]) + resp.WriteUint32(s.server.raviente.register.maxPlayers) + resp.WriteUint32(s.server.raviente.register.ravienteType) + resp.WriteUint32(s.server.raviente.register.register[4]) + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + case 29: + resp := byteframe.NewByteFrame() + resp.WriteUint8(0) + resp.WriteUint8(29) + for _, v := range s.server.raviente.state.stateData { + resp.WriteUint32(v) + } + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + case 25: + resp := byteframe.NewByteFrame() + resp.WriteUint8(0) + resp.WriteUint8(25) + for _, v := range s.server.raviente.support.supportData { + resp.WriteUint32(v) + } + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) } } -// Unused -func (s *Session) notifyplayer() { - s.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D}) - s.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D}) - s.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) -} - func (s *Session) notifyall() { + var temp mhfpacket.MHFPacket + raviNotif := byteframe.NewByteFrame() + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: s.server.raviente.support.semaphoreID} + raviNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(raviNotif, s.clientContext) + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: s.server.raviente.state.semaphoreID} + raviNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(raviNotif, s.clientContext) + temp = &mhfpacket.MsgSysNotifyRegister{RegisterID: s.server.raviente.register.semaphoreID} + raviNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(raviNotif, s.clientContext) + raviNotif.WriteUint16(0x0010) // End it. if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists { for session := range s.server.semaphore["hs_l0u3B51J9k3"].clients { - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D}) - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D}) + session.QueueSend(raviNotif.Data()) } } else if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists { for session := range s.server.semaphore["hs_l0u3B5129k3"].clients { - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D}) - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D}) + session.QueueSend(raviNotif.Data()) } } else if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists { for session := range s.server.semaphore["hs_l0u3B512Ak3"].clients { - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0C, 0x00, 0x1D}) - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0D, 0x00, 0x1D}) - session.QueueSendNonBlocking([]byte{0x00, 0x3F, 0x00, 0x0E, 0x00, 0x1D}) + session.QueueSend(raviNotif.Data()) } } } @@ -288,27 +276,28 @@ func checkRaviSemaphore(s *Session) bool { return false } -func releaseRaviSemaphore(s *Session) { - s.server.raviente.Lock() - if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists { - if len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots) == 0 { - resetRavi(s) - } - } - if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists { - if len(s.server.semaphore["hs_l0u3B5129k3"].reservedClientSlots) == 0 { - resetRavi(s) - } - } - if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists { - if len(s.server.semaphore["hs_l0u3B512Ak3"].reservedClientSlots) == 0 { - resetRavi(s) - } - } - s.server.raviente.Unlock() -} +//func releaseRaviSemaphore(s *Session) { +// s.server.raviente.Lock() +// if _, exists := s.server.semaphore["hs_l0u3B51J9k3"]; exists { +// if len(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots) == 0 { +// resetRavi(s) +// } +// } +// if _, exists := s.server.semaphore["hs_l0u3B5129k3"]; exists { +// if len(s.server.semaphore["hs_l0u3B5129k3"].reservedClientSlots) == 0 { +// resetRavi(s) +// } +// } +// if _, exists := s.server.semaphore["hs_l0u3B512Ak3"]; exists { +// if len(s.server.semaphore["hs_l0u3B512Ak3"].reservedClientSlots) == 0 { +// resetRavi(s) +// } +// } +// s.server.raviente.Unlock() +//} func resetRavi(s *Session) { + s.server.raviente.Lock() s.server.raviente.register.nextTime = 0 s.server.raviente.register.startTime = 0 s.server.raviente.register.killedTime = 0 @@ -320,6 +309,7 @@ func resetRavi(s *Session) { s.server.raviente.register.register = []uint32{0, 0, 0, 0, 0} s.server.raviente.state.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} s.server.raviente.support.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + s.server.raviente.Unlock() } // Unused @@ -334,4 +324,4 @@ func (s *Session) notifyticker() { } } -func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} \ No newline at end of file +func handleMsgSysNotifyRegister(s *Session, p mhfpacket.MHFPacket) {} diff --git a/Erupe/server/channelserver/handlers_semaphore.go b/Erupe/server/channelserver/handlers_semaphore.go index 117e46d4f..630105ea3 100644 --- a/Erupe/server/channelserver/handlers_semaphore.go +++ b/Erupe/server/channelserver/handlers_semaphore.go @@ -1,7 +1,9 @@ package channelserver import ( + "erupe-ce/common/byteframe" "fmt" + "go.uber.org/zap" "strings" "erupe-ce/network/mhfpacket" @@ -10,11 +12,13 @@ import ( func removeSessionFromSemaphore(s *Session) { s.server.semaphoreLock.Lock() for _, semaphore := range s.server.semaphore { + if _, exists := semaphore.reservedClientSlots[s.charID]; exists { + delete(semaphore.reservedClientSlots, s.charID) + } if _, exists := semaphore.clients[s]; exists { delete(semaphore.clients, s) } } - releaseRaviSemaphore(s) s.server.semaphoreLock.Unlock() } @@ -23,54 +27,50 @@ func handleMsgSysCreateSemaphore(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x03, 0x00, 0x0d}) } +func destructEmptySemaphores(s *Session) { + s.server.semaphoreLock.Lock() + for id, sema := range s.server.semaphore { + if len(sema.reservedClientSlots) == 0 && len(sema.clients) == 0 { + s.server.semaphoreLock.Unlock() + delete(s.server.semaphore, id) + s.server.semaphoreLock.Lock() + if strings.HasPrefix(id, "hs_l0u3B51") { + releaseRaviSemaphore(s, sema) + } + s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) + } + } + s.server.semaphoreLock.Unlock() +} + +func releaseRaviSemaphore(s *Session, sema *Semaphore) { + if !strings.HasSuffix(sema.id_semaphore, "5") { + delete(sema.reservedClientSlots, s.charID) + delete(sema.clients, s) + } + if len(sema.reservedClientSlots) == 0 && len(sema.clients) == 0 { + s.logger.Debug("Raviente semaphore is empty, resetting") + resetRavi(s) + } +} + func handleMsgSysDeleteSemaphore(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysDeleteSemaphore) sem := pkt.AckHandle if s.server.semaphore != nil { + destructEmptySemaphores(s) s.server.semaphoreLock.Lock() - for id := range s.server.semaphore { - switch sem { - case 917533: - if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k3" { - delete(s.server.semaphore["hs_l0u3B51J9k3"].reservedClientSlots, s.charID) - delete(s.server.semaphore["hs_l0u3B51J9k3"].clients, s) - } else if s.server.semaphore[id].id_semaphore == "hs_l0u3B5129k3" { - delete(s.server.semaphore["hs_l0u3B5129k3"].reservedClientSlots, s.charID) - delete(s.server.semaphore["hs_l0u3B5129k3"].clients, s) - } else if s.server.semaphore[id].id_semaphore == "hs_l0u3B512Ak3" { - delete(s.server.semaphore["hs_l0u3B512Ak3"].reservedClientSlots, s.charID) - delete(s.server.semaphore["hs_l0u3B512Ak3"].clients, s) - } - case 851997: - if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k4" { - delete(s.server.semaphore["hs_l0u3B51J9k4"].reservedClientSlots, s.charID) - } else if s.server.semaphore[id].id_semaphore == "hs_l0u3B5129k4" { - delete(s.server.semaphore["hs_l0u3B5129k4"].reservedClientSlots, s.charID) - } else if s.server.semaphore[id].id_semaphore == "hs_l0u3B512Ak4" { - delete(s.server.semaphore["hs_l0u3B512Ak4"].reservedClientSlots, s.charID) - } - case 786461: - if s.server.semaphore[id].id_semaphore == "hs_l0u3B51J9k5" { - delete(s.server.semaphore["hs_l0u3B51J9k5"].reservedClientSlots, s.charID) - } else if s.server.semaphore[id].id_semaphore == "hs_l0u3B5129k5" { - delete(s.server.semaphore["hs_l0u3B5129k5"].reservedClientSlots, s.charID) - } else if s.server.semaphore[id].id_semaphore == "hs_l0u3B512Ak5" { - delete(s.server.semaphore["hs_l0u3B512Ak5"].reservedClientSlots, s.charID) - } - default: - if len(s.server.semaphore[id].reservedClientSlots) != 0 { - if s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k3" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k4" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B51J9k5" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B5129k3" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B5129k4" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B5129k5" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B512Ak3" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B512Ak4" && - s.server.semaphore[id].id_semaphore != "hs_l0u3B512Ak5" { - delete(s.server.semaphore[id].reservedClientSlots, s.charID) - } + for id, sema := range s.server.semaphore { + if sema.id == sem { + if strings.HasPrefix(id, "hs_l0u3B51") { + releaseRaviSemaphore(s, sema) + s.server.semaphoreLock.Unlock() + return } + s.server.semaphoreLock.Unlock() + delete(s.server.semaphore, id) + s.logger.Debug("Destructed semaphore", zap.String("sema.id_semaphore", id)) + return } } s.server.semaphoreLock.Unlock() @@ -81,15 +81,22 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysCreateAcquireSemaphore) SemaphoreID := pkt.SemaphoreID - newSemaphore, gotNewStage := s.server.semaphore[SemaphoreID] + newSemaphore, exists := s.server.semaphore[SemaphoreID] fmt.Printf("Got reserve stage req, StageID: %v\n\n", SemaphoreID) - if !gotNewStage { + if !exists { s.server.semaphoreLock.Lock() if strings.HasPrefix(SemaphoreID, "hs_l0u3B51") { - s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 32) + s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 32) + if strings.HasSuffix(SemaphoreID, "3") { + s.server.raviente.state.semaphoreID = s.server.semaphore[SemaphoreID].id + } else if strings.HasSuffix(SemaphoreID, "4") { + s.server.raviente.support.semaphoreID = s.server.semaphore[SemaphoreID].id + } else if strings.HasSuffix(SemaphoreID, "5") { + s.server.raviente.register.semaphoreID = s.server.semaphore[SemaphoreID].id + } } else { - s.server.semaphore[SemaphoreID] = NewSemaphore(SemaphoreID, 1) + s.server.semaphore[SemaphoreID] = NewSemaphore(s.server, SemaphoreID, 1) } newSemaphore = s.server.semaphore[SemaphoreID] s.server.semaphoreLock.Unlock() @@ -98,35 +105,18 @@ func handleMsgSysCreateAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { newSemaphore.Lock() defer newSemaphore.Unlock() if _, exists := newSemaphore.reservedClientSlots[s.charID]; exists { - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x1D}) + bf := byteframe.NewByteFrame() + bf.WriteUint32(newSemaphore.id) + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } else if uint16(len(newSemaphore.reservedClientSlots)) < newSemaphore.maxPlayers { - switch SemaphoreID { - case "hs_l0u3B51J9k3", "hs_l0u3B5129k3", "hs_l0u3B512Ak3": - newSemaphore.reservedClientSlots[s.charID] = nil - newSemaphore.clients[s] = s.charID - s.Lock() - s.semaphore = newSemaphore - s.Unlock() - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0E, 0x00, 0x1D}) - case "hs_l0u3B51J9k4", "hs_l0u3B5129k4", "hs_l0u3B512Ak4": - newSemaphore.reservedClientSlots[s.charID] = nil - s.Lock() - s.semaphore = newSemaphore - s.Unlock() - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0D, 0x00, 0x1D}) - case "hs_l0u3B51J9k5", "hs_l0u3B5129k5", "hs_l0u3B512Ak5": - newSemaphore.reservedClientSlots[s.charID] = nil - s.Lock() - s.semaphore = newSemaphore - s.Unlock() - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0C, 0x00, 0x1D}) - default: - newSemaphore.reservedClientSlots[s.charID] = nil - s.Lock() - s.semaphore = newSemaphore - s.Unlock() - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x0F, 0x00, 0x25}) - } + newSemaphore.reservedClientSlots[s.charID] = nil + newSemaphore.clients[s] = s.charID + s.Lock() + s.semaphore = newSemaphore + s.Unlock() + bf := byteframe.NewByteFrame() + bf.WriteUint32(newSemaphore.id) + doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) } else { doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) } @@ -138,7 +128,6 @@ func handleMsgSysAcquireSemaphore(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysReleaseSemaphore(s *Session, p mhfpacket.MHFPacket) { //pkt := p.(*mhfpacket.MsgSysReleaseSemaphore) - releaseRaviSemaphore(s) } func handleMsgSysCheckSemaphore(s *Session, p mhfpacket.MHFPacket) { diff --git a/Erupe/server/channelserver/handlers_stage.go b/Erupe/server/channelserver/handlers_stage.go index d7891ba7b..8f03dd4dd 100644 --- a/Erupe/server/channelserver/handlers_stage.go +++ b/Erupe/server/channelserver/handlers_stage.go @@ -86,7 +86,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { } } -func removeEmptyStages(s *Session) { +func destructEmptyStages(s *Session) { s.server.Lock() defer s.server.Unlock() for _, stage := range s.server.stages { @@ -134,7 +134,8 @@ func removeSessionFromStage(s *Session) { } } s.stage.Unlock() - removeEmptyStages(s) + destructEmptyStages(s) + destructEmptySemaphores(s) } func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { diff --git a/Erupe/server/channelserver/sys_channel_server.go b/Erupe/server/channelserver/sys_channel_server.go index 89bfa2584..6d6933062 100644 --- a/Erupe/server/channelserver/sys_channel_server.go +++ b/Erupe/server/channelserver/sys_channel_server.go @@ -71,8 +71,9 @@ type Server struct { userBinaryParts map[userBinaryPartID][]byte // Semaphore - semaphoreLock sync.RWMutex - semaphore map[string]*Semaphore + semaphoreLock sync.RWMutex + semaphore map[string]*Semaphore + semaphoreIndex uint32 // Discord chat integration discordBot *discordbot.DiscordBot @@ -92,55 +93,58 @@ type Raviente struct { } type RavienteRegister struct { - nextTime uint32 - startTime uint32 - postTime uint32 - killedTime uint32 + semaphoreID uint32 + nextTime uint32 + startTime uint32 + postTime uint32 + killedTime uint32 ravienteType uint32 - maxPlayers uint32 - carveQuest uint32 - register []uint32 + maxPlayers uint32 + carveQuest uint32 + register []uint32 } type RavienteState struct { + semaphoreID uint32 damageMultiplier uint32 - stateData []uint32 + stateData []uint32 } type RavienteSupport struct { + semaphoreID uint32 supportData []uint32 } // Set up the Raviente variables for the server func NewRaviente() *Raviente { - ravienteRegister := &RavienteRegister { - nextTime: 0, - startTime: 0, - killedTime: 0, - postTime: 0, + ravienteRegister := &RavienteRegister{ + nextTime: 0, + startTime: 0, + killedTime: 0, + postTime: 0, ravienteType: 0, - maxPlayers: 0, - carveQuest: 0, + maxPlayers: 0, + carveQuest: 0, } - ravienteState := &RavienteState { + ravienteState := &RavienteState{ damageMultiplier: 1, } - ravienteSupport := &RavienteSupport { } + ravienteSupport := &RavienteSupport{} ravienteRegister.register = []uint32{0, 0, 0, 0, 0} ravienteState.stateData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ravienteSupport.supportData = []uint32{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - raviente := &Raviente { + raviente := &Raviente{ register: ravienteRegister, - state: ravienteState, - support: ravienteSupport, + state: ravienteState, + support: ravienteSupport, } return raviente } // NewServer creates a new Server type. func NewServer(config *Config) *Server { - s := &Server { + s := &Server{ ID: config.ID, logger: config.Logger, db: config.DB, @@ -151,6 +155,7 @@ func NewServer(config *Config) *Server { stages: make(map[string]*Stage), userBinaryParts: make(map[userBinaryPartID][]byte), semaphore: make(map[string]*Semaphore), + semaphoreIndex: 0, discordBot: config.DiscordBot, name: config.Name, enable: config.Enable, @@ -401,3 +406,8 @@ func (s *Server) FindStageObjectByChar(charID uint32) *StageObject { return nil } + +func (s *Server) NextSemaphoreID() uint32 { + s.semaphoreIndex = s.semaphoreIndex + 1 + return s.semaphoreIndex +} diff --git a/Erupe/server/channelserver/sys_semaphore.go b/Erupe/server/channelserver/sys_semaphore.go index c923d4247..369e481b6 100644 --- a/Erupe/server/channelserver/sys_semaphore.go +++ b/Erupe/server/channelserver/sys_semaphore.go @@ -14,6 +14,8 @@ type Semaphore struct { // Stage ID string id_semaphore string + id uint32 + // Map of session -> charID. // These are clients that are CURRENTLY in the stage clients map[*Session]uint32 @@ -26,21 +28,21 @@ type Semaphore struct { } // NewStage creates a new stage with intialized values. -func NewSemaphore(ID string, MaxPlayers uint16) *Semaphore { - s := &Semaphore{ +func NewSemaphore(s *Server, ID string, MaxPlayers uint16) *Semaphore { + sema := &Semaphore{ id_semaphore: ID, + id: s.NextSemaphoreID(), clients: make(map[*Session]uint32), reservedClientSlots: make(map[uint32]interface{}), maxPlayers: MaxPlayers, } - return s + return sema } func (s *Semaphore) BroadcastRavi(pkt mhfpacket.MHFPacket) { // Broadcast the data. for session := range s.clients { - // Make the header bf := byteframe.NewByteFrame() bf.WriteUint16(uint16(pkt.Opcode())) @@ -71,4 +73,4 @@ func (s *Semaphore) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Sessio // Enqueue in a non-blocking way that drops the packet if the connections send buffer channel is full. session.QueueSendNonBlocking(bf.Data()) } -} \ No newline at end of file +} From 88d1653cd34b6c9cbb15d9bb70bd96028f59fe4c Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 26 Jul 2022 17:50:52 +1000 Subject: [PATCH 11/14] test object indexing --- .../server/channelserver/handlers_discord.go | 2 +- Erupe/server/channelserver/handlers_object.go | 44 ++++++------- Erupe/server/channelserver/handlers_stage.go | 59 ++---------------- Erupe/server/channelserver/handlers_users.go | 47 +++++++++++++- .../channelserver/sys_channel_server.go | 12 ++-- Erupe/server/channelserver/sys_stage.go | 62 +++++-------------- 6 files changed, 89 insertions(+), 137 deletions(-) diff --git a/Erupe/server/channelserver/handlers_discord.go b/Erupe/server/channelserver/handlers_discord.go index 94c92c58f..38619e079 100644 --- a/Erupe/server/channelserver/handlers_discord.go +++ b/Erupe/server/channelserver/handlers_discord.go @@ -263,7 +263,7 @@ func getCharInfo(server *Server, charName string) string { objInfo := "" - obj := server.FindStageObjectByChar(c.charID) + obj := server.FindObjectByChar(c.charID) // server.logger.Info("Found object: %+v", zap.Object("obj", obj)) if obj != nil { diff --git a/Erupe/server/channelserver/handlers_object.go b/Erupe/server/channelserver/handlers_object.go index 548d891fe..0b24c0f66 100644 --- a/Erupe/server/channelserver/handlers_object.go +++ b/Erupe/server/channelserver/handlers_object.go @@ -10,44 +10,31 @@ import ( func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysCreateObject) - // Lock the stage. - s.server.Lock() - - // Make a new stage object and insert it into the stage. - objID := s.stage.GetNewObjectID(s.charID) - newObj := &StageObject{ - id: objID, + s.stage.Lock() + newObj := &Object{ + id: s.stage.NextObjectID(), ownerCharID: s.charID, x: pkt.X, y: pkt.Y, z: pkt.Z, } - s.stage.objects[s.charID] = newObj + s.stage.Unlock() - // Unlock the stage. - s.server.Unlock() // Response to our requesting client. resp := byteframe.NewByteFrame() - resp.WriteUint32(objID) // New local obj handle. + resp.WriteUint32(newObj.id) // New local obj handle. doAckSimpleSucceed(s, pkt.AckHandle, resp.Data()) // Duplicate the object creation to all sessions in the same stage. dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{ - ObjID: objID, - X: pkt.X, - Y: pkt.Y, - Z: pkt.Z, - OwnerCharID: s.charID, + ObjID: newObj.id, + X: newObj.x, + Y: newObj.y, + Z: newObj.z, + OwnerCharID: newObj.ownerCharID, } - for i := 1; i <= 3; i++ { - s.server.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ - CharID: s.charID, - BinaryType: uint8(i), - }, s) - } - - s.logger.Info("Duplicate a new characters to others clients") + s.logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, s.charID)) s.stage.BroadcastMHF(dupObjUpdate, s) } @@ -74,7 +61,14 @@ func handleMsgSysRotateObject(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysDuplicateObject(s *Session, p mhfpacket.MHFPacket) {} -func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgSysSetObjectBinary(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgSysSetObjectBinary) + for _, object := range s.stage.objects { + if object.id == pkt.ObjID { + object.binary = pkt.RawDataPayload + } + } +} func handleMsgSysGetObjectBinary(s *Session, p mhfpacket.MHFPacket) {} diff --git a/Erupe/server/channelserver/handlers_stage.go b/Erupe/server/channelserver/handlers_stage.go index d7891ba7b..ae0830846 100644 --- a/Erupe/server/channelserver/handlers_stage.go +++ b/Erupe/server/channelserver/handlers_stage.go @@ -108,29 +108,10 @@ func removeSessionFromStage(s *Session) { // Delete old stage objects owned by the client. s.logger.Info("Sending notification to old stage clients") - for objID, stageObject := range s.stage.objects { - if stageObject.ownerCharID == s.charID { - clientNotif := byteframe.NewByteFrame() - var pkt mhfpacket.MHFPacket - pkt = &mhfpacket.MsgSysDeleteObject{ - ObjID: stageObject.id, - } - clientNotif.WriteUint16(uint16(pkt.Opcode())) - pkt.Build(clientNotif, s.clientContext) - clientNotif.WriteUint16(0x0010) - for client, _ := range s.stage.clients { - client.QueueSend(clientNotif.Data()) - } - // TODO(Andoryuuta): Should this be sent to the owner's client as well? it currently isn't. - // Actually delete it from the objects map. - delete(s.stage.objects, objID) - } - } - for objListID, stageObjectList := range s.stage.objectList { - if stageObjectList.charid == s.charID { - // Added to prevent duplicates from flooding ObjectMap and causing server hangs - s.stage.objectList[objListID].status = false - s.stage.objectList[objListID].charid = 0 + for _, object := range s.stage.objects { + if object.ownerCharID == s.charID { + s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ObjID: object.id}, s) + delete(s.stage.objects, object.ownerCharID) } } s.stage.Unlock() @@ -149,34 +130,6 @@ func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { s.reservationStage = nil } - if pkt.StageID == "sl1Ns200p0a0u0" { // First entry - var temp mhfpacket.MHFPacket - loginNotif := byteframe.NewByteFrame() - s.server.Lock() - for _, session := range s.server.sessions { - if s == session || !session.binariesDone { - continue - } - temp = &mhfpacket.MsgSysInsertUser{ - CharID: session.charID, - } - loginNotif.WriteUint16(uint16(temp.Opcode())) - temp.Build(loginNotif, s.clientContext) - for i := 1; i <= 3; i++ { - temp = &mhfpacket.MsgSysNotifyUserBinary{ - CharID: session.charID, - BinaryType: uint8(i), - } - loginNotif.WriteUint16(uint16(temp.Opcode())) - temp.Build(loginNotif, s.clientContext) - } - } - s.server.Unlock() - loginNotif.WriteUint16(0x0010) // End it. - if len(loginNotif.Data()) > 2 { - s.QueueSend(loginNotif.Data()) - } - } doStageTransfer(s, pkt.AckHandle, pkt.StageID) } @@ -218,11 +171,9 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) { s.reservationStage.RLock() defer s.reservationStage.RUnlock() - destructMessage := &mhfpacket.MsgSysStageDestruct{} - for charID := range s.reservationStage.reservedClientSlots { session := s.server.FindSessionByCharID(charID) - session.QueueSendMHF(destructMessage) + session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) } s.server.Lock() diff --git a/Erupe/server/channelserver/handlers_users.go b/Erupe/server/channelserver/handlers_users.go index 623beced5..10272865d 100644 --- a/Erupe/server/channelserver/handlers_users.go +++ b/Erupe/server/channelserver/handlers_users.go @@ -12,6 +12,49 @@ func handleMsgSysInsertUser(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysDeleteUser(s *Session, p mhfpacket.MHFPacket) {} +func broadcastNewUser(s *Session) { + s.logger.Debug(fmt.Sprintf("Broadcasting new user: %s (%d)", s.Name, s.charID)) + + clientNotif := byteframe.NewByteFrame() + var temp mhfpacket.MHFPacket + for _, session := range s.server.sessions { + if session == s || !s.binariesDone { + continue + } + temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} + clientNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(clientNotif, s.clientContext) + for i := 0; i < 3; i++ { + temp = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: session.charID, + BinaryType: uint8(i + 1), + } + clientNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(clientNotif, s.clientContext) + } + } + s.QueueSend(clientNotif.Data()) + + serverNotif := byteframe.NewByteFrame() + temp = &mhfpacket.MsgSysInsertUser{CharID: s.charID} + serverNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(serverNotif, s.clientContext) + for i := 0; i < 3; i++ { + temp = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: s.charID, + BinaryType: uint8(i + 1), + } + serverNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(serverNotif, s.clientContext) + } + for _, session := range s.server.sessions { + if session == s || !session.binariesDone { + continue + } + session.QueueSend(serverNotif.Data()) + } +} + func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysSetUserBinary) s.server.userBinaryPartsLock.Lock() @@ -27,9 +70,7 @@ func handleMsgSysSetUserBinary(s *Session, p mhfpacket.MHFPacket) { } } s.binariesDone = true - s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser{ - CharID: s.charID, - }, s) + broadcastNewUser(s) return } diff --git a/Erupe/server/channelserver/sys_channel_server.go b/Erupe/server/channelserver/sys_channel_server.go index 89bfa2584..a6e22106d 100644 --- a/Erupe/server/channelserver/sys_channel_server.go +++ b/Erupe/server/channelserver/sys_channel_server.go @@ -277,7 +277,7 @@ func (s *Server) manageSessions() { func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { // Broadcast the data. for _, session := range s.sessions { - if session == ignoredSession { + if session == ignoredSession || !session.binariesDone { continue } @@ -295,14 +295,14 @@ func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) func (s *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { for _, c := range s.Channels { - for _, s := range c.sessions { - if s == ignoredSession { + for _, session := range c.sessions { + if session == ignoredSession || !session.binariesDone { continue } bf := byteframe.NewByteFrame() bf.WriteUint16(uint16(pkt.Opcode())) - pkt.Build(bf, s.clientContext) - s.QueueSendNonBlocking(bf.Data()) + pkt.Build(bf, session.clientContext) + session.QueueSendNonBlocking(bf.Data()) } } } @@ -384,7 +384,7 @@ func (s *Server) FindSessionByCharID(charID uint32) *Session { return nil } -func (s *Server) FindStageObjectByChar(charID uint32) *StageObject { +func (s *Server) FindObjectByChar(charID uint32) *Object { s.stagesLock.RLock() defer s.stagesLock.RUnlock() for _, stage := range s.stages { diff --git a/Erupe/server/channelserver/sys_stage.go b/Erupe/server/channelserver/sys_stage.go index 8c0a19568..3d0d68d28 100644 --- a/Erupe/server/channelserver/sys_stage.go +++ b/Erupe/server/channelserver/sys_stage.go @@ -9,18 +9,13 @@ import ( "erupe-ce/network/mhfpacket" ) -// StageObject holds infomation about a specific stage object. -type StageObject struct { +// Object holds infomation about a specific object. +type Object struct { sync.RWMutex id uint32 ownerCharID uint32 x, y, z float32 -} - -type ObjectMap struct { - id uint8 - charid uint32 - status bool + binary []byte } // stageBinaryKey is a struct used as a map key for identifying a stage binary part. @@ -36,13 +31,10 @@ type Stage struct { // Stage ID string id string - // Total count of objects ever created for this stage. Used for ObjID generation. - gameObjectCount uint32 + // Objects + objects map[uint32]*Object + objectIndex uint32 - // Save all object in stage - objects map[uint32]*StageObject - - objectList map[uint8]*ObjectMap // Map of session -> charID. // These are clients that are CURRENTLY in the stage clients map[*Session]uint32 @@ -66,14 +58,12 @@ func NewStage(ID string) *Stage { id: ID, clients: make(map[*Session]uint32), reservedClientSlots: make(map[uint32]bool), - objects: make(map[uint32]*StageObject), + objects: make(map[uint32]*Object), + objectIndex: 0, rawBinaryData: make(map[stageBinaryKey][]byte), maxPlayers: 4, - gameObjectCount: 1, - objectList: make(map[uint8]*ObjectMap), createdAt: time.Now().Format("01-02-2006 15:04:05"), } - s.InitObjectList() return s } @@ -81,7 +71,7 @@ func NewStage(ID string) *Stage { func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { // Broadcast the data. for session := range s.clients { - if session == ignoredSession { + if session == ignoredSession || !session.binariesDone { continue } @@ -97,17 +87,6 @@ func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { } } -func (s *Stage) InitObjectList() { - for seq := uint8(0x7f); seq > uint8(0); seq-- { - newObj := &ObjectMap{ - id: seq, - charid: uint32(0), - status: false, - } - s.objectList[seq] = newObj - } -} - func (s *Stage) isCharInQuestByID(charID uint32) bool { if _, exists := s.reservedClientSlots[charID]; exists { return exists @@ -120,8 +99,8 @@ func (s *Stage) isQuest() bool { return len(s.reservedClientSlots) > 0 } -func (stage *Stage) GetName() string { - switch stage.id { +func (s *Stage) GetName() string { + switch s.id { case MezeportaStageId: return "Mezeporta" case GuildHallLv1StageId: @@ -149,20 +128,7 @@ func (stage *Stage) GetName() string { } } -func (s *Stage) GetNewObjectID(CharID uint32) uint32 { - ObjId := uint8(0) - for seq := uint8(0x7f); seq > uint8(0); seq-- { - if s.objectList[seq].status == false { - ObjId = seq - break - } - } - s.objectList[ObjId].status = true - s.objectList[ObjId].charid = CharID - bf := byteframe.NewByteFrame() - bf.WriteUint8(uint8(0)) - bf.WriteUint8(ObjId) - bf.WriteUint16(uint16(0)) - obj := uint32(bf.Data()[3]) | uint32(bf.Data()[2])<<8 | uint32(bf.Data()[1])<<16 | uint32(bf.Data()[0])<<32 - return obj +func (s *Stage) NextObjectID() uint32 { + s.objectIndex = s.objectIndex + 1 + return s.objectIndex } From 1c530096b1fbfd4e813417b2e9587f85065d4319 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 26 Jul 2022 20:00:36 +1000 Subject: [PATCH 12/14] stringstack patches --- Erupe/common/stringstack/stringstack.go | 32 ++++++++++++++------ Erupe/server/channelserver/handlers_stage.go | 21 +++++++------ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Erupe/common/stringstack/stringstack.go b/Erupe/common/stringstack/stringstack.go index aff33842e..5f936e6a2 100644 --- a/Erupe/common/stringstack/stringstack.go +++ b/Erupe/common/stringstack/stringstack.go @@ -2,33 +2,45 @@ package stringstack import ( "errors" - "sync" ) // StringStack is a basic LIFO "stack" for storing strings. type StringStack struct { - sync.Mutex - stack []string + Locked bool + stack []string } // New creates a new instance of StringStack func New() *StringStack { - return &StringStack{} + return &StringStack{Locked: false} +} + +// Set sets up a new StringStack +func (s *StringStack) Set(v string) { + s.stack = []string{v} +} + +// Lock freezes the StringStack +func (s *StringStack) Lock() { + if !s.Locked { + s.Locked = true + } +} + +// Unlock unfreezes the StringStack +func (s *StringStack) Unlock() { + if s.Locked { + s.Locked = false + } } // Push pushes a string onto the stack. func (s *StringStack) Push(v string) { - s.Lock() - defer s.Unlock() - s.stack = append(s.stack, v) } // Pop pops a string from the stack. func (s *StringStack) Pop() (string, error) { - s.Lock() - defer s.Unlock() - if len(s.stack) == 0 { return "", errors.New("no items on stack") } diff --git a/Erupe/server/channelserver/handlers_stage.go b/Erupe/server/channelserver/handlers_stage.go index ae0830846..9d9184106 100644 --- a/Erupe/server/channelserver/handlers_stage.go +++ b/Erupe/server/channelserver/handlers_stage.go @@ -120,10 +120,14 @@ func removeSessionFromStage(s *Session) { func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysEnterStage) + // Push our current stage ID to the movement stack before entering another one. - s.Lock() - s.stageMoveStack.Push(s.stageID) - s.Unlock() + if s.stageID == "" { + s.stageMoveStack.Set(pkt.StageID) + } else { + s.stageMoveStack.Push(s.stageID) + s.stageMoveStack.Lock() + } s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{}) if s.reservationStage != nil { @@ -137,9 +141,8 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysBackStage) // Transfer back to the saved stage ID before the previous move or enter. - s.Lock() + s.stageMoveStack.Unlock() backStage, err := s.stageMoveStack.Pop() - s.Unlock() if err != nil { panic(err) @@ -151,10 +154,10 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysMoveStage(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysMoveStage) - // Push our current stage ID to the movement stack before entering another one. - s.Lock() - s.stageMoveStack.Push(s.stageID) - s.Unlock() + // Set a new move stack from the given stage ID if unlocked + if !s.stageMoveStack.Locked { + s.stageMoveStack.Set(pkt.StageID) + } doStageTransfer(s, pkt.AckHandle, pkt.StageID) } From 03714235f7b4f11c6130038d3a2b6973a69ebb0d Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 26 Jul 2022 20:01:48 +1000 Subject: [PATCH 13/14] fix user insertion not broadcasting --- Erupe/server/channelserver/handlers_users.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Erupe/server/channelserver/handlers_users.go b/Erupe/server/channelserver/handlers_users.go index 10272865d..482d83674 100644 --- a/Erupe/server/channelserver/handlers_users.go +++ b/Erupe/server/channelserver/handlers_users.go @@ -18,7 +18,7 @@ func broadcastNewUser(s *Session) { clientNotif := byteframe.NewByteFrame() var temp mhfpacket.MHFPacket for _, session := range s.server.sessions { - if session == s || !s.binariesDone { + if session == s || !session.binariesDone { continue } temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} From 92041ba0f4826ab193927a87abf52fb59b8fc0b0 Mon Sep 17 00:00:00 2001 From: wish Date: Tue, 26 Jul 2022 20:06:01 +1000 Subject: [PATCH 14/14] add option for maximum hexdump length --- Erupe/config.json | 163 ++++++------ Erupe/config/config.go | 291 +++++++++++----------- Erupe/server/channelserver/sys_session.go | 6 +- 3 files changed, 233 insertions(+), 227 deletions(-) diff --git a/Erupe/config.json b/Erupe/config.json index 1523d9d14..eb59db613 100644 --- a/Erupe/config.json +++ b/Erupe/config.json @@ -1,81 +1,82 @@ -{ - "host_ip": "127.0.0.1", - "bin_path": "bin", - "devmode": true, - "devmodeoptions": { - "serverName" : "", - "cleandb": false, - "maxlauncherhr": true, - "LogInboundMessages": false, - "LogOutboundMessages": false, - "Event": 0, - "DivaEvent": 0, - "FestaEvent": 0, - "TournamentEvent": 0, - "MezFesEvent": true, - "SaveDumps": { - "Enabled": true, - "OutputDir": "savedata" - } - }, - "discord": { - "enabled": false, - "bottoken": "", - "realtimeChannelID": "", - "serverId": "", - "devRoles": [], - "devMode": false - }, - "database": { - "host": "localhost", - "port": 5432, - "user": "postgres", - "password": "", - "database": "erupe" - }, - "launcher": { - "port": 80, - "UseOriginalLauncherFiles": false - }, - "sign": { - "port": 53312 - }, - "entrance": { - "port": 53310, - "entries": [ - { - "name": "Newbie", "description": "", "ip": "", "type": 3, "recommended": 2, "allowedclientflags": 0, - "channels": [ - { "port": 54001, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 }, - { "port": 54002, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } - ] - }, { - "name": "Normal", "description": "", "ip": "", "type": 1, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54003, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 }, - { "port": 54004, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } - ] - }, { - "name": "Cities", "description": "", "ip": "", "type": 2, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54005, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } - ] - }, { - "name": "Tavern", "description": "", "ip": "", "type": 4, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54006, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } - ] - }, { - "name": "Return", "description": "", "ip": "", "type": 5, "recommended": 0, "allowedclientflags": 0, - "channels": [ - { "port": 54007, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } - ] - }, { - "name": "MezFes", "description": "", "ip": "", "type": 6, "recommended": 6, "allowedclientflags": 0, - "channels": [ - { "port": 54008, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } - ] - } - ] - } -} +{ + "host_ip": "127.0.0.1", + "bin_path": "bin", + "devmode": true, + "devmodeoptions": { + "serverName" : "", + "cleandb": false, + "maxlauncherhr": true, + "LogInboundMessages": false, + "LogOutboundMessages": false, + "MaxHexdumpLength": 256, + "Event": 0, + "DivaEvent": 0, + "FestaEvent": 0, + "TournamentEvent": 0, + "MezFesEvent": true, + "SaveDumps": { + "Enabled": true, + "OutputDir": "savedata" + } + }, + "discord": { + "enabled": false, + "bottoken": "", + "realtimeChannelID": "", + "serverId": "", + "devRoles": [], + "devMode": false + }, + "database": { + "host": "localhost", + "port": 5432, + "user": "postgres", + "password": "", + "database": "erupe" + }, + "launcher": { + "port": 80, + "UseOriginalLauncherFiles": false + }, + "sign": { + "port": 53312 + }, + "entrance": { + "port": 53310, + "entries": [ + { + "name": "Newbie", "description": "", "ip": "", "type": 3, "recommended": 2, "allowedclientflags": 0, + "channels": [ + { "port": 54001, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 }, + { "port": 54002, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } + ] + }, { + "name": "Normal", "description": "", "ip": "", "type": 1, "recommended": 0, "allowedclientflags": 0, + "channels": [ + { "port": 54003, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 }, + { "port": 54004, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } + ] + }, { + "name": "Cities", "description": "", "ip": "", "type": 2, "recommended": 0, "allowedclientflags": 0, + "channels": [ + { "port": 54005, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } + ] + }, { + "name": "Tavern", "description": "", "ip": "", "type": 4, "recommended": 0, "allowedclientflags": 0, + "channels": [ + { "port": 54006, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } + ] + }, { + "name": "Return", "description": "", "ip": "", "type": 5, "recommended": 0, "allowedclientflags": 0, + "channels": [ + { "port": 54007, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } + ] + }, { + "name": "MezFes", "description": "", "ip": "", "type": 6, "recommended": 6, "allowedclientflags": 0, + "channels": [ + { "port": 54008, "MaxPlayers": 50, "Unk0": 319, "Unk1": 252, "Unk2": 248 } + ] + } + ] + } +} diff --git a/Erupe/config/config.go b/Erupe/config/config.go index 193c76e27..5f0079fad 100644 --- a/Erupe/config/config.go +++ b/Erupe/config/config.go @@ -1,145 +1,146 @@ -package config - -import ( - "log" - "net" - - "github.com/spf13/viper" -) - -// Config holds the global server-wide config. -type Config struct { - HostIP string `mapstructure:"host_ip"` - BinPath string `mapstructure:"bin_path"` - DevMode bool - - DevModeOptions DevModeOptions - Discord Discord - Database Database - Launcher Launcher - Sign Sign - Entrance Entrance -} - -// DevModeOptions holds various debug/temporary options for use while developing Erupe. -type DevModeOptions struct { - ServerName string // To get specific instance server about (Current Players/Event Week) - CleanDB bool // Automatically wipes the DB on server reset. - MaxLauncherHR bool // Sets the HR returned in the launcher to HR9 so that you can join non-beginner worlds. - FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages - LogInboundMessages bool // Log all messages sent to the server - LogOutboundMessages bool // Log all messages sent to the clients - DivaEvent int // Diva Defense event status - FestaEvent int // Hunter's Festa event status - TournamentEvent int // VS Tournament event status - MezFesEvent bool // MezFes status - SaveDumps SaveDumpOptions -} - -type SaveDumpOptions struct { - Enabled bool - OutputDir string -} - -// Discord holds the discord integration config. -type Discord struct { - Enabled bool - BotToken string - ServerID string - RealtimeChannelID string - DevRoles []string - DevMode bool -} - -// Database holds the postgres database config. -type Database struct { - Host string - Port int - User string - Password string - Database string -} - -// Launcher holds the launcher server config. -type Launcher struct { - Port int - UseOriginalLauncherFiles bool -} - -// Sign holds the sign server config. -type Sign struct { - Port int -} - -// Entrance holds the entrance server config. -type Entrance struct { - Port uint16 - Entries []EntranceServerInfo -} - -// EntranceServerInfo represents an entry in the serverlist. -type EntranceServerInfo struct { - IP string - Type uint8 // Server type. 0=?, 1=open, 2=cities, 3=newbie, 4=bar - Season uint8 // Server activity. 0 = green, 1 = orange, 2 = blue - Recommended uint8 // Something to do with server recommendation on 0, 3, and 5. - Name string // Server name, 66 byte null terminated Shift-JIS(JP) or Big5(TW). - Description string // Server description - // 4096(PC, PS3/PS4)?, 8258(PC, PS3/PS4)?, 8192 == nothing? - // THIS ONLY EXISTS IF Binary8Header.type == "SV2", NOT "SVR"! - AllowedClientFlags uint32 - - Channels []EntranceChannelInfo -} - -// EntranceChannelInfo represents an entry in a server's channel list. -type EntranceChannelInfo struct { - Port uint16 - MaxPlayers uint16 - CurrentPlayers uint16 - Unk0 uint16 - Unk1 uint16 - Unk2 uint16 -} - -// getOutboundIP4 gets the preferred outbound ip4 of this machine -// From https://stackoverflow.com/a/37382208 -func getOutboundIP4() net.IP { - conn, err := net.Dial("udp4", "8.8.8.8:80") - if err != nil { - log.Fatal(err) - } - defer conn.Close() - - localAddr := conn.LocalAddr().(*net.UDPAddr) - - return localAddr.IP.To4() -} - -// LoadConfig loads the given config toml file. -func LoadConfig() (*Config, error) { - viper.SetConfigName("config") - viper.AddConfigPath(".") - - viper.SetDefault("DevModeOptions.SaveDumps", SaveDumpOptions{ - Enabled: false, - OutputDir: "savedata", - }) - - err := viper.ReadInConfig() - if err != nil { - return nil, err - } - - c := &Config{} - err = viper.Unmarshal(c) - if err != nil { - return nil, err - } - - if c.HostIP == "" { - c.HostIP = getOutboundIP4().To4().String() - } - - return c, nil -} +package config + +import ( + "log" + "net" + + "github.com/spf13/viper" +) + +// Config holds the global server-wide config. +type Config struct { + HostIP string `mapstructure:"host_ip"` + BinPath string `mapstructure:"bin_path"` + DevMode bool + + DevModeOptions DevModeOptions + Discord Discord + Database Database + Launcher Launcher + Sign Sign + Entrance Entrance +} + +// DevModeOptions holds various debug/temporary options for use while developing Erupe. +type DevModeOptions struct { + ServerName string // To get specific instance server about (Current Players/Event Week) + CleanDB bool // Automatically wipes the DB on server reset. + MaxLauncherHR bool // Sets the HR returned in the launcher to HR9 so that you can join non-beginner worlds. + FixedStageID bool // Causes all move_stage to use the ID sl1Ns200p0a0u0 to get you into all stages + LogInboundMessages bool // Log all messages sent to the server + LogOutboundMessages bool // Log all messages sent to the clients + MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled + DivaEvent int // Diva Defense event status + FestaEvent int // Hunter's Festa event status + TournamentEvent int // VS Tournament event status + MezFesEvent bool // MezFes status + SaveDumps SaveDumpOptions +} + +type SaveDumpOptions struct { + Enabled bool + OutputDir string +} + +// Discord holds the discord integration config. +type Discord struct { + Enabled bool + BotToken string + ServerID string + RealtimeChannelID string + DevRoles []string + DevMode bool +} + +// Database holds the postgres database config. +type Database struct { + Host string + Port int + User string + Password string + Database string +} + +// Launcher holds the launcher server config. +type Launcher struct { + Port int + UseOriginalLauncherFiles bool +} + +// Sign holds the sign server config. +type Sign struct { + Port int +} + +// Entrance holds the entrance server config. +type Entrance struct { + Port uint16 + Entries []EntranceServerInfo +} + +// EntranceServerInfo represents an entry in the serverlist. +type EntranceServerInfo struct { + IP string + Type uint8 // Server type. 0=?, 1=open, 2=cities, 3=newbie, 4=bar + Season uint8 // Server activity. 0 = green, 1 = orange, 2 = blue + Recommended uint8 // Something to do with server recommendation on 0, 3, and 5. + Name string // Server name, 66 byte null terminated Shift-JIS(JP) or Big5(TW). + Description string // Server description + // 4096(PC, PS3/PS4)?, 8258(PC, PS3/PS4)?, 8192 == nothing? + // THIS ONLY EXISTS IF Binary8Header.type == "SV2", NOT "SVR"! + AllowedClientFlags uint32 + + Channels []EntranceChannelInfo +} + +// EntranceChannelInfo represents an entry in a server's channel list. +type EntranceChannelInfo struct { + Port uint16 + MaxPlayers uint16 + CurrentPlayers uint16 + Unk0 uint16 + Unk1 uint16 + Unk2 uint16 +} + +// getOutboundIP4 gets the preferred outbound ip4 of this machine +// From https://stackoverflow.com/a/37382208 +func getOutboundIP4() net.IP { + conn, err := net.Dial("udp4", "8.8.8.8:80") + if err != nil { + log.Fatal(err) + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP.To4() +} + +// LoadConfig loads the given config toml file. +func LoadConfig() (*Config, error) { + viper.SetConfigName("config") + viper.AddConfigPath(".") + + viper.SetDefault("DevModeOptions.SaveDumps", SaveDumpOptions{ + Enabled: false, + OutputDir: "savedata", + }) + + err := viper.ReadInConfig() + if err != nil { + return nil, err + } + + c := &Config{} + err = viper.Unmarshal(c) + if err != nil { + return nil, err + } + + if c.HostIP == "" { + c.HostIP = getOutboundIP4().To4().String() + } + + return c, nil +} diff --git a/Erupe/server/channelserver/sys_session.go b/Erupe/server/channelserver/sys_session.go index a023381ff..fca8741b2 100644 --- a/Erupe/server/channelserver/sys_session.go +++ b/Erupe/server/channelserver/sys_session.go @@ -239,5 +239,9 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien } fmt.Printf("[%s] -> [%s]\n", sender, recipient) fmt.Printf("Opcode: %s\n", opcodePID) - fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) + if len(data) <= s.server.erupeConfig.DevModeOptions.MaxHexdumpLength { + fmt.Printf("Data [%d bytes]:\n%s\n", len(data), hex.Dump(data)) + } else { + fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data)) + } }