diff --git a/network/mhfpacket/msg_sys_create_stage.go b/network/mhfpacket/msg_sys_create_stage.go index fe6e533ff..6f6076143 100644 --- a/network/mhfpacket/msg_sys_create_stage.go +++ b/network/mhfpacket/msg_sys_create_stage.go @@ -3,7 +3,6 @@ package mhfpacket import ( "errors" "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -26,8 +25,8 @@ func (m *MsgSysCreateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client m.AckHandle = bf.ReadUint32() m.Unk0 = bf.ReadUint8() m.PlayerCount = bf.ReadUint8() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + _ = bf.ReadUint8() // Length StageID + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_enter_stage.go b/network/mhfpacket/msg_sys_enter_stage.go index 977ff486f..924e26fe1 100644 --- a/network/mhfpacket/msg_sys_enter_stage.go +++ b/network/mhfpacket/msg_sys_enter_stage.go @@ -4,7 +4,6 @@ import ( "errors" "erupe-ce/common/byteframe" - "erupe-ce/common/bfutil" "erupe-ce/network" "erupe-ce/network/clientctx" ) @@ -12,7 +11,7 @@ import ( // MsgSysEnterStage represents the MSG_SYS_ENTER_STAGE type MsgSysEnterStage struct { AckHandle uint32 - UnkBool uint8 + Unk bool StageID string } @@ -24,9 +23,9 @@ func (m *MsgSysEnterStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.UnkBool = bf.ReadUint8() - stageIDLength := bf.ReadUint8() - m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) + m.Unk = bf.ReadBool() // IsQuest? + _ = bf.ReadUint8() // Length StageID + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_enumerate_stage.go b/network/mhfpacket/msg_sys_enumerate_stage.go index a3f125941..94fe89ed1 100644 --- a/network/mhfpacket/msg_sys_enumerate_stage.go +++ b/network/mhfpacket/msg_sys_enumerate_stage.go @@ -12,7 +12,6 @@ import ( // MsgSysEnumerateStage represents the MSG_SYS_ENUMERATE_STAGE type MsgSysEnumerateStage struct { AckHandle uint32 - Unk0 uint8 // Hardcoded 1 in the binary StagePrefix string // NULL terminated string. } @@ -24,8 +23,8 @@ func (m *MsgSysEnumerateStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysEnumerateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - bf.ReadUint8() + _ = bf.ReadUint8() // Always 1 + _ = bf.ReadUint8() // Prefix length m.StagePrefix = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_lock_stage.go b/network/mhfpacket/msg_sys_lock_stage.go index 14b082596..04d396f87 100644 --- a/network/mhfpacket/msg_sys_lock_stage.go +++ b/network/mhfpacket/msg_sys_lock_stage.go @@ -1,20 +1,17 @@ package mhfpacket -import ( - "errors" +import ( + "errors" - "erupe-ce/network/clientctx" - "erupe-ce/network" "erupe-ce/common/byteframe" + "erupe-ce/network" + "erupe-ce/network/clientctx" ) // MsgSysLockStage represents the MSG_SYS_LOCK_STAGE type MsgSysLockStage struct { - AckHandle uint32 - Unk0 uint8 // Hardcoded 1 in the binary - Unk1 uint8 // Hardcoded 1 in the binary - StageIDLength uint8 - StageID string + AckHandle uint32 + StageID string } // Opcode returns the ID associated with this packet type. @@ -25,10 +22,10 @@ func (m *MsgSysLockStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysLockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { m.AckHandle = bf.ReadUint32() - m.Unk0 = bf.ReadUint8() - m.Unk1 = bf.ReadUint8() - m.StageIDLength = bf.ReadUint8() - m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) + _ = bf.ReadUint8() // Always 1 + _ = bf.ReadUint8() // Always 1 + _ = bf.ReadUint8() // Length StageID + m.StageID = string(bf.ReadNullTerminatedBytes()) return nil } diff --git a/network/mhfpacket/msg_sys_unlock_stage.go b/network/mhfpacket/msg_sys_unlock_stage.go index 74af57424..c0bcbfca4 100644 --- a/network/mhfpacket/msg_sys_unlock_stage.go +++ b/network/mhfpacket/msg_sys_unlock_stage.go @@ -1,15 +1,14 @@ package mhfpacket import ( + "errors" + "erupe-ce/common/byteframe" "erupe-ce/network" "erupe-ce/network/clientctx" - "erupe-ce/common/byteframe" ) // MsgSysUnlockStage represents the MSG_SYS_UNLOCK_STAGE -type MsgSysUnlockStage struct { - Unk0 uint16 // Hardcoded 0 in the binary. -} +type MsgSysUnlockStage struct{} // Opcode returns the ID associated with this packet type. func (m *MsgSysUnlockStage) Opcode() network.PacketID { @@ -18,12 +17,11 @@ func (m *MsgSysUnlockStage) Opcode() network.PacketID { // Parse parses the packet from binary func (m *MsgSysUnlockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - m.Unk0 = bf.ReadUint16() + _ = bf.ReadUint16() // Always zero return nil } // Build builds a binary packet from the current data. func (m *MsgSysUnlockStage) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { - bf.WriteUint16(m.Unk0) - return nil + return errors.New("NOT IMPLEMENTED") } diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 211fcaf79..1b4442e51 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -190,11 +190,9 @@ func logoutPlayer(s *Session) { for _, stage := range s.server.stages { // Tell sessions registered to disconnecting players quest to unregister if stage.host != nil && stage.host.charID == s.charID { - for _, sess := range s.server.sessions { - for rSlot := range stage.reservedClientSlots { - if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" { - sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) - } + for _, sess := range stage.ReservedSessions(s) { + if sess.stage != nil && sess.stage.id[3:5] != "Qs" { + sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) } } } @@ -243,14 +241,6 @@ func logoutPlayer(s *Session) { CharID: s.charID, }, s) - s.server.Lock() - for _, stage := range s.server.stages { - if _, exists := stage.reservedClientSlots[s.charID]; exists { - delete(stage.reservedClientSlots, s.charID) - } - } - s.server.Unlock() - removeSessionFromSemaphore(s) removeSessionFromStage(s) @@ -317,8 +307,6 @@ func handleMsgSysRecordLog(s *Session, p mhfpacket.MHFPacket) { } } } - // remove a client returning to town from reserved slots to make sure the stage is hidden from board - delete(s.stage.reservedClientSlots, s.charID) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } @@ -378,7 +366,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) { if session.charID == CharID { count++ sessionName := stringsupport.UTF8ToSJIS(session.Name) - sessionStage := stringsupport.UTF8ToSJIS(session.stageID) + sessionStage := stringsupport.UTF8ToSJIS(session.stage.id) resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4())) resp.WriteUint16(c.Port) resp.WriteUint32(session.charID) @@ -408,7 +396,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) { if strings.Contains(session.Name, searchTerm) { count++ sessionName := stringsupport.UTF8ToSJIS(session.Name) - sessionStage := stringsupport.UTF8ToSJIS(session.stageID) + sessionStage := stringsupport.UTF8ToSJIS(session.stage.id) resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4())) resp.WriteUint16(c.Port) resp.WriteUint32(session.charID) @@ -445,7 +433,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) { hrp := uint16(1) gr := uint16(0) s.server.db.QueryRow("SELECT hrp, gr FROM characters WHERE id=$1", session.charID).Scan(&hrp, &gr) - sessionStage := stringsupport.UTF8ToSJIS(session.stageID) + sessionStage := stringsupport.UTF8ToSJIS(session.stage.id) sessionName := stringsupport.UTF8ToSJIS(session.Name) resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4())) resp.WriteUint16(c.Port) diff --git a/server/channelserver/handlers_clients.go b/server/channelserver/handlers_clients.go index a617cad2d..3073b1286 100644 --- a/server/channelserver/handlers_clients.go +++ b/server/channelserver/handlers_clients.go @@ -29,15 +29,15 @@ func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) { clients = append(clients, cid) } case 1: // Not ready - for cid, ready := range stage.reservedClientSlots { - if !ready { - clients = append(clients, cid) + for _, session := range stage.ReservedSessions(s) { + if !session.reservationReady { + clients = append(clients, session.charID) } } case 2: // Ready - for cid, ready := range stage.reservedClientSlots { - if ready { - clients = append(clients, cid) + for _, session := range stage.ReservedSessions(s) { + if session.reservationReady { + clients = append(clients, session.charID) } } } diff --git a/server/channelserver/handlers_discord.go b/server/channelserver/handlers_discord.go index 1f3398d18..785a0a595 100644 --- a/server/channelserver/handlers_discord.go +++ b/server/channelserver/handlers_discord.go @@ -15,7 +15,7 @@ type Player struct { func getPlayerSlice(s *Server) []Player { var p []Player - var questIndex int + //var questIndex int for _, channel := range s.Channels { for _, stage := range channel.stages { @@ -23,10 +23,10 @@ func getPlayerSlice(s *Server) []Player { continue } questID := 0 - if stage.isQuest() { - questIndex++ - questID = questIndex - } + //if stage.isQuest() { + // questIndex++ + // questID = questIndex + //} for client := range stage.clients { p = append(p, Player{ CharName: client.Name, diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index c29ea0093..7c96f0751 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -1,6 +1,7 @@ package channelserver import ( + "erupe-ce/network" "fmt" "strings" "time" @@ -29,6 +30,8 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {} func doStageTransfer(s *Session, ackHandle uint32, stageID string) { + s.reservationStage = nil + s.server.Lock() stage, exists := s.server.stages[stageID] s.server.Unlock() @@ -53,9 +56,8 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { removeSessionFromStage(s) } - // Save our new stage ID and pointer to the new stage itself. + // Save our pointer to the new stage itself. s.Lock() - s.stageID = stageID s.stage = s.server.stages[stageID] s.Unlock() @@ -113,7 +115,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { s.stage.RUnlock() } - newNotif.WriteUint16(0x0010) // End it. + newNotif.WriteUint16(uint16(network.MSG_SYS_END)) // End it. if len(newNotif.Data()) > 2 { s.QueueSend(newNotif.Data()) } @@ -125,7 +127,7 @@ func destructEmptyStages(s *Session) { for _, stage := range s.server.stages { // Destroy empty Quest/My series/Guild stages. if stage.id[3:5] == "Qs" || stage.id[3:5] == "Ms" || stage.id[3:5] == "Gs" || stage.id[3:5] == "Ls" { - if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { + if len(stage.ReservedSessions(s)) == 0 && len(stage.clients) == 0 { delete(s.server.stages, stage.id) s.logger.Debug("Destructed stage", zap.String("stage.id", stage.id)) } @@ -153,21 +155,13 @@ func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysEnterStage) // Push our current stage ID to the movement stack before entering another one. - if s.stageID == "" { + if s.stage.id == "" { s.stageMoveStack.Set(pkt.StageID) } else { - s.stage.Lock() - s.stage.reservedClientSlots[s.charID] = false - s.stage.Unlock() - s.stageMoveStack.Push(s.stageID) + s.stageMoveStack.Push(s.stage.id) s.stageMoveStack.Lock() } - s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{}) - if s.reservationStage != nil { - s.reservationStage = nil - } - doStageTransfer(s, pkt.AckHandle, pkt.StageID) } @@ -178,19 +172,9 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) { s.stageMoveStack.Unlock() backStage, err := s.stageMoveStack.Pop() if err != nil { - panic(err) + backStage = "sl1Ns200p0a0u0" } - s.stage.Lock() - if _, exists := s.stage.reservedClientSlots[s.charID]; exists { - delete(s.stage.reservedClientSlots, s.charID) - } - - if _, exists := s.server.stages[backStage].reservedClientSlots[s.charID]; exists { - delete(s.server.stages[backStage].reservedClientSlots, s.charID) - } - s.stage.Unlock() - doStageTransfer(s, pkt.AckHandle, backStage) } @@ -209,18 +193,19 @@ func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysLockStage) - // TODO(Andoryuuta): What does this packet _actually_ do? - // I think this is supposed to mark a stage as no longer able to accept client reservations - doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) + if stage, exists := s.server.stages[pkt.StageID]; exists { + stage.Lock() + stage.locked = true + stage.Unlock() + } + doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) } func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) { if s.reservationStage != nil { s.reservationStage.RLock() defer s.reservationStage.RUnlock() - - for charID := range s.reservationStage.reservedClientSlots { - session := s.server.FindSessionByCharID(charID) + for _, session := range s.reservationStage.ReservedSessions(s) { session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) } @@ -235,24 +220,24 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) { if stage, exists := s.server.stages[pkt.StageID]; exists { stage.Lock() defer stage.Unlock() - if _, exists := stage.reservedClientSlots[s.charID]; exists { + if stage.IsSessionReserved(s) { switch pkt.Ready { case 1: // 0x01 - stage.reservedClientSlots[s.charID] = false + s.reservationReady = false case 17: // 0x11 - stage.reservedClientSlots[s.charID] = true + s.reservationReady = true } doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) - } else if uint16(len(stage.reservedClientSlots)) < stage.maxPlayers { + } else if uint16(len(stage.ReservedSessions(s))) < stage.maxPlayers { if len(stage.password) > 0 { if stage.password != s.stagePass { doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) return } } - stage.reservedClientSlots[s.charID] = false // Save the reservation stage in the session for later use in MsgSysUnreserveStage. s.Lock() + s.reservationReady = false s.reservationStage = stage s.Unlock() doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) @@ -267,16 +252,8 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) { s.Lock() - stage := s.reservationStage s.reservationStage = nil s.Unlock() - if stage != nil { - stage.Lock() - if _, exists := stage.reservedClientSlots[s.charID]; exists { - delete(stage.reservedClientSlots, s.charID) - } - stage.Unlock() - } } func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) { @@ -287,7 +264,7 @@ func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) { if stage != nil { stage.Lock() // Will only exist if host. - if _, exists := stage.reservedClientSlots[s.charID]; exists { + if stage.IsSessionReserved(s) { stage.password = pkt.Password } stage.Unlock() @@ -370,7 +347,7 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { for _, stage := range s.server.stages { stage.RLock() defer stage.RUnlock() - if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { + if len(stage.ReservedSessions(s)) == 0 && len(stage.clients) == 0 { continue } if !strings.Contains(stage.id, pkt.StagePrefix) { @@ -383,21 +360,18 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) { bf.WriteUint16(uint16(len(stages))) for _, stage := range stages { stage.RLock() - bf.WriteUint16(uint16(len(stage.reservedClientSlots))) - bf.WriteUint16(0) - if len(stage.clients) > 0 { - bf.WriteUint16(1) - } else { - bf.WriteUint16(0) - } + bf.WriteUint16(uint16(len(stage.ReservedSessions(s))) - uint16(len(stage.clients))) + bf.WriteUint16(uint16(len(stage.clients))) + bf.WriteUint16(uint16(len(stage.clients))) bf.WriteUint16(stage.maxPlayers) - if len(stage.password) > 0 { - // This byte has also been seen as 1 - // 2/3 = Locked, bitfield? - bf.WriteUint8(2) - } else { - bf.WriteUint8(0) + var flags uint8 + if stage.locked { + flags |= 1 } + if len(stage.password) > 0 { + flags |= 2 + } + bf.WriteUint8(flags) ps.Uint8(bf, stage.id, false) stage.RUnlock() } diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index b11847af2..9c4cdb6ed 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -36,9 +36,9 @@ type Session struct { objectIndex uint16 userEnteredStage bool // If the user has entered a stage before - stageID string stage *Stage reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. + reservationReady bool stagePass string // Temporary storage prevGuildID uint32 // Stores the last GuildID used in InfoGuild charID uint32 diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go index ae8ddd149..02b1d150c 100644 --- a/server/channelserver/sys_stage.go +++ b/server/channelserver/sys_stage.go @@ -36,10 +36,6 @@ type Stage struct { // These are clients that are CURRENTLY in the stage clients map[*Session]uint32 - // Map of charID -> bool, key represents whether they are ready - // These are clients that aren't in the stage, but have reserved a slot (for quests, etc). - reservedClientSlots map[uint32]bool - // These are raw binary blobs that the stage owner sets, // other clients expect the server to echo them back in the exact same format. rawBinaryData map[stageBinaryKey][]byte @@ -47,18 +43,39 @@ type Stage struct { host *Session maxPlayers uint16 password string + locked bool +} + +func (s *Stage) ReservedSessions(se *Session) []*Session { + var sessions []*Session + se.server.RLock() + for _, session := range se.server.sessions { + if session.reservationStage == s { + sessions = append(sessions, session) + } + } + se.server.RUnlock() + return sessions +} + +func (s *Stage) IsSessionReserved(se *Session) bool { + for _, session := range s.ReservedSessions(se) { + if session == se { + return true + } + } + return false } // NewStage creates a new stage with intialized values. func NewStage(ID string) *Stage { s := &Stage{ - id: ID, - clients: make(map[*Session]uint32), - reservedClientSlots: make(map[uint32]bool), - objects: make(map[uint32]*Object), - objectIndex: 0, - rawBinaryData: make(map[stageBinaryKey][]byte), - maxPlayers: 4, + id: ID, + clients: make(map[*Session]uint32), + objects: make(map[uint32]*Object), + objectIndex: 0, + rawBinaryData: make(map[stageBinaryKey][]byte), + maxPlayers: 4, } return s } @@ -83,15 +100,3 @@ func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { session.QueueSendNonBlocking(bf.Data()) } } - -func (s *Stage) isCharInQuestByID(charID uint32) bool { - if _, exists := s.reservedClientSlots[charID]; exists { - return exists - } - - return false -} - -func (s *Stage) isQuest() bool { - return len(s.reservedClientSlots) > 0 -}