255 lines
5.6 KiB
Go
255 lines
5.6 KiB
Go
package packets
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"eq2emu/internal/common"
|
|
"eq2emu/internal/packets/parser"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
)
|
|
|
|
// PacketReader reads packet data based on packet definitions
|
|
type PacketReader struct {
|
|
data []byte
|
|
pos int
|
|
}
|
|
|
|
// NewPacketReader creates a new packet reader
|
|
func NewPacketReader(data []byte) *PacketReader {
|
|
return &PacketReader{
|
|
data: data,
|
|
pos: 0,
|
|
}
|
|
}
|
|
|
|
// ParsePacketFields parses packet data using a packet definition
|
|
func ParsePacketFields(data []byte, packetName string, version uint32) (map[string]any, error) {
|
|
def, exists := GetPacket(packetName)
|
|
if !exists {
|
|
return nil, fmt.Errorf("packet definition '%s' not found", packetName)
|
|
}
|
|
|
|
reader := NewPacketReader(data)
|
|
return reader.parseStruct(def, version)
|
|
}
|
|
|
|
// parseStruct parses a struct according to packet definition
|
|
func (r *PacketReader) parseStruct(def *parser.PacketDef, version uint32) (map[string]any, error) {
|
|
result := make(map[string]any)
|
|
|
|
// Get field order for this version
|
|
order := r.getVersionOrder(def, version)
|
|
|
|
for _, fieldName := range order {
|
|
field, exists := def.Fields[fieldName]
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
// For simplicity, skip conditional fields for now
|
|
if field.Condition != "" {
|
|
continue
|
|
}
|
|
|
|
fieldType := field.Type
|
|
if field.Type2 != 0 {
|
|
fieldType = field.Type2
|
|
}
|
|
|
|
value, err := r.readField(field, fieldType, fieldName, result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading field '%s': %w", fieldName, err)
|
|
}
|
|
|
|
if value != nil {
|
|
result[fieldName] = value
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// readField reads a single field from the packet data
|
|
func (r *PacketReader) readField(field parser.FieldDesc, fieldType common.EQ2DataType, fieldName string, context map[string]any) (any, error) {
|
|
switch fieldType {
|
|
case common.TypeInt8:
|
|
return r.readUint8()
|
|
case common.TypeInt16:
|
|
return r.readUint16()
|
|
case common.TypeInt32:
|
|
return r.readUint32()
|
|
case common.TypeInt64:
|
|
return r.readUint64()
|
|
case common.TypeSInt8:
|
|
return r.readInt8()
|
|
case common.TypeSInt16:
|
|
return r.readInt16()
|
|
case common.TypeSInt32:
|
|
return r.readInt32()
|
|
case common.TypeSInt64:
|
|
return r.readInt64()
|
|
case common.TypeString8:
|
|
return r.readEQ2String8()
|
|
case common.TypeString16:
|
|
return r.readEQ2String16()
|
|
case common.TypeString32:
|
|
return r.readEQ2String32()
|
|
case common.TypeFloat:
|
|
return r.readFloat32()
|
|
case common.TypeDouble:
|
|
return r.readFloat64()
|
|
case common.TypeChar:
|
|
if field.Length > 0 {
|
|
return r.readBytes(field.Length)
|
|
}
|
|
return nil, fmt.Errorf("char field '%s' has no length specified", fieldName)
|
|
default:
|
|
// For unsupported types, skip the field
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
// Low-level read functions
|
|
func (r *PacketReader) readUint8() (uint8, error) {
|
|
if r.pos+1 > len(r.data) {
|
|
return 0, io.EOF
|
|
}
|
|
value := r.data[r.pos]
|
|
r.pos++
|
|
return value, nil
|
|
}
|
|
|
|
func (r *PacketReader) readInt8() (int8, error) {
|
|
value, err := r.readUint8()
|
|
return int8(value), err
|
|
}
|
|
|
|
func (r *PacketReader) readUint16() (uint16, error) {
|
|
if r.pos+2 > len(r.data) {
|
|
return 0, io.EOF
|
|
}
|
|
value := binary.LittleEndian.Uint16(r.data[r.pos:])
|
|
r.pos += 2
|
|
return value, nil
|
|
}
|
|
|
|
func (r *PacketReader) readInt16() (int16, error) {
|
|
value, err := r.readUint16()
|
|
return int16(value), err
|
|
}
|
|
|
|
func (r *PacketReader) readUint32() (uint32, error) {
|
|
if r.pos+4 > len(r.data) {
|
|
return 0, io.EOF
|
|
}
|
|
value := binary.LittleEndian.Uint32(r.data[r.pos:])
|
|
r.pos += 4
|
|
return value, nil
|
|
}
|
|
|
|
func (r *PacketReader) readInt32() (int32, error) {
|
|
value, err := r.readUint32()
|
|
return int32(value), err
|
|
}
|
|
|
|
func (r *PacketReader) readUint64() (uint64, error) {
|
|
if r.pos+8 > len(r.data) {
|
|
return 0, io.EOF
|
|
}
|
|
value := binary.LittleEndian.Uint64(r.data[r.pos:])
|
|
r.pos += 8
|
|
return value, nil
|
|
}
|
|
|
|
func (r *PacketReader) readInt64() (int64, error) {
|
|
value, err := r.readUint64()
|
|
return int64(value), err
|
|
}
|
|
|
|
func (r *PacketReader) readFloat32() (float32, error) {
|
|
if r.pos+4 > len(r.data) {
|
|
return 0, io.EOF
|
|
}
|
|
bits := binary.LittleEndian.Uint32(r.data[r.pos:])
|
|
r.pos += 4
|
|
return math.Float32frombits(bits), nil
|
|
}
|
|
|
|
func (r *PacketReader) readFloat64() (float64, error) {
|
|
if r.pos+8 > len(r.data) {
|
|
return 0, io.EOF
|
|
}
|
|
bits := binary.LittleEndian.Uint64(r.data[r.pos:])
|
|
r.pos += 8
|
|
return math.Float64frombits(bits), nil
|
|
}
|
|
|
|
func (r *PacketReader) readBytes(n int) ([]byte, error) {
|
|
if r.pos+n > len(r.data) {
|
|
return nil, io.EOF
|
|
}
|
|
data := make([]byte, n)
|
|
copy(data, r.data[r.pos:r.pos+n])
|
|
r.pos += n
|
|
return data, nil
|
|
}
|
|
|
|
func (r *PacketReader) readEQ2String8() (string, error) {
|
|
length, err := r.readUint8()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if length == 0 {
|
|
return "", nil
|
|
}
|
|
data, err := r.readBytes(int(length))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(data), nil
|
|
}
|
|
|
|
func (r *PacketReader) readEQ2String16() (string, error) {
|
|
length, err := r.readUint16()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if length == 0 {
|
|
return "", nil
|
|
}
|
|
data, err := r.readBytes(int(length))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(data), nil
|
|
}
|
|
|
|
func (r *PacketReader) readEQ2String32() (string, error) {
|
|
length, err := r.readUint32()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if length == 0 {
|
|
return "", nil
|
|
}
|
|
data, err := r.readBytes(int(length))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(data), nil
|
|
}
|
|
|
|
// getVersionOrder returns the field order for the specified version
|
|
func (r *PacketReader) getVersionOrder(def *parser.PacketDef, version uint32) []string {
|
|
var bestVersion uint32
|
|
for v := range def.Orders {
|
|
if v <= version && v > bestVersion {
|
|
bestVersion = v
|
|
}
|
|
}
|
|
if order, exists := def.Orders[bestVersion]; exists {
|
|
return order
|
|
}
|
|
return []string{}
|
|
} |