further mutex/stage rework

This commit is contained in:
wish
2023-11-13 23:12:25 +11:00
parent e24c432d69
commit 85eb9fe99c
11 changed files with 102 additions and 143 deletions

View File

@@ -3,7 +3,6 @@ package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/common/bfutil"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/network/clientctx" "erupe-ce/network/clientctx"
) )
@@ -26,8 +25,8 @@ func (m *MsgSysCreateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8() m.Unk0 = bf.ReadUint8()
m.PlayerCount = bf.ReadUint8() m.PlayerCount = bf.ReadUint8()
stageIDLength := bf.ReadUint8() _ = bf.ReadUint8() // Length StageID
m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) m.StageID = string(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -4,7 +4,6 @@ import (
"errors" "errors"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/common/bfutil"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/network/clientctx" "erupe-ce/network/clientctx"
) )
@@ -12,7 +11,7 @@ import (
// MsgSysEnterStage represents the MSG_SYS_ENTER_STAGE // MsgSysEnterStage represents the MSG_SYS_ENTER_STAGE
type MsgSysEnterStage struct { type MsgSysEnterStage struct {
AckHandle uint32 AckHandle uint32
UnkBool uint8 Unk bool
StageID string StageID string
} }
@@ -24,9 +23,9 @@ func (m *MsgSysEnterStage) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.UnkBool = bf.ReadUint8() m.Unk = bf.ReadBool() // IsQuest?
stageIDLength := bf.ReadUint8() _ = bf.ReadUint8() // Length StageID
m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength)))) m.StageID = string(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -12,7 +12,6 @@ import (
// MsgSysEnumerateStage represents the MSG_SYS_ENUMERATE_STAGE // MsgSysEnumerateStage represents the MSG_SYS_ENUMERATE_STAGE
type MsgSysEnumerateStage struct { type MsgSysEnumerateStage struct {
AckHandle uint32 AckHandle uint32
Unk0 uint8 // Hardcoded 1 in the binary
StagePrefix string // NULL terminated string. StagePrefix string // NULL terminated string.
} }
@@ -24,8 +23,8 @@ func (m *MsgSysEnumerateStage) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgSysEnumerateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysEnumerateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8() _ = bf.ReadUint8() // Always 1
bf.ReadUint8() _ = bf.ReadUint8() // Prefix length
m.StagePrefix = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) m.StagePrefix = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -1,20 +1,17 @@
package mhfpacket package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
) )
// MsgSysLockStage represents the MSG_SYS_LOCK_STAGE // MsgSysLockStage represents the MSG_SYS_LOCK_STAGE
type MsgSysLockStage struct { type MsgSysLockStage struct {
AckHandle uint32 AckHandle uint32
Unk0 uint8 // Hardcoded 1 in the binary StageID string
Unk1 uint8 // Hardcoded 1 in the binary
StageIDLength uint8
StageID string
} }
// Opcode returns the ID associated with this packet type. // 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 // Parse parses the packet from binary
func (m *MsgSysLockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysLockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.AckHandle = bf.ReadUint32() m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint8() _ = bf.ReadUint8() // Always 1
m.Unk1 = bf.ReadUint8() _ = bf.ReadUint8() // Always 1
m.StageIDLength = bf.ReadUint8() _ = bf.ReadUint8() // Length StageID
m.StageID = string(bf.ReadBytes(uint(m.StageIDLength))) m.StageID = string(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -1,15 +1,14 @@
package mhfpacket package mhfpacket
import ( import (
"errors"
"erupe-ce/common/byteframe"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/network/clientctx" "erupe-ce/network/clientctx"
"erupe-ce/common/byteframe"
) )
// MsgSysUnlockStage represents the MSG_SYS_UNLOCK_STAGE // MsgSysUnlockStage represents the MSG_SYS_UNLOCK_STAGE
type MsgSysUnlockStage struct { type MsgSysUnlockStage struct{}
Unk0 uint16 // Hardcoded 0 in the binary.
}
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
func (m *MsgSysUnlockStage) Opcode() network.PacketID { func (m *MsgSysUnlockStage) Opcode() network.PacketID {
@@ -18,12 +17,11 @@ func (m *MsgSysUnlockStage) Opcode() network.PacketID {
// Parse parses the packet from binary // Parse parses the packet from binary
func (m *MsgSysUnlockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysUnlockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
m.Unk0 = bf.ReadUint16() _ = bf.ReadUint16() // Always zero
return nil return nil
} }
// Build builds a binary packet from the current data. // Build builds a binary packet from the current data.
func (m *MsgSysUnlockStage) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error { func (m *MsgSysUnlockStage) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
bf.WriteUint16(m.Unk0) return errors.New("NOT IMPLEMENTED")
return nil
} }

View File

@@ -190,11 +190,9 @@ func logoutPlayer(s *Session) {
for _, stage := range s.server.stages { for _, stage := range s.server.stages {
// Tell sessions registered to disconnecting players quest to unregister // Tell sessions registered to disconnecting players quest to unregister
if stage.host != nil && stage.host.charID == s.charID { if stage.host != nil && stage.host.charID == s.charID {
for _, sess := range s.server.sessions { for _, sess := range stage.ReservedSessions(s) {
for rSlot := range stage.reservedClientSlots { if sess.stage != nil && sess.stage.id[3:5] != "Qs" {
if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" { sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
}
} }
} }
} }
@@ -243,14 +241,6 @@ func logoutPlayer(s *Session) {
CharID: s.charID, CharID: s.charID,
}, s) }, 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) removeSessionFromSemaphore(s)
removeSessionFromStage(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)) doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
@@ -378,7 +366,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
if session.charID == CharID { if session.charID == CharID {
count++ count++
sessionName := stringsupport.UTF8ToSJIS(session.Name) 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.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
resp.WriteUint16(c.Port) resp.WriteUint16(c.Port)
resp.WriteUint32(session.charID) resp.WriteUint32(session.charID)
@@ -408,7 +396,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
if strings.Contains(session.Name, searchTerm) { if strings.Contains(session.Name, searchTerm) {
count++ count++
sessionName := stringsupport.UTF8ToSJIS(session.Name) 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.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
resp.WriteUint16(c.Port) resp.WriteUint16(c.Port)
resp.WriteUint32(session.charID) resp.WriteUint32(session.charID)
@@ -445,7 +433,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
hrp := uint16(1) hrp := uint16(1)
gr := uint16(0) gr := uint16(0)
s.server.db.QueryRow("SELECT hrp, gr FROM characters WHERE id=$1", session.charID).Scan(&hrp, &gr) 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) sessionName := stringsupport.UTF8ToSJIS(session.Name)
resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4())) resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
resp.WriteUint16(c.Port) resp.WriteUint16(c.Port)

View File

@@ -29,15 +29,15 @@ func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {
clients = append(clients, cid) clients = append(clients, cid)
} }
case 1: // Not ready case 1: // Not ready
for cid, ready := range stage.reservedClientSlots { for _, session := range stage.ReservedSessions(s) {
if !ready { if !session.reservationReady {
clients = append(clients, cid) clients = append(clients, session.charID)
} }
} }
case 2: // Ready case 2: // Ready
for cid, ready := range stage.reservedClientSlots { for _, session := range stage.ReservedSessions(s) {
if ready { if session.reservationReady {
clients = append(clients, cid) clients = append(clients, session.charID)
} }
} }
} }

View File

@@ -15,7 +15,7 @@ type Player struct {
func getPlayerSlice(s *Server) []Player { func getPlayerSlice(s *Server) []Player {
var p []Player var p []Player
var questIndex int //var questIndex int
for _, channel := range s.Channels { for _, channel := range s.Channels {
for _, stage := range channel.stages { for _, stage := range channel.stages {
@@ -23,10 +23,10 @@ func getPlayerSlice(s *Server) []Player {
continue continue
} }
questID := 0 questID := 0
if stage.isQuest() { //if stage.isQuest() {
questIndex++ // questIndex++
questID = questIndex // questID = questIndex
} //}
for client := range stage.clients { for client := range stage.clients {
p = append(p, Player{ p = append(p, Player{
CharName: client.Name, CharName: client.Name,

View File

@@ -1,6 +1,7 @@
package channelserver package channelserver
import ( import (
"erupe-ce/network"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@@ -29,6 +30,8 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
func doStageTransfer(s *Session, ackHandle uint32, stageID string) { func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
s.reservationStage = nil
s.server.Lock() s.server.Lock()
stage, exists := s.server.stages[stageID] stage, exists := s.server.stages[stageID]
s.server.Unlock() s.server.Unlock()
@@ -53,9 +56,8 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
removeSessionFromStage(s) 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.Lock()
s.stageID = stageID
s.stage = s.server.stages[stageID] s.stage = s.server.stages[stageID]
s.Unlock() s.Unlock()
@@ -113,7 +115,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
s.stage.RUnlock() s.stage.RUnlock()
} }
newNotif.WriteUint16(0x0010) // End it. newNotif.WriteUint16(uint16(network.MSG_SYS_END)) // End it.
if len(newNotif.Data()) > 2 { if len(newNotif.Data()) > 2 {
s.QueueSend(newNotif.Data()) s.QueueSend(newNotif.Data())
} }
@@ -125,7 +127,7 @@ func destructEmptyStages(s *Session) {
for _, stage := range s.server.stages { for _, stage := range s.server.stages {
// Destroy empty Quest/My series/Guild 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 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) delete(s.server.stages, stage.id)
s.logger.Debug("Destructed stage", zap.String("stage.id", 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) pkt := p.(*mhfpacket.MsgSysEnterStage)
// Push our current stage ID to the movement stack before entering another one. // 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) s.stageMoveStack.Set(pkt.StageID)
} else { } else {
s.stage.Lock() s.stageMoveStack.Push(s.stage.id)
s.stage.reservedClientSlots[s.charID] = false
s.stage.Unlock()
s.stageMoveStack.Push(s.stageID)
s.stageMoveStack.Lock() s.stageMoveStack.Lock()
} }
s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{})
if s.reservationStage != nil {
s.reservationStage = nil
}
doStageTransfer(s, pkt.AckHandle, pkt.StageID) doStageTransfer(s, pkt.AckHandle, pkt.StageID)
} }
@@ -178,19 +172,9 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
s.stageMoveStack.Unlock() s.stageMoveStack.Unlock()
backStage, err := s.stageMoveStack.Pop() backStage, err := s.stageMoveStack.Pop()
if err != nil { 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) doStageTransfer(s, pkt.AckHandle, backStage)
} }
@@ -209,18 +193,19 @@ func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysLockStage) pkt := p.(*mhfpacket.MsgSysLockStage)
// TODO(Andoryuuta): What does this packet _actually_ do? if stage, exists := s.server.stages[pkt.StageID]; exists {
// I think this is supposed to mark a stage as no longer able to accept client reservations stage.Lock()
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) stage.locked = true
stage.Unlock()
}
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
} }
func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
if s.reservationStage != nil { if s.reservationStage != nil {
s.reservationStage.RLock() s.reservationStage.RLock()
defer s.reservationStage.RUnlock() defer s.reservationStage.RUnlock()
for _, session := range s.reservationStage.ReservedSessions(s) {
for charID := range s.reservationStage.reservedClientSlots {
session := s.server.FindSessionByCharID(charID)
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
} }
@@ -235,24 +220,24 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
if stage, exists := s.server.stages[pkt.StageID]; exists { if stage, exists := s.server.stages[pkt.StageID]; exists {
stage.Lock() stage.Lock()
defer stage.Unlock() defer stage.Unlock()
if _, exists := stage.reservedClientSlots[s.charID]; exists { if stage.IsSessionReserved(s) {
switch pkt.Ready { switch pkt.Ready {
case 1: // 0x01 case 1: // 0x01
stage.reservedClientSlots[s.charID] = false s.reservationReady = false
case 17: // 0x11 case 17: // 0x11
stage.reservedClientSlots[s.charID] = true s.reservationReady = true
} }
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) 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 len(stage.password) > 0 {
if stage.password != s.stagePass { if stage.password != s.stagePass {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4)) doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return return
} }
} }
stage.reservedClientSlots[s.charID] = false
// Save the reservation stage in the session for later use in MsgSysUnreserveStage. // Save the reservation stage in the session for later use in MsgSysUnreserveStage.
s.Lock() s.Lock()
s.reservationReady = false
s.reservationStage = stage s.reservationStage = stage
s.Unlock() s.Unlock()
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4)) 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) { func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {
s.Lock() s.Lock()
stage := s.reservationStage
s.reservationStage = nil s.reservationStage = nil
s.Unlock() 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) { func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {
@@ -287,7 +264,7 @@ func handleMsgSysSetStagePass(s *Session, p mhfpacket.MHFPacket) {
if stage != nil { if stage != nil {
stage.Lock() stage.Lock()
// Will only exist if host. // Will only exist if host.
if _, exists := stage.reservedClientSlots[s.charID]; exists { if stage.IsSessionReserved(s) {
stage.password = pkt.Password stage.password = pkt.Password
} }
stage.Unlock() stage.Unlock()
@@ -370,7 +347,7 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
for _, stage := range s.server.stages { for _, stage := range s.server.stages {
stage.RLock() stage.RLock()
defer stage.RUnlock() defer stage.RUnlock()
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 { if len(stage.ReservedSessions(s)) == 0 && len(stage.clients) == 0 {
continue continue
} }
if !strings.Contains(stage.id, pkt.StagePrefix) { if !strings.Contains(stage.id, pkt.StagePrefix) {
@@ -383,21 +360,18 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint16(uint16(len(stages))) bf.WriteUint16(uint16(len(stages)))
for _, stage := range stages { for _, stage := range stages {
stage.RLock() stage.RLock()
bf.WriteUint16(uint16(len(stage.reservedClientSlots))) bf.WriteUint16(uint16(len(stage.ReservedSessions(s))) - uint16(len(stage.clients)))
bf.WriteUint16(0) bf.WriteUint16(uint16(len(stage.clients)))
if len(stage.clients) > 0 { bf.WriteUint16(uint16(len(stage.clients)))
bf.WriteUint16(1)
} else {
bf.WriteUint16(0)
}
bf.WriteUint16(stage.maxPlayers) bf.WriteUint16(stage.maxPlayers)
if len(stage.password) > 0 { var flags uint8
// This byte has also been seen as 1 if stage.locked {
// 2/3 = Locked, bitfield? flags |= 1
bf.WriteUint8(2)
} else {
bf.WriteUint8(0)
} }
if len(stage.password) > 0 {
flags |= 2
}
bf.WriteUint8(flags)
ps.Uint8(bf, stage.id, false) ps.Uint8(bf, stage.id, false)
stage.RUnlock() stage.RUnlock()
} }

View File

@@ -36,9 +36,9 @@ type Session struct {
objectIndex uint16 objectIndex uint16
userEnteredStage bool // If the user has entered a stage before userEnteredStage bool // If the user has entered a stage before
stageID string
stage *Stage stage *Stage
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet. reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
reservationReady bool
stagePass string // Temporary storage stagePass string // Temporary storage
prevGuildID uint32 // Stores the last GuildID used in InfoGuild prevGuildID uint32 // Stores the last GuildID used in InfoGuild
charID uint32 charID uint32

View File

@@ -36,10 +36,6 @@ type Stage struct {
// These are clients that are CURRENTLY in the stage // These are clients that are CURRENTLY in the stage
clients map[*Session]uint32 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, // These are raw binary blobs that the stage owner sets,
// other clients expect the server to echo them back in the exact same format. // other clients expect the server to echo them back in the exact same format.
rawBinaryData map[stageBinaryKey][]byte rawBinaryData map[stageBinaryKey][]byte
@@ -47,18 +43,39 @@ type Stage struct {
host *Session host *Session
maxPlayers uint16 maxPlayers uint16
password string 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. // NewStage creates a new stage with intialized values.
func NewStage(ID string) *Stage { func NewStage(ID string) *Stage {
s := &Stage{ s := &Stage{
id: ID, id: ID,
clients: make(map[*Session]uint32), clients: make(map[*Session]uint32),
reservedClientSlots: make(map[uint32]bool), objects: make(map[uint32]*Object),
objects: make(map[uint32]*Object), objectIndex: 0,
objectIndex: 0, rawBinaryData: make(map[stageBinaryKey][]byte),
rawBinaryData: make(map[stageBinaryKey][]byte), maxPlayers: 4,
maxPlayers: 4,
} }
return s return s
} }
@@ -83,15 +100,3 @@ func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
session.QueueSendNonBlocking(bf.Data()) 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
}