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, }) }) }