mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-13 07:25:03 +01:00
Compare commits
2 Commits
8f3624d589
...
fix/mutex-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85eb9fe99c | ||
|
|
e24c432d69 |
@@ -3,7 +3,6 @@ package mhfpacket
|
||||
import (
|
||||
"errors"
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/common/bfutil"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
@@ -26,8 +25,8 @@ func (m *MsgSysCreateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Client
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.Unk0 = bf.ReadUint8()
|
||||
m.PlayerCount = bf.ReadUint8()
|
||||
stageIDLength := bf.ReadUint8()
|
||||
m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength))))
|
||||
_ = bf.ReadUint8() // Length StageID
|
||||
m.StageID = string(bf.ReadNullTerminatedBytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/common/bfutil"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
@@ -12,7 +11,7 @@ import (
|
||||
// MsgSysEnterStage represents the MSG_SYS_ENTER_STAGE
|
||||
type MsgSysEnterStage struct {
|
||||
AckHandle uint32
|
||||
UnkBool uint8
|
||||
Unk bool
|
||||
StageID string
|
||||
}
|
||||
|
||||
@@ -24,9 +23,9 @@ func (m *MsgSysEnterStage) Opcode() network.PacketID {
|
||||
// Parse parses the packet from binary
|
||||
func (m *MsgSysEnterStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.UnkBool = bf.ReadUint8()
|
||||
stageIDLength := bf.ReadUint8()
|
||||
m.StageID = string(bfutil.UpToNull(bf.ReadBytes(uint(stageIDLength))))
|
||||
m.Unk = bf.ReadBool() // IsQuest?
|
||||
_ = bf.ReadUint8() // Length StageID
|
||||
m.StageID = string(bf.ReadNullTerminatedBytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
// MsgSysEnumerateStage represents the MSG_SYS_ENUMERATE_STAGE
|
||||
type MsgSysEnumerateStage struct {
|
||||
AckHandle uint32
|
||||
Unk0 uint8 // Hardcoded 1 in the binary
|
||||
StagePrefix string // NULL terminated string.
|
||||
}
|
||||
|
||||
@@ -24,8 +23,8 @@ func (m *MsgSysEnumerateStage) Opcode() network.PacketID {
|
||||
// Parse parses the packet from binary
|
||||
func (m *MsgSysEnumerateStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.Unk0 = bf.ReadUint8()
|
||||
bf.ReadUint8()
|
||||
_ = bf.ReadUint8() // Always 1
|
||||
_ = bf.ReadUint8() // Prefix length
|
||||
m.StagePrefix = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"erupe-ce/network/clientctx"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// MsgSysLockStage represents the MSG_SYS_LOCK_STAGE
|
||||
type MsgSysLockStage struct {
|
||||
AckHandle uint32
|
||||
Unk0 uint8 // Hardcoded 1 in the binary
|
||||
Unk1 uint8 // Hardcoded 1 in the binary
|
||||
StageIDLength uint8
|
||||
StageID string
|
||||
AckHandle uint32
|
||||
StageID string
|
||||
}
|
||||
|
||||
// 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
|
||||
func (m *MsgSysLockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.Unk0 = bf.ReadUint8()
|
||||
m.Unk1 = bf.ReadUint8()
|
||||
m.StageIDLength = bf.ReadUint8()
|
||||
m.StageID = string(bf.ReadBytes(uint(m.StageIDLength)))
|
||||
_ = bf.ReadUint8() // Always 1
|
||||
_ = bf.ReadUint8() // Always 1
|
||||
_ = bf.ReadUint8() // Length StageID
|
||||
m.StageID = string(bf.ReadNullTerminatedBytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
"erupe-ce/common/byteframe"
|
||||
)
|
||||
|
||||
// MsgSysUnlockStage represents the MSG_SYS_UNLOCK_STAGE
|
||||
type MsgSysUnlockStage struct {
|
||||
Unk0 uint16 // Hardcoded 0 in the binary.
|
||||
}
|
||||
type MsgSysUnlockStage struct{}
|
||||
|
||||
// Opcode returns the ID associated with this packet type.
|
||||
func (m *MsgSysUnlockStage) Opcode() network.PacketID {
|
||||
@@ -18,12 +17,11 @@ func (m *MsgSysUnlockStage) Opcode() network.PacketID {
|
||||
|
||||
// Parse parses the packet from binary
|
||||
func (m *MsgSysUnlockStage) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
m.Unk0 = bf.ReadUint16()
|
||||
_ = bf.ReadUint16() // Always zero
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build builds a binary packet from the current data.
|
||||
func (m *MsgSysUnlockStage) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
bf.WriteUint16(m.Unk0)
|
||||
return nil
|
||||
return errors.New("NOT IMPLEMENTED")
|
||||
}
|
||||
|
||||
@@ -190,11 +190,9 @@ 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 {
|
||||
for _, sess := range s.server.sessions {
|
||||
for rSlot := range stage.reservedClientSlots {
|
||||
if sess.charID == rSlot && sess.stage != nil && sess.stage.id[3:5] != "Qs" {
|
||||
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
for _, sess := range stage.ReservedSessions(s) {
|
||||
if sess.stage != nil && sess.stage.id[3:5] != "Qs" {
|
||||
sess.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,14 +241,6 @@ func logoutPlayer(s *Session) {
|
||||
CharID: s.charID,
|
||||
}, 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)
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -378,7 +366,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
|
||||
if session.charID == CharID {
|
||||
count++
|
||||
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.WriteUint16(c.Port)
|
||||
resp.WriteUint32(session.charID)
|
||||
@@ -408,7 +396,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
|
||||
if strings.Contains(session.Name, searchTerm) {
|
||||
count++
|
||||
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.WriteUint16(c.Port)
|
||||
resp.WriteUint32(session.charID)
|
||||
@@ -445,7 +433,7 @@ func handleMsgMhfTransitMessage(s *Session, p mhfpacket.MHFPacket) {
|
||||
hrp := uint16(1)
|
||||
gr := uint16(0)
|
||||
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)
|
||||
resp.WriteUint32(binary.LittleEndian.Uint32(net.ParseIP(c.IP).To4()))
|
||||
resp.WriteUint16(c.Port)
|
||||
|
||||
@@ -10,15 +10,14 @@ import (
|
||||
func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysEnumerateClient)
|
||||
|
||||
s.server.stagesLock.RLock()
|
||||
s.server.RLock()
|
||||
stage, ok := s.server.stages[pkt.StageID]
|
||||
s.server.RUnlock()
|
||||
if !ok {
|
||||
s.server.stagesLock.RUnlock()
|
||||
s.logger.Warn("Can't enumerate clients for stage that doesn't exist!", zap.String("stageID", pkt.StageID))
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
s.server.stagesLock.RUnlock()
|
||||
|
||||
// Read-lock the stage and make the response with all of the charID's in the stage.
|
||||
resp := byteframe.NewByteFrame()
|
||||
@@ -30,15 +29,15 @@ func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {
|
||||
clients = append(clients, cid)
|
||||
}
|
||||
case 1: // Not ready
|
||||
for cid, ready := range stage.reservedClientSlots {
|
||||
if !ready {
|
||||
clients = append(clients, cid)
|
||||
for _, session := range stage.ReservedSessions(s) {
|
||||
if !session.reservationReady {
|
||||
clients = append(clients, session.charID)
|
||||
}
|
||||
}
|
||||
case 2: // Ready
|
||||
for cid, ready := range stage.reservedClientSlots {
|
||||
if ready {
|
||||
clients = append(clients, cid)
|
||||
for _, session := range stage.ReservedSessions(s) {
|
||||
if session.reservationReady {
|
||||
clients = append(clients, session.charID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +48,6 @@ func handleMsgSysEnumerateClient(s *Session, p mhfpacket.MHFPacket) {
|
||||
stage.RUnlock()
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
|
||||
s.logger.Debug("MsgSysEnumerateClient Done!")
|
||||
}
|
||||
|
||||
func handleMsgMhfListMember(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
@@ -15,7 +15,7 @@ type Player struct {
|
||||
|
||||
func getPlayerSlice(s *Server) []Player {
|
||||
var p []Player
|
||||
var questIndex int
|
||||
//var questIndex int
|
||||
|
||||
for _, channel := range s.Channels {
|
||||
for _, stage := range channel.stages {
|
||||
@@ -23,10 +23,10 @@ func getPlayerSlice(s *Server) []Player {
|
||||
continue
|
||||
}
|
||||
questID := 0
|
||||
if stage.isQuest() {
|
||||
questIndex++
|
||||
questID = questIndex
|
||||
}
|
||||
//if stage.isQuest() {
|
||||
// questIndex++
|
||||
// questID = questIndex
|
||||
//}
|
||||
for client := range stage.clients {
|
||||
p = append(p, Player{
|
||||
CharName: client.Name,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"erupe-ce/network"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -29,6 +30,8 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
s.reservationStage = nil
|
||||
|
||||
s.server.Lock()
|
||||
stage, exists := s.server.stages[stageID]
|
||||
s.server.Unlock()
|
||||
@@ -53,9 +56,8 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
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.stageID = stageID
|
||||
s.stage = s.server.stages[stageID]
|
||||
s.Unlock()
|
||||
|
||||
@@ -113,7 +115,7 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
|
||||
s.stage.RUnlock()
|
||||
}
|
||||
|
||||
newNotif.WriteUint16(0x0010) // End it.
|
||||
newNotif.WriteUint16(uint16(network.MSG_SYS_END)) // End it.
|
||||
if len(newNotif.Data()) > 2 {
|
||||
s.QueueSend(newNotif.Data())
|
||||
}
|
||||
@@ -125,7 +127,7 @@ func destructEmptyStages(s *Session) {
|
||||
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 {
|
||||
if len(stage.ReservedSessions(s)) == 0 && len(stage.clients) == 0 {
|
||||
delete(s.server.stages, 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)
|
||||
|
||||
// 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)
|
||||
} else {
|
||||
s.stage.Lock()
|
||||
s.stage.reservedClientSlots[s.charID] = false
|
||||
s.stage.Unlock()
|
||||
s.stageMoveStack.Push(s.stageID)
|
||||
s.stageMoveStack.Push(s.stage.id)
|
||||
s.stageMoveStack.Lock()
|
||||
}
|
||||
|
||||
s.QueueSendMHF(&mhfpacket.MsgSysCleanupObject{})
|
||||
if s.reservationStage != nil {
|
||||
s.reservationStage = nil
|
||||
}
|
||||
|
||||
doStageTransfer(s, pkt.AckHandle, pkt.StageID)
|
||||
}
|
||||
|
||||
@@ -178,15 +172,7 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.stageMoveStack.Unlock()
|
||||
backStage, err := s.stageMoveStack.Pop()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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)
|
||||
backStage = "sl1Ns200p0a0u0"
|
||||
}
|
||||
|
||||
doStageTransfer(s, pkt.AckHandle, backStage)
|
||||
@@ -207,18 +193,19 @@ func handleMsgSysLeaveStage(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
func handleMsgSysLockStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysLockStage)
|
||||
// TODO(Andoryuuta): What does this packet _actually_ do?
|
||||
// I think this is supposed to mark a stage as no longer able to accept client reservations
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
if stage, exists := s.server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
stage.locked = true
|
||||
stage.Unlock()
|
||||
}
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
if s.reservationStage != nil {
|
||||
s.reservationStage.RLock()
|
||||
defer s.reservationStage.RUnlock()
|
||||
|
||||
for charID := range s.reservationStage.reservedClientSlots {
|
||||
session := s.server.FindSessionByCharID(charID)
|
||||
for _, session := range s.reservationStage.ReservedSessions(s) {
|
||||
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
|
||||
}
|
||||
|
||||
@@ -233,24 +220,24 @@ func handleMsgSysReserveStage(s *Session, 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 stage.IsSessionReserved(s) {
|
||||
switch pkt.Ready {
|
||||
case 1: // 0x01
|
||||
stage.reservedClientSlots[s.charID] = false
|
||||
s.reservationReady = false
|
||||
case 17: // 0x11
|
||||
stage.reservedClientSlots[s.charID] = true
|
||||
s.reservationReady = true
|
||||
}
|
||||
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 stage.password != s.stagePass {
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
}
|
||||
stage.reservedClientSlots[s.charID] = false
|
||||
// Save the reservation stage in the session for later use in MsgSysUnreserveStage.
|
||||
s.Lock()
|
||||
s.reservationReady = false
|
||||
s.reservationStage = stage
|
||||
s.Unlock()
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
@@ -265,35 +252,27 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.Lock()
|
||||
stage := s.reservationStage
|
||||
s.reservationStage = nil
|
||||
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) {
|
||||
pkt := p.(*mhfpacket.MsgSysSetStagePass)
|
||||
s.Lock()
|
||||
s.RLock()
|
||||
stage := s.reservationStage
|
||||
s.Unlock()
|
||||
s.RUnlock()
|
||||
if stage != nil {
|
||||
stage.Lock()
|
||||
// Will only exist if host.
|
||||
if _, exists := stage.reservedClientSlots[s.charID]; exists {
|
||||
if stage.IsSessionReserved(s) {
|
||||
stage.password = pkt.Password
|
||||
}
|
||||
stage.Unlock()
|
||||
} else {
|
||||
// Store for use on next ReserveStage.
|
||||
s.Lock()
|
||||
s.RLock()
|
||||
s.stagePass = pkt.Password
|
||||
s.Unlock()
|
||||
s.RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +290,7 @@ func handleMsgSysSetStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysGetStageBinary)
|
||||
if stage, exists := s.server.stages[pkt.StageID]; exists {
|
||||
stage.Lock()
|
||||
stage.RLock()
|
||||
if binaryData, exists := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]; exists {
|
||||
doAckBufSucceed(s, pkt.AckHandle, binaryData)
|
||||
} else if pkt.BinaryType1 == 4 {
|
||||
@@ -323,7 +302,7 @@ func handleMsgSysGetStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
s.logger.Warn("Sending blank stage binary")
|
||||
doAckBufSucceed(s, pkt.AckHandle, []byte{})
|
||||
}
|
||||
stage.Unlock()
|
||||
stage.RUnlock()
|
||||
} else {
|
||||
s.logger.Warn("Failed to get stage", zap.String("StageID", pkt.StageID))
|
||||
}
|
||||
@@ -340,9 +319,9 @@ func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
for {
|
||||
s.logger.Debug("MsgSysWaitStageBinary before lock and get stage")
|
||||
stage.Lock()
|
||||
stage.RLock()
|
||||
stageBinary, gotBinary := stage.rawBinaryData[stageBinaryKey{pkt.BinaryType0, pkt.BinaryType1}]
|
||||
stage.Unlock()
|
||||
stage.RUnlock()
|
||||
s.logger.Debug("MsgSysWaitStageBinary after lock and get stage")
|
||||
if gotBinary {
|
||||
doAckBufSucceed(s, pkt.AckHandle, stageBinary)
|
||||
@@ -362,47 +341,40 @@ func handleMsgSysWaitStageBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgSysEnumerateStage)
|
||||
|
||||
// Read-lock the server stage map.
|
||||
s.server.stagesLock.RLock()
|
||||
defer s.server.stagesLock.RUnlock()
|
||||
|
||||
// Build the response
|
||||
bf := byteframe.NewByteFrame()
|
||||
var joinable uint16
|
||||
bf.WriteUint16(0)
|
||||
for sid, stage := range s.server.stages {
|
||||
var stages []*Stage
|
||||
s.server.RLock()
|
||||
for _, stage := range s.server.stages {
|
||||
stage.RLock()
|
||||
|
||||
if len(stage.reservedClientSlots) == 0 && len(stage.clients) == 0 {
|
||||
stage.RUnlock()
|
||||
defer stage.RUnlock()
|
||||
if len(stage.ReservedSessions(s)) == 0 && len(stage.clients) == 0 {
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(stage.id, pkt.StagePrefix) {
|
||||
stage.RUnlock()
|
||||
continue
|
||||
}
|
||||
joinable++
|
||||
stages = append(stages, stage)
|
||||
}
|
||||
s.server.RUnlock()
|
||||
|
||||
bf.WriteUint16(uint16(len(stage.reservedClientSlots)))
|
||||
bf.WriteUint16(0) // Unk
|
||||
if len(stage.clients) > 0 {
|
||||
bf.WriteUint16(1)
|
||||
} else {
|
||||
bf.WriteUint16(0)
|
||||
}
|
||||
bf.WriteUint16(uint16(len(stages)))
|
||||
for _, stage := range stages {
|
||||
stage.RLock()
|
||||
bf.WriteUint16(uint16(len(stage.ReservedSessions(s))) - uint16(len(stage.clients)))
|
||||
bf.WriteUint16(uint16(len(stage.clients)))
|
||||
bf.WriteUint16(uint16(len(stage.clients)))
|
||||
bf.WriteUint16(stage.maxPlayers)
|
||||
if len(stage.password) > 0 {
|
||||
// This byte has also been seen as 1
|
||||
// The quest is also recognised as locked when this is 2
|
||||
bf.WriteUint8(2)
|
||||
} else {
|
||||
bf.WriteUint8(0)
|
||||
var flags uint8
|
||||
if stage.locked {
|
||||
flags |= 1
|
||||
}
|
||||
ps.Uint8(bf, sid, false)
|
||||
if len(stage.password) > 0 {
|
||||
flags |= 2
|
||||
}
|
||||
bf.WriteUint8(flags)
|
||||
ps.Uint8(bf, stage.id, false)
|
||||
stage.RUnlock()
|
||||
}
|
||||
bf.Seek(0, 0)
|
||||
bf.WriteUint16(joinable)
|
||||
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ type userBinaryPartID struct {
|
||||
|
||||
// Server is a MHF channel server.
|
||||
type Server struct {
|
||||
sync.Mutex
|
||||
sync.RWMutex
|
||||
Channels []*Server
|
||||
ID uint16
|
||||
GlobalID string
|
||||
@@ -52,8 +52,7 @@ type Server struct {
|
||||
listener net.Listener // Listener that is created when Server.Start is called.
|
||||
isShuttingDown bool
|
||||
|
||||
stagesLock sync.RWMutex
|
||||
stages map[string]*Stage
|
||||
stages map[string]*Stage
|
||||
|
||||
// Used to map different languages
|
||||
dict map[string]string
|
||||
@@ -374,8 +373,6 @@ func (s *Server) FindSessionByCharID(charID uint32) *Session {
|
||||
}
|
||||
|
||||
func (s *Server) FindObjectByChar(charID uint32) *Object {
|
||||
s.stagesLock.RLock()
|
||||
defer s.stagesLock.RUnlock()
|
||||
for _, stage := range s.stages {
|
||||
stage.RLock()
|
||||
for objId := range stage.objects {
|
||||
|
||||
@@ -25,7 +25,7 @@ type packet struct {
|
||||
|
||||
// Session holds state for the channel server connection.
|
||||
type Session struct {
|
||||
sync.Mutex
|
||||
sync.RWMutex
|
||||
logger *zap.Logger
|
||||
server *Server
|
||||
rawConn net.Conn
|
||||
@@ -36,9 +36,9 @@ type Session struct {
|
||||
|
||||
objectIndex uint16
|
||||
userEnteredStage bool // If the user has entered a stage before
|
||||
stageID string
|
||||
stage *Stage
|
||||
reservationStage *Stage // Required for the stateful MsgSysUnreserveStage packet.
|
||||
reservationReady bool
|
||||
stagePass string // Temporary storage
|
||||
prevGuildID uint32 // Stores the last GuildID used in InfoGuild
|
||||
charID uint32
|
||||
|
||||
@@ -36,10 +36,6 @@ type Stage struct {
|
||||
// These are clients that are CURRENTLY in the stage
|
||||
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,
|
||||
// other clients expect the server to echo them back in the exact same format.
|
||||
rawBinaryData map[stageBinaryKey][]byte
|
||||
@@ -47,18 +43,39 @@ type Stage struct {
|
||||
host *Session
|
||||
maxPlayers uint16
|
||||
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.
|
||||
func NewStage(ID string) *Stage {
|
||||
s := &Stage{
|
||||
id: ID,
|
||||
clients: make(map[*Session]uint32),
|
||||
reservedClientSlots: make(map[uint32]bool),
|
||||
objects: make(map[uint32]*Object),
|
||||
objectIndex: 0,
|
||||
rawBinaryData: make(map[stageBinaryKey][]byte),
|
||||
maxPlayers: 4,
|
||||
id: ID,
|
||||
clients: make(map[*Session]uint32),
|
||||
objects: make(map[uint32]*Object),
|
||||
objectIndex: 0,
|
||||
rawBinaryData: make(map[stageBinaryKey][]byte),
|
||||
maxPlayers: 4,
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -83,15 +100,3 @@ func (s *Stage) BroadcastMHF(pkt mhfpacket.MHFPacket, ignoredSession *Session) {
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user