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{} }