port partial fix/mutex-rework

This commit is contained in:
wish
2023-11-26 23:22:56 +11:00
parent fc4476ed8c
commit 3c6067c8a6
9 changed files with 53 additions and 57 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"
) )
@@ -13,7 +12,7 @@ type MsgSysCreateStage struct {
AckHandle uint32 AckHandle uint32
Unk0 uint8 // Likely only has 1 and 2 as values. Unk0 uint8 // Likely only has 1 and 2 as values.
PlayerCount uint8 PlayerCount uint8
StageID string // NULL terminated string. StageID string
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -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

@@ -11,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
} }
@@ -23,8 +23,8 @@ 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?
bf.ReadUint8() bf.ReadUint8() // Length StageID
m.StageID = string(bf.ReadNullTerminatedBytes()) m.StageID = string(bf.ReadNullTerminatedBytes())
return nil return nil
} }

View File

@@ -2,8 +2,6 @@ package mhfpacket
import ( import (
"errors" "errors"
"erupe-ce/common/stringsupport"
"erupe-ce/common/byteframe" "erupe-ce/common/byteframe"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/network/clientctx" "erupe-ce/network/clientctx"
@@ -12,8 +10,7 @@ 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
StagePrefix string // NULL terminated string.
} }
// Opcode returns the ID associated with this packet type. // Opcode returns the ID associated with this packet type.
@@ -24,9 +21,9 @@ 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() // Length StagePrefix
m.StagePrefix = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()) m.StagePrefix = string(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() // Zeroed
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

@@ -378,7 +378,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 +408,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 +445,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

@@ -55,7 +55,6 @@ func doStageTransfer(s *Session, ackHandle uint32, stageID string) {
// Save our new stage ID and pointer to the new stage itself. // Save our new stage ID and 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()
@@ -153,13 +152,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.stage.Lock()
s.stage.reservedClientSlots[s.charID] = false s.stage.reservedClientSlots[s.charID] = false
s.stage.Unlock() s.stage.Unlock()
s.stageMoveStack.Push(s.stageID) s.stageMoveStack.Push(s.stage.id)
s.stageMoveStack.Lock() s.stageMoveStack.Lock()
} }
@@ -206,9 +205,12 @@ 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) {
@@ -218,7 +220,9 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {
for charID := range s.reservationStage.reservedClientSlots { for charID := range s.reservationStage.reservedClientSlots {
session := s.server.FindSessionByCharID(charID) session := s.server.FindSessionByCharID(charID)
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{}) if session != nil {
session.QueueSendMHF(&mhfpacket.MsgSysStageDestruct{})
}
} }
delete(s.server.stages, s.reservationStage.id) delete(s.server.stages, s.reservationStage.id)
@@ -241,6 +245,10 @@ func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
} }
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.reservedClientSlots)) < stage.maxPlayers {
if stage.locked {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
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))
@@ -383,20 +391,17 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
joinable++ joinable++
bf.WriteUint16(uint16(len(stage.reservedClientSlots))) bf.WriteUint16(uint16(len(stage.reservedClientSlots)))
bf.WriteUint16(0) // Unk 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 {
// The quest is also recognised as locked when this is 2 flags |= 1
bf.WriteUint8(2)
} else {
bf.WriteUint8(0)
} }
if len(stage.password) > 0 {
flags |= 2
}
bf.WriteUint8(flags)
ps.Uint8(bf, sid, false) ps.Uint8(bf, sid, false)
stage.RUnlock() stage.RUnlock()
} }

View File

@@ -36,7 +36,6 @@ 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.
stagePass string // Temporary storage stagePass string // Temporary storage

View File

@@ -47,6 +47,7 @@ type Stage struct {
host *Session host *Session
maxPlayers uint16 maxPlayers uint16
password string password string
locked bool
} }
// NewStage creates a new stage with intialized values. // NewStage creates a new stage with intialized values.