package packets import ( "encoding/binary" "eq2emu/internal/opcodes" ) type AppHandler struct { pool *PacketPool } func NewAppHandler(pool *PacketPool) *AppHandler { return &AppHandler{pool: pool} } // Create application packet for sending func (h *AppHandler) CreateAppPacket(opcode opcodes.AppOpcode, data []byte) *AppPacket { packet := h.pool.GetAppPacket() packet.Opcode = opcode packet.Data = make([]byte, len(data)) copy(packet.Data, data) return packet } // Serialize app packet to protocol packet func (h *AppHandler) SerializeAppPacket(app *AppPacket, sequence uint16) []byte { size := 3 + len(app.Data) // opcode(1) + seq(2) + opcode(2) + data if app.Compressed { size++ // compression flag } data := make([]byte, size) offset := 0 data[offset] = byte(opcodes.OP_Packet) offset++ binary.LittleEndian.PutUint16(data[offset:], sequence) offset += 2 if app.Compressed { data[offset] = 0xFF offset++ } binary.LittleEndian.PutUint16(data[offset:], uint16(app.Opcode)) offset += 2 copy(data[offset:], app.Data) return data } // Create combined packet func (h *AppHandler) SerializeCombinedPacket(apps []*AppPacket, sequence uint16) []byte { // Calculate total size totalSize := 3 // opcode + sequence for _, app := range apps { subSize := 2 + len(app.Data) // opcode + data if subSize < 0xFF { totalSize += 1 + subSize } else { totalSize += 3 + subSize } } data := make([]byte, totalSize) offset := 0 data[offset] = byte(opcodes.OP_Combined) offset++ binary.LittleEndian.PutUint16(data[offset:], sequence) offset += 2 for _, app := range apps { subSize := 2 + len(app.Data) // Write length if subSize < 0xFF { data[offset] = byte(subSize) offset++ } else { data[offset] = 0xFF offset++ binary.LittleEndian.PutUint16(data[offset:], uint16(subSize)) offset += 2 } // Write opcode binary.LittleEndian.PutUint16(data[offset:], uint16(app.Opcode)) offset += 2 // Write data copy(data[offset:], app.Data) offset += len(app.Data) } return data } // Common EQ2 packet helpers func (h *AppHandler) CreateChatPacket(message string, channel uint8) *AppPacket { writer := NewPacketWriter() writer.WriteUint8(channel) writer.WriteEQ2String(message) return h.CreateAppPacket(opcodes.OP_EqHearChatCmd, writer.Bytes()) } func (h *AppHandler) CreatePositionUpdatePacket(playerID uint32, x, y, z float32) *AppPacket { writer := NewPacketWriter() writer.WriteUint32(playerID) writer.WriteFloat32(x) writer.WriteFloat32(y) writer.WriteFloat32(z) return h.CreateAppPacket(opcodes.OP_UpdatePositionMsg, writer.Bytes()) }