Files
Erupe/cmd/protbot/scenario/chat.go
Houmgaor 48639942f6 style: run gofmt across entire codebase
330 non-vendor files had minor formatting inconsistencies
(comment alignment, whitespace). No logic changes.
2026-02-23 21:28:30 +01:00

75 lines
2.2 KiB
Go

package scenario
import (
"fmt"
"erupe-ce/common/byteframe"
"erupe-ce/common/stringsupport"
"erupe-ce/cmd/protbot/protocol"
)
// ChatMessage holds a parsed incoming chat message.
type ChatMessage struct {
ChatType uint8
SenderName string
Message string
}
// SendChat sends a chat message via MSG_SYS_CAST_BINARY with a MsgBinChat payload.
// broadcastType controls delivery scope: 0x03 = stage, 0x06 = world.
func SendChat(ch *protocol.ChannelConn, broadcastType, chatType uint8, message, senderName string) error {
payload := protocol.BuildChatPayload(chatType, message, senderName)
pkt := protocol.BuildCastBinaryPacket(broadcastType, 1, payload)
fmt.Printf("[chat] Sending chat (type=%d, broadcast=%d): %s\n", chatType, broadcastType, message)
return ch.SendPacket(pkt)
}
// ChatCallback is invoked when a chat message is received.
type ChatCallback func(msg ChatMessage)
// ListenChat registers a handler on MSG_SYS_CASTED_BINARY that parses chat
// messages (messageType=1) and invokes the callback.
func ListenChat(ch *protocol.ChannelConn, cb ChatCallback) {
ch.OnPacket(protocol.MSG_SYS_CASTED_BINARY, func(opcode uint16, data []byte) {
// MSG_SYS_CASTED_BINARY layout from server:
// uint32 unk
// uint8 broadcastType
// uint8 messageType
// uint16 dataSize
// []byte payload
if len(data) < 8 {
return
}
messageType := data[5]
if messageType != 1 { // Only handle chat messages.
return
}
bf := byteframe.NewByteFrameFromBytes(data)
_ = bf.ReadUint32() // unk
_ = bf.ReadUint8() // broadcastType
_ = bf.ReadUint8() // messageType
dataSize := bf.ReadUint16()
if dataSize == 0 {
return
}
payload := bf.ReadBytes(uint(dataSize))
// Parse MsgBinChat inner payload.
pbf := byteframe.NewByteFrameFromBytes(payload)
_ = pbf.ReadUint8() // unk0
chatType := pbf.ReadUint8()
_ = pbf.ReadUint16() // flags
_ = pbf.ReadUint16() // senderNameLen
_ = pbf.ReadUint16() // messageLen
msg := stringsupport.SJISToUTF8Lossy(pbf.ReadNullTerminatedBytes())
sender := stringsupport.SJISToUTF8Lossy(pbf.ReadNullTerminatedBytes())
cb(ChatMessage{
ChatType: chatType,
SenderName: sender,
Message: msg,
})
})
}