diff --git a/patch-schema/dbuserbinaries.sql b/patch-schema/dbuserbinaries.sql new file mode 100644 index 000000000..e92b3fd20 --- /dev/null +++ b/patch-schema/dbuserbinaries.sql @@ -0,0 +1,11 @@ +BEGIN; + +CREATE TABLE user_binaries +( + id int PRIMARY KEY, + type1 bytea, + type2 bytea, + type3 bytea +); + +END; \ No newline at end of file diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go index 62630a132..1977d0281 100644 --- a/server/channelserver/handlers.go +++ b/server/channelserver/handlers.go @@ -183,6 +183,8 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) { doAckSimpleSucceed(s, pkt.AckHandle, bf.Data()) updateRights(s) + + s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser{CharID: s.charID}, s) } func handleMsgSysLogout(s *Session, p mhfpacket.MHFPacket) { diff --git a/server/channelserver/handlers_object.go b/server/channelserver/handlers_object.go index 0b24c0f66..08252f61a 100644 --- a/server/channelserver/handlers_object.go +++ b/server/channelserver/handlers_object.go @@ -34,7 +34,7 @@ func handleMsgSysCreateObject(s *Session, p mhfpacket.MHFPacket) { OwnerCharID: newObj.ownerCharID, } - s.logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, s.charID)) + s.logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, newObj.id)) s.stage.BroadcastMHF(dupObjUpdate, s) } @@ -63,9 +63,16 @@ func handleMsgSysDuplicateObject(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 + for _, session := range s.server.sessions { + if session.charID == s.charID { + s.server.userBinaryPartsLock.Lock() + s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: 3}] = pkt.RawDataPayload + s.server.userBinaryPartsLock.Unlock() + msg := &mhfpacket.MsgSysNotifyUserBinary{ + CharID: s.charID, + BinaryType: 3, + } + s.server.BroadcastMHF(msg, s) } } } diff --git a/server/channelserver/handlers_stage.go b/server/channelserver/handlers_stage.go index 221a99ce4..d40c6522a 100644 --- a/server/channelserver/handlers_stage.go +++ b/server/channelserver/handlers_stage.go @@ -1,6 +1,7 @@ package channelserver import ( + "fmt" "time" "erupe-ce/common/byteframe" @@ -51,7 +52,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { // Save our new stage ID and pointer to the new stage itself. s.Lock() - s.stageID = string(stageID) + s.stageID = stageID s.stage = s.server.stages[stageID] s.Unlock() @@ -61,13 +62,41 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { // Confirm the stage entry. doAckSimpleSucceed(s, ackHandle, []byte{0x00, 0x00, 0x00, 0x00}) + var temp mhfpacket.MHFPacket + newNotif := byteframe.NewByteFrame() + + // Cast existing user data to new user + if !s.userEnteredStage { + s.userEnteredStage = true + + for _, session := range s.server.sessions { + if s == session { + continue + } + temp = &mhfpacket.MsgSysInsertUser{CharID: session.charID} + newNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(newNotif, s.clientContext) + for i := 0; i < 3; i++ { + temp = &mhfpacket.MsgSysNotifyUserBinary{ + CharID: session.charID, + BinaryType: uint8(i + 1), + } + newNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(newNotif, s.clientContext) + } + } + } + if s.stage != nil { // avoids lock up when using bed for dream quests // Notify the client to duplicate the existing objects. - s.logger.Info("Sending existing stage objects") - clientDupObjNotif := byteframe.NewByteFrame() + s.logger.Info(fmt.Sprintf("Sending existing stage objects to %s", s.Name)) s.stage.RLock() + var temp mhfpacket.MHFPacket for _, obj := range s.stage.objects { - cur := &mhfpacket.MsgSysDuplicateObject{ + if obj.ownerCharID == s.charID { + continue + } + temp = &mhfpacket.MsgSysDuplicateObject{ ObjID: obj.id, X: obj.x, Y: obj.y, @@ -75,14 +104,15 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) { Unk0: 0, OwnerCharID: obj.ownerCharID, } - clientDupObjNotif.WriteUint16(uint16(cur.Opcode())) - cur.Build(clientDupObjNotif, s.clientContext) + newNotif.WriteUint16(uint16(temp.Opcode())) + temp.Build(newNotif, s.clientContext) } s.stage.RUnlock() - clientDupObjNotif.WriteUint16(0x0010) // End it. - if len(clientDupObjNotif.Data()) > 2 { - s.QueueSend(clientDupObjNotif.Data()) - } + } + + newNotif.WriteUint16(0x0010) // End it. + if len(newNotif.Data()) > 2 { + s.QueueSend(newNotif.Data()) } } diff --git a/server/channelserver/handlers_users.go b/server/channelserver/handlers_users.go index 482d83674..b20b07a7c 100644 --- a/server/channelserver/handlers_users.go +++ b/server/channelserver/handlers_users.go @@ -12,68 +12,19 @@ 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 || !session.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() s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: pkt.BinaryType}] = pkt.RawDataPayload s.server.userBinaryPartsLock.Unlock() - // Insert user once all binary parts exist - if !s.binariesDone { - for i := 0; i < 3; i++ { - _, exists := s.server.userBinaryParts[userBinaryPartID{charID: s.charID, index: uint8(i + 1)}] - if !exists { - return - } - } - s.binariesDone = true - broadcastNewUser(s) - return + err := s.server.db.QueryRow("SELECT type1 FROM user_binaries WHERE id=$1", s.charID) + if err != nil { + s.server.db.Exec("INSERT INTO user_binaries (id) VALUES ($1)", s.charID) } + s.server.db.Exec(fmt.Sprintf("UPDATE user_binaries SET type%d=$1 WHERE id=$2", pkt.BinaryType), pkt.RawDataPayload, s.charID) + msg := &mhfpacket.MsgSysNotifyUserBinary{ CharID: s.charID, BinaryType: pkt.BinaryType, @@ -91,25 +42,18 @@ func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) { data, ok := s.server.userBinaryParts[userBinaryPartID{charID: pkt.CharID, index: pkt.BinaryType}] resp := byteframe.NewByteFrame() - // If we can't get the real data, use a placeholder. + // If we can't get the real data, try to get it from the database. if !ok { - if pkt.BinaryType == 1 { - // Stub name response with character ID - resp.WriteBytes([]byte(fmt.Sprintf("CID%d", s.charID))) - resp.WriteUint8(0) // NULL terminator. - } else if pkt.BinaryType == 2 { - data, err := base64.StdEncoding.DecodeString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBn8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAwAAAAAAAAAAAAAABAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") - if err != nil { - panic(err) - } - resp.WriteBytes(data) - } else if pkt.BinaryType == 3 { - data, err := base64.StdEncoding.DecodeString("AQAAA2ea5P8ATgEA/wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBn8AAAAAAAAAAAABAKAMAAAAAAAAAAAAACgAAAAAAAAAAAABAsQOAAAAAAAAAAABA6UMAAAAAAAAAAABBKAMAAAAAAAAAAABBToNAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") - if err != nil { - panic(err) - } + var data []byte + rows, _ := s.server.db.Queryx(fmt.Sprintf("SELECT type%d FROM user_binaries WHERE id=$1", pkt.BinaryType), pkt.CharID) + for rows.Next() { + rows.Scan(&data) resp.WriteBytes(data) + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) + return } + doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) + return } else { resp.WriteBytes(data) } diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 62c4b2ad7..b03907f8b 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -279,7 +279,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 || !session.binariesDone { + if session == ignoredSession { continue } @@ -298,7 +298,7 @@ func (s *Server) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) func (s *Server) WorldcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) { for _, c := range s.Channels { for _, session := range c.sessions { - if session == ignoredSession || !session.binariesDone { + if session == ignoredSession { continue } bf := byteframe.NewByteFrame() diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index b2a591c8d..6270b33aa 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -27,12 +27,12 @@ type Session struct { sendPackets chan []byte clientContext *clientctx.ClientContext + userEnteredStage bool // If the user has entered a stage before myseries MySeries stageID string stage *Stage reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. stagePass string // Temporary storage - binariesDone bool charID uint32 logKey []byte sessionStart int64 @@ -79,9 +79,9 @@ func NewSession(server *Server, conn net.Conn) *Session { Encoding: japanese.ShiftJIS, }, }, - binariesDone: false, - sessionStart: Time_Current_Adjusted().Unix(), - stageMoveStack: stringstack.New(), + userEnteredStage: false, + sessionStart: Time_Current_Adjusted().Unix(), + stageMoveStack: stringstack.New(), } return s } diff --git a/server/channelserver/sys_stage.go b/server/channelserver/sys_stage.go index 3d0d68d28..40f266981 100644 --- a/server/channelserver/sys_stage.go +++ b/server/channelserver/sys_stage.go @@ -15,7 +15,6 @@ type Object struct { id uint32 ownerCharID uint32 x, y, z float32 - binary []byte } // stageBinaryKey is a struct used as a map key for identifying a stage binary part. @@ -33,7 +32,7 @@ type Stage struct { // Objects objects map[uint32]*Object - objectIndex uint32 + objectIndex uint8 // Map of session -> charID. // These are clients that are CURRENTLY in the stage @@ -71,7 +70,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 || !session.binariesDone { + if session == ignoredSession { continue } @@ -130,5 +129,10 @@ func (s *Stage) GetName() string { func (s *Stage) NextObjectID() uint32 { s.objectIndex = s.objectIndex + 1 - return s.objectIndex + bf := byteframe.NewByteFrame() + bf.WriteUint8(0) + bf.WriteUint8(s.objectIndex) + bf.WriteUint16(0) + obj := uint32(bf.Data()[3]) | uint32(bf.Data()[2])<<8 | uint32(bf.Data()[1])<<16 | uint32(bf.Data()[0])<<24 + return obj }