From 78fe5c85efc334597d841a8147e1cfc82c3de709 Mon Sep 17 00:00:00 2001 From: Sophie Date: Mon, 9 Mar 2020 19:15:16 +0000 Subject: [PATCH] Add support for players logging out and closing client Removed seemingly unnecessary castedBinary messages on character login --- network/mhfpacket/msg_sys_delete_user.go | 8 +- server/channelserver/handlers.go | 105 +++++++++++++++-------- server/channelserver/session.go | 8 ++ 3 files changed, 83 insertions(+), 38 deletions(-) diff --git a/network/mhfpacket/msg_sys_delete_user.go b/network/mhfpacket/msg_sys_delete_user.go index 0a3584763..a84589897 100644 --- a/network/mhfpacket/msg_sys_delete_user.go +++ b/network/mhfpacket/msg_sys_delete_user.go @@ -6,7 +6,9 @@ import ( ) // MsgSysDeleteUser represents the MSG_SYS_DELETE_USER -type MsgSysDeleteUser struct{} +type MsgSysDeleteUser struct { + CharID uint32 +} // Opcode returns the ID associated with this packet type. func (m *MsgSysDeleteUser) Opcode() network.PacketID { @@ -20,5 +22,7 @@ func (m *MsgSysDeleteUser) Parse(bf *byteframe.ByteFrame) error { // Build builds a binary packet from the current data. func (m *MsgSysDeleteUser) Build(bf *byteframe.ByteFrame) error { - panic("Not implemented") + bf.WriteUint32(m.CharID) + + return nil } diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index e71f52cae..ecb6a2715 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -177,7 +177,9 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) { s.QueueAck(pkt.AckHandle, bf.Data()) } -func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) {} +func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) { + logoutPlayer(s) +} func handleMsgSysSetStatus(s *Session, p mhfpacket.MHFPacket) {} @@ -396,27 +398,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { s.server.stagesLock.Unlock() if s.stage != nil { - s.stage.Lock() - - // Remove client from old stage. - delete(s.stage.clients, s) - - // Delete old stage objects owned by the client. - s.logger.Info("Sending MsgSysDeleteObject to old stage clients") - for objID, stageObject := range s.stage.objects { - if stageObject.ownerCharID == s.charID { - // Broadcast the deletion to clients in the stage. - s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ - ObjID: stageObject.id, - }, s) - // TODO(Andoryuuta): Should this be sent to the owner's client as well? it currently isn't. - - // Actually delete it form the objects map. - delete(s.stage.objects, objID) - } - } - - s.stage.Unlock() + removeSessionFromStage(s) } // Add the new stage. @@ -439,25 +421,28 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { s.QueueAck(ackHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) // Notify existing stage clients that this new client has entered. - s.logger.Info("Sending MsgSysInsertUser & MsgSysNotifyUserBinary") + s.logger.Info("Sending MsgSysInsertUser") s.stage.BroadcastMHF(&mhfpacket.MsgSysInsertUser{ CharID: s.charID, }, s) - s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ - CharID: s.charID, - BinaryType: 1, - }, s) - s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ - CharID: s.charID, - BinaryType: 2, - }, s) - s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ - CharID: s.charID, - BinaryType: 3, - }, s) + // It seems to be acceptable to recast all MSG_SYS_SET_USER_BINARY messages so far, + // players are still notified when a new player has joined the stage. + // These extra messages may not be needed + //s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ + // CharID: s.charID, + // BinaryType: 1, + //}, s) + //s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ + // CharID: s.charID, + // BinaryType: 2, + //}, s) + //s.stage.BroadcastMHF(&mhfpacket.MsgSysNotifyUserBinary{ + // CharID: s.charID, + // BinaryType: 3, + //}, s) - // Notify the entree client about all of the existing clients in the stage. + //Notify the entree client about all of the existing clients in the stage. s.logger.Info("Notifying entree about existing stage clients") s.stage.RLock() clientNotif := byteframe.NewByteFrame() @@ -515,6 +500,54 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { s.QueueSend(clientDupObjNotif.Data()) } +func removeSessionFromStage(s *Session) { + s.stage.Lock() + defer s.stage.Unlock() + + // Remove client from old stage. + delete(s.stage.clients, s) + + // Delete old stage objects owned by the client. + s.logger.Info("Sending MsgSysDeleteObject to old stage clients") + for objID, stageObject := range s.stage.objects { + if stageObject.ownerCharID == s.charID { + // Broadcast the deletion to clients in the stage. + s.stage.BroadcastMHF(&mhfpacket.MsgSysDeleteObject{ + ObjID: stageObject.id, + }, s) + // TODO(Andoryuuta): Should this be sent to the owner's client as well? it currently isn't. + + // Actually delete it form the objects map. + delete(s.stage.objects, objID) + } + } +} + +func stageContainsSession(stage *Stage, s *Session) bool { + stage.RLock() + defer stage.RUnlock() + + for session := range stage.clients { + if session == s { + return true + } + } + + return false +} + +func logoutPlayer(s *Session) { + s.stage.RLock() + for client := range s.stage.clients { + client.QueueSendMHF(&mhfpacket.MsgSysDeleteUser{ + CharID: s.charID, + }) + } + s.stage.RUnlock() + + removeSessionFromStage(s) +} + func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgSysEnterStage) diff --git a/server/channelserver/session.go b/server/channelserver/session.go index 0bd81d6fb..0f3329c37 100644 --- a/server/channelserver/session.go +++ b/server/channelserver/session.go @@ -3,6 +3,7 @@ package channelserver import ( "encoding/hex" "fmt" + "io" "net" "sync" @@ -124,6 +125,13 @@ func (s *Session) sendLoop() { func (s *Session) recvLoop() { for { pkt, err := s.cryptConn.ReadPacket() + + if err == io.EOF { + s.logger.Info(fmt.Sprintf("Character(%d) disconnected", s.charID)) + logoutPlayer(s) + return + } + if err != nil { s.logger.Warn("Error on ReadPacket, exiting recv loop", zap.Error(err)) return