mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-15 16:34:51 +01:00
stage as a /internal/system
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package channelserver
|
||||
package system
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -6,18 +6,24 @@ import (
|
||||
"erupe-ce/network/mhfpacket"
|
||||
)
|
||||
|
||||
type SessionStage interface {
|
||||
QueueSendMHF(packet mhfpacket.MHFPacket)
|
||||
GetCharID() uint32
|
||||
GetName() string
|
||||
}
|
||||
|
||||
// Object holds infomation about a specific object.
|
||||
type Object struct {
|
||||
sync.RWMutex
|
||||
id uint32
|
||||
ownerCharID uint32
|
||||
x, y, z float32
|
||||
Id uint32
|
||||
OwnerCharID uint32
|
||||
X, Y, Z float32
|
||||
}
|
||||
|
||||
// stageBinaryKey is a struct used as a map key for identifying a stage binary part.
|
||||
type stageBinaryKey struct {
|
||||
id0 uint8
|
||||
id1 uint8
|
||||
type StageBinaryKey struct {
|
||||
Id0 uint8
|
||||
Id1 uint8
|
||||
}
|
||||
|
||||
// Stage holds stage-specific information
|
||||
@@ -25,49 +31,49 @@ type Stage struct {
|
||||
sync.RWMutex
|
||||
|
||||
// Stage ID string
|
||||
id string
|
||||
Id string
|
||||
|
||||
// Objects
|
||||
objects map[uint32]*Object
|
||||
Objects map[uint32]*Object
|
||||
objectIndex uint8
|
||||
|
||||
// Map of session -> charID.
|
||||
// These are clients that are CURRENTLY in the stage
|
||||
clients map[*Session]uint32
|
||||
Clients map[SessionStage]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
|
||||
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
|
||||
RawBinaryData map[StageBinaryKey][]byte
|
||||
|
||||
host *Session
|
||||
maxPlayers uint16
|
||||
password string
|
||||
locked bool
|
||||
Host SessionStage
|
||||
MaxPlayers uint16
|
||||
Password string
|
||||
Locked bool
|
||||
}
|
||||
|
||||
// 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),
|
||||
Id: ID,
|
||||
Clients: make(map[SessionStage]uint32),
|
||||
ReservedClientSlots: make(map[uint32]bool),
|
||||
Objects: make(map[uint32]*Object),
|
||||
objectIndex: 0,
|
||||
rawBinaryData: make(map[stageBinaryKey][]byte),
|
||||
maxPlayers: 127,
|
||||
RawBinaryData: make(map[StageBinaryKey][]byte),
|
||||
MaxPlayers: 127,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// BroadcastMHF queues a MHFPacket to be sent to all sessions in the stage.
|
||||
func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
|
||||
func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession SessionStage) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for session := range s.clients {
|
||||
for session := range s.Clients {
|
||||
if session == ignoredSession {
|
||||
continue
|
||||
}
|
||||
@@ -76,13 +82,13 @@ func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
|
||||
}
|
||||
|
||||
func (s *Stage) isCharInQuestByID(charID uint32) bool {
|
||||
if _, exists := s.reservedClientSlots[charID]; exists {
|
||||
if _, exists := s.ReservedClientSlots[charID]; exists {
|
||||
return exists
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Stage) isQuest() bool {
|
||||
return len(s.reservedClientSlots) > 0
|
||||
func (s *Stage) IsQuest() bool {
|
||||
return len(s.ReservedClientSlots) > 0
|
||||
}
|
||||
@@ -146,11 +146,11 @@ func psn(s *Session, args []string) error {
|
||||
func reload(s *Session, _ []string) error {
|
||||
s.sendMessage(t("commands.reload", v{}))
|
||||
var temp mhfpacket.MHFPacket
|
||||
for _, object := range s.stage.objects {
|
||||
if object.ownerCharID == s.CharID {
|
||||
for _, object := range s.stage.Objects {
|
||||
if object.OwnerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.id}
|
||||
temp = &mhfpacket.MsgSysDeleteObject{ObjID: object.Id}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
for _, session := range s.Server.sessions {
|
||||
@@ -175,17 +175,17 @@ func reload(s *Session, _ []string) error {
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
}
|
||||
for _, obj := range s.stage.objects {
|
||||
if obj.ownerCharID == s.CharID {
|
||||
for _, obj := range s.stage.Objects {
|
||||
if obj.OwnerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: obj.id,
|
||||
X: obj.x,
|
||||
Y: obj.y,
|
||||
Z: obj.z,
|
||||
ObjID: obj.Id,
|
||||
X: obj.X,
|
||||
Y: obj.Y,
|
||||
Z: obj.Z,
|
||||
Unk0: 0,
|
||||
OwnerCharID: obj.ownerCharID,
|
||||
OwnerCharID: obj.OwnerCharID,
|
||||
}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/binary"
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/internal/model"
|
||||
"erupe-ce/internal/system"
|
||||
"erupe-ce/utils/db"
|
||||
"erupe-ce/utils/gametime"
|
||||
"erupe-ce/utils/mhfcourse"
|
||||
@@ -155,18 +156,18 @@ 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 {
|
||||
if stage.Host != nil && stage.Host.GetCharID() == 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" {
|
||||
for rSlot := range stage.ReservedClientSlots {
|
||||
if sess.CharID == rSlot && sess.stage != nil && sess.stage.Id[3:5] != "Qs" {
|
||||
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for session := range stage.clients {
|
||||
if session.CharID == s.CharID {
|
||||
delete(stage.clients, session)
|
||||
for session := range stage.Clients {
|
||||
if session.GetCharID() == s.CharID {
|
||||
delete(stage.Clients, session)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,8 +212,8 @@ func logoutPlayer(s *Session) {
|
||||
|
||||
s.Server.Lock()
|
||||
for _, stage := range s.Server.stages {
|
||||
if _, exists := stage.reservedClientSlots[s.CharID]; exists {
|
||||
delete(stage.reservedClientSlots, s.CharID)
|
||||
if _, exists := stage.ReservedClientSlots[s.CharID]; exists {
|
||||
delete(stage.ReservedClientSlots, s.CharID)
|
||||
}
|
||||
}
|
||||
s.Server.Unlock()
|
||||
@@ -285,7 +286,7 @@ func handleMsgSysRecordLog(s *Session, db *sqlx.DB, 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)
|
||||
delete(s.stage.ReservedClientSlots, s.CharID)
|
||||
s.DoAckSimpleSucceed(pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
@@ -377,12 +378,12 @@ func handleMsgMhfTransitMessage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
if pkt.SearchType == 2 && !strings.Contains(session.Name, term) {
|
||||
continue
|
||||
}
|
||||
if pkt.SearchType == 3 && session.Server.IP != ip && session.Server.Port != port && session.stage.id != term {
|
||||
if pkt.SearchType == 3 && session.Server.IP != ip && session.Server.Port != port && session.stage.Id != term {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
sessionName := stringsupport.UTF8ToSJIS(session.Name)
|
||||
sessionStage := stringsupport.UTF8ToSJIS(session.stage.id)
|
||||
sessionStage := stringsupport.UTF8ToSJIS(session.stage.Id)
|
||||
if !local {
|
||||
resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
|
||||
} else {
|
||||
@@ -497,8 +498,8 @@ func handleMsgMhfTransitMessage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
if count == maxResults {
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(stage.id, findPartyParams.StagePrefix) {
|
||||
sb3 := byteframe.NewByteFrameFromBytes(stage.rawBinaryData[stageBinaryKey{1, 3}])
|
||||
if strings.HasPrefix(stage.Id, findPartyParams.StagePrefix) {
|
||||
sb3 := byteframe.NewByteFrameFromBytes(stage.RawBinaryData[system.StageBinaryKey{1, 3}])
|
||||
sb3.Seek(4, 0)
|
||||
|
||||
stageDataParams := 7
|
||||
@@ -546,17 +547,17 @@ func handleMsgMhfTransitMessage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
|
||||
resp.WriteUint16(0) // Static?
|
||||
resp.WriteUint16(0) // Unk, [0 1 2]
|
||||
resp.WriteUint16(uint16(len(stage.clients) + len(stage.reservedClientSlots)))
|
||||
resp.WriteUint16(stage.maxPlayers)
|
||||
resp.WriteUint16(uint16(len(stage.Clients) + len(stage.ReservedClientSlots)))
|
||||
resp.WriteUint16(stage.MaxPlayers)
|
||||
// TODO: Retail returned the number of clients in quests, not workshop/my series
|
||||
resp.WriteUint16(uint16(len(stage.reservedClientSlots)))
|
||||
resp.WriteUint16(uint16(len(stage.ReservedClientSlots)))
|
||||
|
||||
resp.WriteUint8(0) // Static?
|
||||
resp.WriteUint8(uint8(stage.maxPlayers))
|
||||
resp.WriteUint8(uint8(stage.MaxPlayers))
|
||||
resp.WriteUint8(1) // Static?
|
||||
resp.WriteUint8(uint8(len(stage.id) + 1))
|
||||
resp.WriteUint8(uint8(len(stage.rawBinaryData[stageBinaryKey{1, 0}])))
|
||||
resp.WriteUint8(uint8(len(stage.rawBinaryData[stageBinaryKey{1, 1}])))
|
||||
resp.WriteUint8(uint8(len(stage.Id) + 1))
|
||||
resp.WriteUint8(uint8(len(stage.RawBinaryData[system.StageBinaryKey{1, 0}])))
|
||||
resp.WriteUint8(uint8(len(stage.RawBinaryData[system.StageBinaryKey{1, 1}])))
|
||||
|
||||
for i := range stageData {
|
||||
if config.GetConfig().ClientID >= config.Z1 {
|
||||
@@ -568,9 +569,9 @@ func handleMsgMhfTransitMessage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
resp.WriteUint8(0) // Unk
|
||||
resp.WriteUint8(0) // Unk
|
||||
|
||||
resp.WriteNullTerminatedBytes([]byte(stage.id))
|
||||
resp.WriteBytes(stage.rawBinaryData[stageBinaryKey{1, 0}])
|
||||
resp.WriteBytes(stage.rawBinaryData[stageBinaryKey{1, 1}])
|
||||
resp.WriteNullTerminatedBytes([]byte(stage.Id))
|
||||
resp.WriteBytes(stage.RawBinaryData[system.StageBinaryKey{1, 0}])
|
||||
resp.WriteBytes(stage.RawBinaryData[system.StageBinaryKey{1, 1}])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ func handleMsgSysCastBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
return
|
||||
}
|
||||
if (pkt.BroadcastType == constant.BroadcastTypeStage && s.stage.id == "sl1Ns200p0a0u0") || pkt.BroadcastType == constant.BroadcastTypeWorld {
|
||||
if (pkt.BroadcastType == constant.BroadcastTypeStage && s.stage.Id == "sl1Ns200p0a0u0") || pkt.BroadcastType == constant.BroadcastTypeWorld {
|
||||
s.Server.DiscordChannelSend(chatMessage.SenderName, chatMessage.Message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,20 +28,20 @@ func handleMsgSysEnumerateClient(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
var clients []uint32
|
||||
switch pkt.Get {
|
||||
case 0: // All
|
||||
for _, cid := range stage.clients {
|
||||
for _, cid := range stage.Clients {
|
||||
clients = append(clients, cid)
|
||||
}
|
||||
for cid := range stage.reservedClientSlots {
|
||||
for cid := range stage.ReservedClientSlots {
|
||||
clients = append(clients, cid)
|
||||
}
|
||||
case 1: // Not ready
|
||||
for cid, ready := range stage.reservedClientSlots {
|
||||
for cid, ready := range stage.ReservedClientSlots {
|
||||
if !ready {
|
||||
clients = append(clients, cid)
|
||||
}
|
||||
}
|
||||
case 2: // Ready
|
||||
for cid, ready := range stage.reservedClientSlots {
|
||||
for cid, ready := range stage.ReservedClientSlots {
|
||||
if ready {
|
||||
clients = append(clients, cid)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/internal/system"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"erupe-ce/utils/byteframe"
|
||||
|
||||
@@ -14,30 +15,30 @@ func handleMsgSysCreateObject(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysCreateObject)
|
||||
|
||||
s.stage.Lock()
|
||||
newObj := &Object{
|
||||
id: s.NextObjectID(),
|
||||
ownerCharID: s.CharID,
|
||||
x: pkt.X,
|
||||
y: pkt.Y,
|
||||
z: pkt.Z,
|
||||
newObj := &system.Object{
|
||||
Id: s.NextObjectID(),
|
||||
OwnerCharID: s.CharID,
|
||||
X: pkt.X,
|
||||
Y: pkt.Y,
|
||||
Z: pkt.Z,
|
||||
}
|
||||
s.stage.objects[s.CharID] = newObj
|
||||
s.stage.Objects[s.CharID] = newObj
|
||||
s.stage.Unlock()
|
||||
|
||||
// Response to our requesting client.
|
||||
resp := byteframe.NewByteFrame()
|
||||
resp.WriteUint32(newObj.id) // New local obj handle.
|
||||
resp.WriteUint32(newObj.Id) // New local obj handle.
|
||||
s.DoAckSimpleSucceed(pkt.AckHandle, resp.Data())
|
||||
// Duplicate the object creation to all sessions in the same stage.
|
||||
dupObjUpdate := &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: newObj.id,
|
||||
X: newObj.x,
|
||||
Y: newObj.y,
|
||||
Z: newObj.z,
|
||||
OwnerCharID: newObj.ownerCharID,
|
||||
ObjID: newObj.Id,
|
||||
X: newObj.X,
|
||||
Y: newObj.Y,
|
||||
Z: newObj.Z,
|
||||
OwnerCharID: newObj.OwnerCharID,
|
||||
}
|
||||
|
||||
s.Logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, newObj.id))
|
||||
s.Logger.Info(fmt.Sprintf("Broadcasting new object: %s (%d)", s.Name, newObj.Id))
|
||||
s.stage.BroadcastMHF(dupObjUpdate, s)
|
||||
}
|
||||
|
||||
@@ -49,11 +50,11 @@ func handleMsgSysPositionObject(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
fmt.Printf("[%s] with objectID [%d] move to (%f,%f,%f)\n\n", s.Name, pkt.ObjID, pkt.X, pkt.Y, pkt.Z)
|
||||
}
|
||||
s.stage.Lock()
|
||||
object, ok := s.stage.objects[s.CharID]
|
||||
object, ok := s.stage.Objects[s.CharID]
|
||||
if ok {
|
||||
object.x = pkt.X
|
||||
object.y = pkt.Y
|
||||
object.z = pkt.Z
|
||||
object.X = pkt.X
|
||||
object.Y = pkt.Y
|
||||
object.Z = pkt.Z
|
||||
}
|
||||
s.stage.Unlock()
|
||||
// One of the few packets we can just re-broadcast directly.
|
||||
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"erupe-ce/internal/system"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"erupe-ce/utils/byteframe"
|
||||
|
||||
ps "erupe-ce/utils/pascalstring"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
@@ -20,10 +22,10 @@ func handleMsgSysCreateStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
if _, exists := s.Server.stages[pkt.StageID]; exists {
|
||||
s.DoAckSimpleFail(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
} else {
|
||||
stage := NewStage(pkt.StageID)
|
||||
stage.host = s
|
||||
stage.maxPlayers = uint16(pkt.PlayerCount)
|
||||
s.Server.stages[stage.id] = stage
|
||||
stage := system.NewStage(pkt.StageID)
|
||||
stage.Host = s
|
||||
stage.MaxPlayers = uint16(pkt.PlayerCount)
|
||||
s.Server.stages[stage.Id] = stage
|
||||
s.DoAckSimpleSucceed(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
}
|
||||
}
|
||||
@@ -37,16 +39,16 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
|
||||
if exists {
|
||||
stage.Lock()
|
||||
stage.clients[s] = s.CharID
|
||||
stage.Clients[s] = s.CharID
|
||||
stage.Unlock()
|
||||
} else { // Create new stage object
|
||||
s.Server.Lock()
|
||||
s.Server.stages[stageID] = NewStage(stageID)
|
||||
s.Server.stages[stageID] = system.NewStage(stageID)
|
||||
stage = s.Server.stages[stageID]
|
||||
s.Server.Unlock()
|
||||
stage.Lock()
|
||||
stage.host = s
|
||||
stage.clients[s] = s.CharID
|
||||
stage.Host = s
|
||||
stage.Clients[s] = s.CharID
|
||||
stage.Unlock()
|
||||
}
|
||||
|
||||
@@ -92,17 +94,17 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
// Notify the client to duplicate the existing objects.
|
||||
s.Logger.Info(fmt.Sprintf("Sending existing stage objects to %s", s.Name))
|
||||
s.stage.RLock()
|
||||
for _, obj := range s.stage.objects {
|
||||
if obj.ownerCharID == s.CharID {
|
||||
for _, obj := range s.stage.Objects {
|
||||
if obj.OwnerCharID == s.CharID {
|
||||
continue
|
||||
}
|
||||
temp = &mhfpacket.MsgSysDuplicateObject{
|
||||
ObjID: obj.id,
|
||||
X: obj.x,
|
||||
Y: obj.y,
|
||||
Z: obj.z,
|
||||
ObjID: obj.Id,
|
||||
X: obj.X,
|
||||
Y: obj.Y,
|
||||
Z: obj.Z,
|
||||
Unk0: 0,
|
||||
OwnerCharID: obj.ownerCharID,
|
||||
OwnerCharID: obj.OwnerCharID,
|
||||
}
|
||||
s.QueueSendMHF(temp)
|
||||
}
|
||||
@@ -115,10 +117,10 @@ func destructEmptyStages(s *Session) {
|
||||
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" || stage.id[3:5] == "Ls" {
|
||||
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))
|
||||
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 {
|
||||
delete(s.Server.stages, stage.Id)
|
||||
s.Logger.Debug("Destructed stage", zap.String("stage.id", stage.Id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,14 +128,14 @@ func destructEmptyStages(s *Session) {
|
||||
|
||||
func removeSessionFromStage(s *Session) {
|
||||
// Remove client from old stage.
|
||||
delete(s.stage.clients, s)
|
||||
delete(s.stage.Clients, s)
|
||||
|
||||
// Delete old stage objects owned by the client.
|
||||
s.Logger.Info("Sending notification to old stage clients")
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
destructEmptyStages(s)
|
||||
@@ -142,10 +144,10 @@ func removeSessionFromStage(s *Session) {
|
||||
|
||||
func isStageFull(s *Session, StageID string) bool {
|
||||
if stage, exists := s.Server.stages[StageID]; exists {
|
||||
if _, exists := stage.reservedClientSlots[s.CharID]; exists {
|
||||
if _, exists := stage.ReservedClientSlots[s.CharID]; exists {
|
||||
return false
|
||||
}
|
||||
return len(stage.reservedClientSlots)+len(stage.clients) >= int(stage.maxPlayers)
|
||||
return len(stage.ReservedClientSlots)+len(stage.Clients) >= int(stage.MaxPlayers)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -161,9 +163,9 @@ func handleMsgSysEnterStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
// Push our current stage ID to the movement stack before entering another one.
|
||||
if s.stage != nil {
|
||||
s.stage.Lock()
|
||||
s.stage.reservedClientSlots[s.CharID] = false
|
||||
s.stage.ReservedClientSlots[s.CharID] = false
|
||||
s.stage.Unlock()
|
||||
s.stageMoveStack.Push(s.stage.id)
|
||||
s.stageMoveStack.Push(s.stage.Id)
|
||||
}
|
||||
|
||||
if s.reservationStage != nil {
|
||||
@@ -188,12 +190,12 @@ func handleMsgSysBackStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, exists := s.stage.reservedClientSlots[s.CharID]; exists {
|
||||
delete(s.stage.reservedClientSlots, s.CharID)
|
||||
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)
|
||||
if _, exists := s.Server.stages[backStage].ReservedClientSlots[s.CharID]; exists {
|
||||
delete(s.Server.stages[backStage].ReservedClientSlots, s.CharID)
|
||||
}
|
||||
|
||||
doStageTransfer(s, pkt.AckHandle, backStage)
|
||||
@@ -216,7 +218,7 @@ func handleMsgSysLockStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysLockStage)
|
||||
if stage, exists := s.Server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
stage.locked = true
|
||||
stage.Locked = true
|
||||
stage.Unlock()
|
||||
}
|
||||
s.DoAckSimpleSucceed(pkt.AckHandle, make([]byte, 4))
|
||||
@@ -227,14 +229,14 @@ func handleMsgSysUnlockStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
s.reservationStage.RLock()
|
||||
defer s.reservationStage.RUnlock()
|
||||
|
||||
for charID := range s.reservationStage.reservedClientSlots {
|
||||
for charID := range s.reservationStage.ReservedClientSlots {
|
||||
session := s.Server.FindSessionByCharID(charID)
|
||||
if session != nil {
|
||||
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
}
|
||||
|
||||
delete(s.Server.stages, s.reservationStage.id)
|
||||
delete(s.Server.stages, s.reservationStage.Id)
|
||||
}
|
||||
|
||||
destructEmptyStages(s)
|
||||
@@ -245,26 +247,26 @@ func handleMsgSysReserveStage(s *Session, db *sqlx.DB, 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 _, exists := stage.ReservedClientSlots[s.CharID]; exists {
|
||||
switch pkt.Ready {
|
||||
case 1: // 0x01
|
||||
stage.reservedClientSlots[s.CharID] = false
|
||||
stage.ReservedClientSlots[s.CharID] = false
|
||||
case 17: // 0x11
|
||||
stage.reservedClientSlots[s.CharID] = true
|
||||
stage.ReservedClientSlots[s.CharID] = true
|
||||
}
|
||||
s.DoAckSimpleSucceed(pkt.AckHandle, make([]byte, 4))
|
||||
} else if uint16(len(stage.reservedClientSlots)) < stage.maxPlayers {
|
||||
if stage.locked {
|
||||
} else if uint16(len(stage.ReservedClientSlots)) < stage.MaxPlayers {
|
||||
if stage.Locked {
|
||||
s.DoAckSimpleFail(pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
if len(stage.password) > 0 {
|
||||
if stage.password != s.stagePass {
|
||||
if len(stage.Password) > 0 {
|
||||
if stage.Password != s.stagePass {
|
||||
s.DoAckSimpleFail(pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
}
|
||||
stage.reservedClientSlots[s.CharID] = false
|
||||
stage.ReservedClientSlots[s.CharID] = false
|
||||
// Save the reservation stage in the session for later use in MsgSysUnreserveStage.
|
||||
s.Lock()
|
||||
s.reservationStage = stage
|
||||
@@ -286,8 +288,8 @@ func handleMsgSysUnreserveStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
s.Unlock()
|
||||
if stage != nil {
|
||||
stage.Lock()
|
||||
if _, exists := stage.reservedClientSlots[s.CharID]; exists {
|
||||
delete(stage.reservedClientSlots, s.CharID)
|
||||
if _, exists := stage.ReservedClientSlots[s.CharID]; exists {
|
||||
delete(stage.ReservedClientSlots, s.CharID)
|
||||
}
|
||||
stage.Unlock()
|
||||
}
|
||||
@@ -301,8 +303,8 @@ func handleMsgSysSetStagePass(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket) {
|
||||
if stage != nil {
|
||||
stage.Lock()
|
||||
// Will only exist if host.
|
||||
if _, exists := stage.reservedClientSlots[s.CharID]; exists {
|
||||
stage.password = pkt.Password
|
||||
if _, exists := stage.ReservedClientSlots[s.CharID]; exists {
|
||||
stage.Password = pkt.Password
|
||||
}
|
||||
stage.Unlock()
|
||||
} else {
|
||||
@@ -317,7 +319,7 @@ func handleMsgSysSetStageBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
pkt := p.(*mhfpacket.MsgSysSetStageBinary)
|
||||
if stage, exists := s.Server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] = pkt.RawDataPayload
|
||||
stage.RawBinaryData[system.StageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}] = pkt.RawDataPayload
|
||||
stage.Unlock()
|
||||
} else {
|
||||
s.Logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
|
||||
@@ -328,7 +330,7 @@ func handleMsgSysGetStageBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
pkt := p.(*mhfpacket.MsgSysGetStageBinary)
|
||||
if stage, exists := s.Server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
if binaryData, exists := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]; exists {
|
||||
if binaryData, exists := stage.RawBinaryData[system.StageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]; exists {
|
||||
s.DoAckBufSucceed(pkt.AckHandle, binaryData)
|
||||
} else if pkt.BinaryType1 == 4 {
|
||||
// Unknown binary type that is supposedly generated server side
|
||||
@@ -357,7 +359,7 @@ func handleMsgSysWaitStageBinary(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
for {
|
||||
s.Logger.Debug("MsgSysWaitStageBinary before lock and get stage")
|
||||
stage.Lock()
|
||||
stageBinary, gotBinary := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
|
||||
stageBinary, gotBinary := stage.RawBinaryData[system.StageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
|
||||
stage.Unlock()
|
||||
s.Logger.Debug("MsgSysWaitStageBinary after lock and get stage")
|
||||
if gotBinary {
|
||||
@@ -389,29 +391,29 @@ func handleMsgSysEnumerateStage(s *Session, db *sqlx.DB, p mhfpacket.MHFPacket)
|
||||
for sid, stage := range s.Server.stages {
|
||||
stage.RLock()
|
||||
|
||||
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
|
||||
if len(stage.ReservedClientSlots) == 0 && len(stage.Clients) == 0 {
|
||||
stage.RUnlock()
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(stage.id, pkt.StagePrefix) {
|
||||
if !strings.Contains(stage.Id, pkt.StagePrefix) {
|
||||
stage.RUnlock()
|
||||
continue
|
||||
}
|
||||
joinable++
|
||||
|
||||
bf.WriteUint16(uint16(len(stage.reservedClientSlots)))
|
||||
bf.WriteUint16(uint16(len(stage.clients)))
|
||||
if strings.HasPrefix(stage.id, "sl2Ls") {
|
||||
bf.WriteUint16(uint16(len(stage.clients) + len(stage.reservedClientSlots)))
|
||||
bf.WriteUint16(uint16(len(stage.ReservedClientSlots)))
|
||||
bf.WriteUint16(uint16(len(stage.Clients)))
|
||||
if strings.HasPrefix(stage.Id, "sl2Ls") {
|
||||
bf.WriteUint16(uint16(len(stage.Clients) + len(stage.ReservedClientSlots)))
|
||||
} else {
|
||||
bf.WriteUint16(uint16(len(stage.clients)))
|
||||
bf.WriteUint16(uint16(len(stage.Clients)))
|
||||
}
|
||||
bf.WriteUint16(stage.maxPlayers)
|
||||
bf.WriteUint16(stage.MaxPlayers)
|
||||
var flags uint8
|
||||
if stage.locked {
|
||||
if stage.Locked {
|
||||
flags |= 1
|
||||
}
|
||||
if len(stage.password) > 0 {
|
||||
if len(stage.Password) > 0 {
|
||||
flags |= 2
|
||||
}
|
||||
bf.WriteUint8(flags)
|
||||
|
||||
@@ -7,8 +7,10 @@ import (
|
||||
"time"
|
||||
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/internal/system"
|
||||
"erupe-ce/server/discordbot"
|
||||
"erupe-ce/utils/db"
|
||||
|
||||
"erupe-ce/utils/gametime"
|
||||
"erupe-ce/utils/logger"
|
||||
|
||||
@@ -47,7 +49,7 @@ type ChannelServer struct {
|
||||
isShuttingDown bool
|
||||
|
||||
stagesLock sync.RWMutex
|
||||
stages map[string]*Stage
|
||||
stages map[string]*system.Stage
|
||||
|
||||
// Used to map different languages
|
||||
i18n i18n
|
||||
@@ -82,9 +84,9 @@ func NewServer(config *Config) *ChannelServer {
|
||||
"sl2Ns379p0a0u0", // Diva fountain
|
||||
"sl1Ns462p0a0u0", // MezFes
|
||||
}
|
||||
stages := make(map[string]*Stage)
|
||||
stages := make(map[string]*system.Stage)
|
||||
for _, name := range stageNames {
|
||||
stages[name] = NewStage(name)
|
||||
stages[name] = system.NewStage(name)
|
||||
}
|
||||
server := &ChannelServer{
|
||||
ID: config.ID,
|
||||
@@ -228,14 +230,14 @@ func (server *ChannelServer) DisconnectUser(uid uint32) {
|
||||
}
|
||||
}
|
||||
|
||||
func (server *ChannelServer) FindObjectByChar(charID uint32) *Object {
|
||||
func (server *ChannelServer) FindObjectByChar(charID uint32) *system.Object {
|
||||
server.stagesLock.RLock()
|
||||
defer server.stagesLock.RUnlock()
|
||||
for _, stage := range server.stages {
|
||||
stage.RLock()
|
||||
for objId := range stage.objects {
|
||||
obj := stage.objects[objId]
|
||||
if obj.ownerCharID == charID {
|
||||
for objId := range stage.Objects {
|
||||
obj := stage.Objects[objId]
|
||||
if obj.OwnerCharID == charID {
|
||||
stage.RUnlock()
|
||||
return obj
|
||||
}
|
||||
|
||||
@@ -22,17 +22,17 @@ func getPlayerSlice(server *ChannelServer) []Player {
|
||||
|
||||
for _, channel := range server.Channels {
|
||||
for _, stage := range channel.stages {
|
||||
if len(stage.clients) == 0 {
|
||||
if len(stage.Clients) == 0 {
|
||||
continue
|
||||
}
|
||||
questID := 0
|
||||
if stage.isQuest() {
|
||||
if stage.IsQuest() {
|
||||
questIndex++
|
||||
questID = questIndex
|
||||
}
|
||||
for client := range stage.clients {
|
||||
for client := range stage.Clients {
|
||||
p = append(p, Player{
|
||||
CharName: client.Name,
|
||||
CharName: client.GetName(),
|
||||
QuestID: questID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/internal/constant"
|
||||
"erupe-ce/internal/system"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/binpacket"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
@@ -36,10 +37,10 @@ type Session struct {
|
||||
|
||||
objectIndex uint16
|
||||
userEnteredStage bool // If the user has entered a stage before
|
||||
stage *Stage
|
||||
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
|
||||
stagePass string // Temporary storage
|
||||
prevGuildID uint32 // Stores the last GuildID used in InfoGuild
|
||||
stage *system.Stage
|
||||
reservationStage *system.Stage // Required for the stateful MsgSysUnreserveStage packet.
|
||||
stagePass string // Temporary storage
|
||||
prevGuildID uint32 // Stores the last GuildID used in InfoGuild
|
||||
CharID uint32
|
||||
logKey []byte
|
||||
sessionStart int64
|
||||
@@ -371,3 +372,9 @@ func (s *Session) DoAckSimpleFail(ackHandle uint32, data []byte) {
|
||||
AckData: data,
|
||||
})
|
||||
}
|
||||
func (s *Session) GetCharID() uint32 {
|
||||
return s.CharID // Assuming `Session` has a field `CharID`
|
||||
}
|
||||
func (s *Session) GetName() string {
|
||||
return s.Name // Assuming `Session` has a field `CharID`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user