121 lines
2.6 KiB
Go
121 lines
2.6 KiB
Go
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())
|
|
}
|