mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
rework stages
This commit is contained in:
@@ -183,10 +183,6 @@ func handleMsgSysLogin(s *Session, p mhfpacket.MHFPacket) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser {
|
||||
CharID: s.charID,
|
||||
}, s)
|
||||
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"erupe-ce/common/byteframe"
|
||||
ps "erupe-ce/common/pascalstring"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -15,7 +14,7 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.server.Lock()
|
||||
defer s.server.Unlock()
|
||||
if _, exists := s.server.stages[pkt.StageID]; exists {
|
||||
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
doAckSimpleFail(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
} else {
|
||||
stage := NewStage(pkt.StageID)
|
||||
stage.maxPlayers = uint16(pkt.PlayerCount)
|
||||
@@ -27,36 +26,33 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
// Remove this session from old stage clients list and put myself in the new one.
|
||||
s.server.stagesLock.Lock()
|
||||
newStage, gotNewStage := s.server.stages[stageID]
|
||||
s.server.stagesLock.Unlock()
|
||||
s.server.Lock()
|
||||
stage, exists := s.server.stages[stageID]
|
||||
s.server.Unlock()
|
||||
|
||||
if s.stage != nil {
|
||||
removeSessionFromStage(s)
|
||||
if exists {
|
||||
stage.Lock()
|
||||
stage.clients[s] = s.charID
|
||||
stage.Unlock()
|
||||
} else { // Create new stage object
|
||||
s.server.Lock()
|
||||
s.server.stages[stageID] = NewStage(stageID)
|
||||
stage = s.server.stages[stageID]
|
||||
s.server.Unlock()
|
||||
stage.Lock()
|
||||
stage.clients[s] = s.charID
|
||||
stage.Unlock()
|
||||
}
|
||||
|
||||
// Add the new stage.
|
||||
if gotNewStage {
|
||||
newStage.Lock()
|
||||
newStage.clients[s] = s.charID
|
||||
newStage.Unlock()
|
||||
} else {
|
||||
// Fix stages
|
||||
s.logger.Info("Fix Map Appliqued")
|
||||
s.server.stagesLock.Lock()
|
||||
s.server.stages[stageID] = NewStage(stageID)
|
||||
newStage = s.server.stages[stageID]
|
||||
s.server.stagesLock.Unlock()
|
||||
newStage.Lock()
|
||||
newStage.clients[s] = s.charID
|
||||
newStage.Unlock()
|
||||
// Ensure this session no longer belongs to reservations.
|
||||
if s.stage != nil {
|
||||
removeSessionFromStage(s)
|
||||
}
|
||||
|
||||
// Save our new stage ID and pointer to the new stage itself.
|
||||
s.Lock()
|
||||
s.stageID = string(stageID)
|
||||
s.stage = newStage
|
||||
s.stage = s.server.stages[stageID]
|
||||
s.Unlock()
|
||||
|
||||
// Tell the client to cleanup its current stage objects.
|
||||
@@ -65,138 +61,133 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
// Confirm the stage entry.
|
||||
doAckSimpleSucceed(s, ackHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
|
||||
// Notify existing stage clients that this new client has entered.
|
||||
if s.stage != nil { // avoids lock up when using bed for dream quests
|
||||
var pkt mhfpacket.MHFPacket
|
||||
|
||||
// Notify the entree client about all of the existing clients in the stage.
|
||||
s.logger.Info("Notifying entree about existing stage clients")
|
||||
|
||||
clientNotif := byteframe.NewByteFrame()
|
||||
s.server.Lock()
|
||||
s.server.BroadcastMHF(&mhfpacket.MsgSysDeleteUser{
|
||||
CharID: s.charID,
|
||||
}, s)
|
||||
s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser {
|
||||
CharID: s.charID,
|
||||
}, s)
|
||||
|
||||
for session := range s.server.sessions {
|
||||
session := s.server.sessions[session]
|
||||
|
||||
// Send existing players back to the client
|
||||
pkt = &mhfpacket.MsgSysInsertUser{
|
||||
CharID: session.charID,
|
||||
}
|
||||
clientNotif.WriteUint16(uint16(pkt.Opcode()))
|
||||
pkt.Build(clientNotif, session.clientContext)
|
||||
for i := 1; i <= 3; i++ {
|
||||
pkt = &mhfpacket.MsgSysNotifyUserBinary{
|
||||
CharID: session.charID,
|
||||
BinaryType: uint8(i),
|
||||
}
|
||||
clientNotif.WriteUint16(uint16(pkt.Opcode()))
|
||||
pkt.Build(clientNotif, session.clientContext)
|
||||
}
|
||||
}
|
||||
s.server.Unlock()
|
||||
clientNotif.WriteUint16(0x0010) // End it.
|
||||
s.QueueSend(clientNotif.Data())
|
||||
|
||||
// Notify the client to duplicate the existing objects.
|
||||
s.logger.Info("Notifying entree about existing stage objects")
|
||||
s.logger.Info("Sending existing stage objects")
|
||||
clientDupObjNotif := byteframe.NewByteFrame()
|
||||
s.stage.RLock()
|
||||
for _, obj := range s.stage.objects {
|
||||
cur := &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: obj.id,
|
||||
X: obj.x,
|
||||
Y: obj.y,
|
||||
Z: obj.z,
|
||||
Unk0: 0,
|
||||
OwnerCharID: obj.ownerCharID,
|
||||
}
|
||||
clientDupObjNotif.WriteUint16(uint16(cur.Opcode()))
|
||||
cur.Build(clientDupObjNotif, s.clientContext)
|
||||
cur := &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: obj.id,
|
||||
X: obj.x,
|
||||
Y: obj.y,
|
||||
Z: obj.z,
|
||||
Unk0: 0,
|
||||
OwnerCharID: obj.ownerCharID,
|
||||
}
|
||||
clientDupObjNotif.WriteUint16(uint16(cur.Opcode()))
|
||||
cur.Build(clientDupObjNotif, s.clientContext)
|
||||
}
|
||||
s.stage.RUnlock()
|
||||
clientDupObjNotif.WriteUint16(0x0010) // End it.
|
||||
s.QueueSend(clientDupObjNotif.Data())
|
||||
if len(clientDupObjNotif.Data()) > 2 {
|
||||
s.QueueSend(clientDupObjNotif.Data())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeEmptyStages(s *Session) {
|
||||
s.server.Lock()
|
||||
for sid, stage := range s.server.stages {
|
||||
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
|
||||
if strings.HasPrefix(sid, "sl1Qs") || strings.HasPrefix(sid, "sl2Qs") || strings.HasPrefix(sid, "sl3Qs") {
|
||||
delete(s.server.stages, sid)
|
||||
defer s.server.Unlock()
|
||||
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" {
|
||||
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
|
||||
delete(s.server.stages, stage.id)
|
||||
s.logger.Debug("Destructed stage", zap.String("stage.id", stage.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
s.server.Unlock()
|
||||
}
|
||||
|
||||
func removeSessionFromStage(s *Session) {
|
||||
s.stage.Lock()
|
||||
defer s.stage.Unlock()
|
||||
|
||||
// Remove client from old stage.
|
||||
s.stage.Lock()
|
||||
delete(s.stage.clients, s)
|
||||
delete(s.stage.reservedClientSlots, s.charID)
|
||||
|
||||
// Remove client from all reservations
|
||||
s.server.Lock()
|
||||
for _, stage := range s.server.stages {
|
||||
if _, exists := stage.reservedClientSlots[s.charID]; exists {
|
||||
delete(stage.reservedClientSlots, s.charID)
|
||||
}
|
||||
}
|
||||
s.server.Unlock()
|
||||
|
||||
// Delete old stage objects owned by the client.
|
||||
s.logger.Info("Sending MsgSysDeleteObject to old stage clients")
|
||||
s.logger.Info("Sending notification 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{
|
||||
clientNotif := byteframe.NewByteFrame()
|
||||
var pkt mhfpacket.MHFPacket
|
||||
pkt = &mhfpacket.MsgSysDeleteObject{
|
||||
ObjID: stageObject.id,
|
||||
}, s)
|
||||
}
|
||||
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 form the objects map.
|
||||
// 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
|
||||
// Added to prevent duplicates from flooding ObjectMap and causing server hangs
|
||||
s.stage.objectList[objListID].status = false
|
||||
s.stage.objectList[objListID].charid = 0
|
||||
}
|
||||
}
|
||||
|
||||
s.stage.Unlock()
|
||||
removeEmptyStages(s)
|
||||
}
|
||||
|
||||
|
||||
func handleMsgSysEnterStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysEnterStage)
|
||||
fmt.Printf("The Stage is %s\n",pkt.StageID)
|
||||
// Push our current stage ID to the movement stack before entering another one.
|
||||
s.Lock()
|
||||
s.stageMoveStack.Push(s.stageID)
|
||||
s.Unlock()
|
||||
|
||||
s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{})
|
||||
if s.reservationStage != nil {
|
||||
s.reservationStage = nil
|
||||
}
|
||||
|
||||
if pkt.StageID == "sl1Ns200p0a0u0" { // First entry
|
||||
s.server.BroadcastMHF(&mhfpacket.MsgSysInsertUser{
|
||||
CharID: s.charID,
|
||||
}, s)
|
||||
|
||||
var temp mhfpacket.MHFPacket
|
||||
loginNotif := byteframe.NewByteFrame()
|
||||
s.server.Lock()
|
||||
for _, session := range s.server.sessions {
|
||||
if s == session {
|
||||
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)
|
||||
}
|
||||
|
||||
func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysBackStage)
|
||||
|
||||
if s.stage != nil {
|
||||
removeSessionFromStage(s)
|
||||
}
|
||||
|
||||
// Transfer back to the saved stage ID before the previous move or enter.
|
||||
s.Lock()
|
||||
backStage, err := s.stageMoveStack.Pop()
|
||||
@@ -260,24 +251,17 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
} else if uint16(len(stage.reservedClientSlots)) < stage.maxPlayers {
|
||||
if len(stage.password) > 0 {
|
||||
// s.logger.Debug("", zap.String("stgpw", stage.password), zap.String("usrpw", s.stagePass))
|
||||
if stage.password == s.stagePass {
|
||||
stage.reservedClientSlots[s.charID] = false
|
||||
s.Lock()
|
||||
s.reservationStage = stage
|
||||
s.Unlock()
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
if stage.password != s.stagePass {
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
} else {
|
||||
stage.reservedClientSlots[s.charID] = false
|
||||
// Save the reservation stage in the session for later use in MsgSysUnreserveStage.
|
||||
s.Lock()
|
||||
s.reservationStage = stage
|
||||
s.Unlock()
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
stage.reservedClientSlots[s.charID] = false
|
||||
// Save the reservation stage in the session for later use in MsgSysUnreserveStage.
|
||||
s.Lock()
|
||||
s.reservationStage = stage
|
||||
s.Unlock()
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
} else {
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
@@ -308,12 +292,13 @@ func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.Unlock()
|
||||
if stage != nil {
|
||||
stage.Lock()
|
||||
// Will only exist if host.
|
||||
if _, exists := stage.reservedClientSlots[s.charID]; exists {
|
||||
stage.password = pkt.Password
|
||||
}
|
||||
stage.Unlock()
|
||||
} else {
|
||||
// Store for use on next ReserveStage
|
||||
// Store for use on next ReserveStage.
|
||||
s.Lock()
|
||||
s.stagePass = pkt.Password
|
||||
s.Unlock()
|
||||
@@ -322,66 +307,66 @@ func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgSysSetStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysSetStageBinary)
|
||||
|
||||
// Try to get the stage
|
||||
stageID := pkt.StageID
|
||||
s.server.stagesLock.Lock()
|
||||
stage, gotStage := s.server.stages[stageID]
|
||||
s.server.stagesLock.Unlock()
|
||||
|
||||
// If we got the stage, lock and set the data.
|
||||
if gotStage {
|
||||
if stage, exists := s.server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] = pkt.RawDataPayload
|
||||
stage.Unlock()
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", stageID))
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
|
||||
}
|
||||
s.logger.Debug("handleMsgSysSetStageBinary Done!")
|
||||
}
|
||||
|
||||
func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysGetStageBinary)
|
||||
|
||||
// Try to get the stage
|
||||
stageID := pkt.StageID
|
||||
s.server.stagesLock.Lock()
|
||||
stage, gotStage := s.server.stages[stageID]
|
||||
s.server.stagesLock.Unlock()
|
||||
|
||||
// If we got the stage, lock and try to get the data.
|
||||
var stageBinary []byte
|
||||
var gotBinary bool
|
||||
if gotStage {
|
||||
if stage, exists := s.server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
stageBinary, gotBinary = stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
|
||||
if binaryData, exists := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]; exists {
|
||||
doAckBufSucceed(s, pkt.AckHandle, binaryData)
|
||||
} else if pkt.BinaryType1 == 4 {
|
||||
// Unknown binary type that is supposedly generated server side
|
||||
// Temporary response
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1))
|
||||
s.logger.Warn("Sending blank stage binary")
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
||||
}
|
||||
stage.Unlock()
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", stageID))
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
|
||||
}
|
||||
|
||||
if gotBinary {
|
||||
doAckBufSucceed(s, pkt.AckHandle, stageBinary)
|
||||
|
||||
} else if pkt.BinaryType1 == 4 {
|
||||
// This particular type seems to be expecting data that isn't set
|
||||
// is it required before the party joining can be completed
|
||||
//s.QueueAck(pkt.AckHandle, []byte{0x01, 0x00, 0x00, 0x00, 0x10})
|
||||
|
||||
// TODO(Andoryuuta): This doesn't fit a normal ack packet? where is this from?
|
||||
// This would be a buffered(0x01), non-error(0x00), with no data payload (size 0x00, 0x00) packet.
|
||||
// but for some reason has a 0x10 on the end that the client shouldn't parse?
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{}) // Without the previous 0x10 suffix
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1))
|
||||
s.logger.Warn("Sending blank stage binary")
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
||||
}
|
||||
|
||||
s.logger.Debug("MsgSysGetStageBinary Done!")
|
||||
}
|
||||
|
||||
func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysWaitStageBinary)
|
||||
if stage, exists := s.server.stages[pkt.StageID]; exists {
|
||||
if pkt.BinaryType0 == 1 && pkt.BinaryType1 == 12 {
|
||||
// This might contain the hunter count, or max player count?
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
||||
return
|
||||
}
|
||||
for {
|
||||
s.logger.Debug("MsgSysWaitStageBinary before lock and get stage")
|
||||
stage.Lock()
|
||||
stageBinary, gotBinary := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
|
||||
stage.Unlock()
|
||||
s.logger.Debug("MsgSysWaitStageBinary after lock and get stage")
|
||||
if gotBinary {
|
||||
doAckBufSucceed(s, pkt.AckHandle, stageBinary)
|
||||
break
|
||||
} else {
|
||||
s.logger.Debug("Waiting stage binary", zap.Uint8("BinaryType0", pkt.BinaryType0), zap.Uint8("pkt.BinaryType1", pkt.BinaryType1))
|
||||
time.Sleep(1 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
|
||||
}
|
||||
s.logger.Debug("MsgSysWaitStageBinary Done!")
|
||||
}
|
||||
|
||||
func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysEnumerateStage)
|
||||
|
||||
@@ -409,14 +394,10 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
joinable++
|
||||
|
||||
resp.WriteUint16(uint16(len(stage.reservedClientSlots))) // Reserved players.
|
||||
resp.WriteUint16(0) // Unknown value
|
||||
|
||||
var hasDeparted uint16
|
||||
if stage.hasDeparted {
|
||||
hasDeparted = 1
|
||||
}
|
||||
resp.WriteUint16(hasDeparted) // HasDeparted.
|
||||
resp.WriteUint16(stage.maxPlayers) // Max players.
|
||||
resp.WriteUint16(0) // Unk
|
||||
resp.WriteUint8(0) // Unk
|
||||
resp.WriteBool(len(stage.clients) > 0) // Has departed.
|
||||
resp.WriteUint16(stage.maxPlayers) // Max players.
|
||||
if len(stage.password) > 0 {
|
||||
// This byte has also been seen as 1
|
||||
// The quest is also recognised as locked when this is 2
|
||||
|
||||
@@ -55,10 +55,9 @@ type Stage struct {
|
||||
// other clients expect the server to echo them back in the exact same format.
|
||||
rawBinaryData map[stageBinaryKey][]byte
|
||||
|
||||
maxPlayers uint16
|
||||
hasDeparted bool
|
||||
password string
|
||||
createdAt string
|
||||
maxPlayers uint16
|
||||
password string
|
||||
createdAt string
|
||||
}
|
||||
|
||||
// NewStage creates a new stage with intialized values.
|
||||
@@ -71,7 +70,7 @@ func NewStage(ID string) *Stage {
|
||||
rawBinaryData: make(map[stageBinaryKey][]byte),
|
||||
maxPlayers: 4,
|
||||
gameObjectCount: 1,
|
||||
objectList: make(map[uint8]*ObjectMap),
|
||||
objectList: make(map[uint8]*ObjectMap),
|
||||
createdAt: time.Now().Format("01-02-2006 15:04:05"),
|
||||
}
|
||||
s.InitObjectList()
|
||||
|
||||
Reference in New Issue
Block a user