Add chat type checks based on existing comments

Add basic support for clients reserving stages
Remove unnecessary packets
Add max player count to stages
This commit is contained in:
Sophie
2020-03-07 17:30:07 +00:00
parent 795028a1ca
commit b526e66821
3 changed files with 63 additions and 49 deletions

View File

@@ -317,12 +317,12 @@ const (
) )
const ( const (
CHAT_TYPE_LOCAL = 3 CHAT_TYPE_WORLD uint8 = iota
// For some reason sending private messages appears to use the same code CHAT_TYPE_LOCAL
// however the 9th byte in payload is 0x05 and there is no reference to CHAT_TYPE_GUILD
// the target player, something must be wrong here. CHAT_TYPE_ALLIANCE
CHAT_TYPE_LIMITED = 1 CHAT_TYPE_PARTY
CHAT_TYPE_GLOBAL = 0xa CHAT_TYPE_WHISPER
) )
func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
@@ -338,16 +338,16 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
RawDataPayload: pkt.RawDataPayload, RawDataPayload: pkt.RawDataPayload,
} }
switch chatType := pkt.Type0; chatType { switch chatType := pkt.RawDataPayload[2]; chatType {
case CHAT_TYPE_GLOBAL: case CHAT_TYPE_WORLD:
s.server.BroadcastMHF(resp, s) s.server.BroadcastMHF(resp, s)
case CHAT_TYPE_LOCAL: case CHAT_TYPE_LOCAL:
s.stage.BroadcastMHF(resp, s) s.stage.BroadcastMHF(resp, s)
case CHAT_TYPE_LIMITED: case CHAT_TYPE_PARTY:
if pkt.RawDataPayload[9] == 0x04 { // Party messages seem to work partially when a party member starts the quest
// TODO Send to party members only // In town it is not working yet
s.stage.BroadcastMHF(resp, s) // TODO Send to party members only
} s.stage.BroadcastMHF(resp, s)
} }
/* /*
@@ -493,20 +493,12 @@ func handleMsgSysCreateStage(s *Session, p mhfpacket.MHFPacket) {
s.server.stagesLock.Lock() s.server.stagesLock.Lock()
stage := NewStage(stripNullTerminator(pkt.StageID)) stage := NewStage(stripNullTerminator(pkt.StageID))
stage.maxClients = pkt.PlayerCount
s.server.stages[stage.id] = stage s.server.stages[stage.id] = stage
s.server.stagesLock.Unlock() s.server.stagesLock.Unlock()
resp := make([]byte, 8) // Unk resp. resp := make([]byte, 8) // Unk resp.
s.QueueAck(pkt.AckHandle, resp) s.QueueAck(pkt.AckHandle, resp)
createdPartyMessage := &mhfpacket.MsgSysCastedBinary{
CharID: s.charID,
Type0: 0x03,
Type1: 0x03,
RawDataPayload: []byte{0x00, 0x02, 0x0b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x5b, 0x27, 0xb3, 0x2e, 0x48, 0xa3, 0x17, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
}
s.stage.BroadcastMHF(createdPartyMessage, s)
} }
func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysStageDestruct(s *Session, p mhfpacket.MHFPacket) {}
@@ -693,37 +685,56 @@ func handleMsgSysUnlockStage(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) { func handleMsgSysReserveStage(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgSysReserveStage) pkt := p.(*mhfpacket.MsgSysReserveStage)
fmt.Printf("Got reserve stage req, Unk0:%v, StageID:%q\n", pkt.Unk0, pkt.StageID) stageID := stripNullTerminator(pkt.StageID)
s.server.stagesLock.RLock()
stage := s.server.stages[stageID]
s.server.stagesLock.RUnlock()
if uint8(len(stage.clients)) >= s.stage.maxClients {
// Do something? This will probably only be possible when multiple
// players attempt joining a quest at the same time I think.
}
s.server.stagesLock.Lock()
stage.clients[s] = s.charID
s.server.stagesLock.Unlock()
s.reserveStage = stage
fmt.Printf("Got reserve stage req, Unk0:%v, StageID:%q\n", pkt.Unk0, stageID)
// TODO(Andoryuuta): Add proper player-slot reservations for stages. // TODO(Andoryuuta): Add proper player-slot reservations for stages.
s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}) s.QueueAck(pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
s.QueueSend([]byte{ stage.RLock()
0x00, 0x1b, 0x30, 0x15, 0xc2, 0x45, 0x03, 0x03, 0x00, 0x0c, 0x00, 0x02, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, for _, charID := range stage.clients {
}) if charID == s.charID {
continue
}
// TODO remove this, temp for testing // Notify joining player of all existing party members
if s.charID == 0x02 { s.QueueSendMHF(&binpacket.MsgBinPlayerJoinedParty{
return CharID: charID,
PartyJoinType: binpacket.JoinedYourParty,
Unk1: 0x01,
})
} }
stage.RUnlock()
//TODO these messages should be directed to the correct recipients // Notify players in room that player has joined a party
joinedAPartyMessage := &binpacket.MsgBinPlayerJoinedParty{ s.stage.BroadcastMHF(&binpacket.MsgBinPlayerJoinedParty{
CharID: s.charID, CharID: s.charID,
PartyJoinType: binpacket.JoinedLocalParty, PartyJoinType: binpacket.JoinedLocalParty,
Unk1: 0x01, Unk1: 0x01,
} }, s)
s.stage.BroadcastMHF(joinedAPartyMessage, s) // Notify players in party that player has joined
stage.BroadcastMHF(&binpacket.MsgBinPlayerJoinedParty{
joinedYourPartyMessage := &binpacket.MsgBinPlayerJoinedParty{
CharID: s.charID, CharID: s.charID,
PartyJoinType: binpacket.JoinedYourParty, PartyJoinType: binpacket.JoinedYourParty,
Unk1: 0x01, Unk1: 0x01,
} }, s)
s.stage.BroadcastMHF(joinedYourPartyMessage, s)
} }
func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {} func handleMsgSysUnreserveStage(s *Session, p mhfpacket.MHFPacket) {}
@@ -875,14 +886,14 @@ func handleMsgSysEnumerateStage(s *Session, p mhfpacket.MHFPacket) {
// Build the response // Build the response
resp := byteframe.NewByteFrame() resp := byteframe.NewByteFrame()
resp.WriteUint16(uint16(len(s.server.stages))) resp.WriteUint16(uint16(len(s.server.stages)))
for sid := range s.server.stages { for sid, stage := range s.server.stages {
// Found parsing code, field sizes are correct, but unknown purposes still. // Found parsing code, field sizes are correct, but unknown purposes still.
//resp.WriteBytes([]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00}) //resp.WriteBytes([]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00})
resp.WriteUint16(1) // Current players. resp.WriteUint16(1) // Current players.
resp.WriteUint16(0) // Unknown value resp.WriteUint16(0) // Unknown value
resp.WriteUint16(0) // HasDeparted. resp.WriteUint16(0) // HasDeparted.
resp.WriteUint16(4) // Max players. resp.WriteUint16(uint16(stage.maxClients)) // Max players.
resp.WriteUint8(2) // Password protected. resp.WriteUint8(2) // Password protected.
resp.WriteUint8(uint8(len(sid))) resp.WriteUint8(uint8(len(sid)))
resp.WriteBytes([]byte(sid)) resp.WriteBytes([]byte(sid))
} }

View File

@@ -22,10 +22,11 @@ type Session struct {
cryptConn *network.CryptConn cryptConn *network.CryptConn
sendPackets chan []byte sendPackets chan []byte
stageID string stageID string
stage *Stage stage *Stage
charID uint32 reserveStage *Stage
logKey []byte charID uint32
logKey []byte
// A stack containing the stage movement history (push on enter/move, pop on back) // A stack containing the stage movement history (push on enter/move, pop on back)
stageMoveStack *stringstack.StringStack stageMoveStack *stringstack.StringStack

View File

@@ -27,6 +27,7 @@ type Stage struct {
gameObjectCount uint32 // Total count of objects ever created for this stage. Used for ObjID generation. gameObjectCount uint32 // Total count of objects ever created for this stage. Used for ObjID generation.
objects map[uint32]*StageObject // Map of ObjID -> StageObject objects map[uint32]*StageObject // Map of ObjID -> StageObject
clients map[*Session]uint32 // Map of session -> charID clients map[*Session]uint32 // Map of session -> charID
maxClients uint8 // Max number of clients allowed to join this stage
rawBinaryData map[stageBinaryKey][]byte // Raw binary data set by the client. rawBinaryData map[stageBinaryKey][]byte // Raw binary data set by the client.
} }
@@ -37,6 +38,7 @@ func NewStage(ID string) *Stage {
objects: make(map[uint32]*StageObject), objects: make(map[uint32]*StageObject),
clients: make(map[*Session]uint32), clients: make(map[*Session]uint32),
rawBinaryData: make(map[stageBinaryKey][]byte), rawBinaryData: make(map[stageBinaryKey][]byte),
maxClients: 4,
gameObjectCount: 1, gameObjectCount: 1,
} }