117 lines
3.5 KiB
Go
117 lines
3.5 KiB
Go
package parser
|
|
|
|
import "eq2emu/internal/common"
|
|
|
|
// PacketDef defines a complete packet structure with versioned field ordering
|
|
type PacketDef struct {
|
|
Fields map[string]FieldDesc // Field definitions by name
|
|
Orders map[uint32][]string // Field order by version number
|
|
}
|
|
|
|
func (def *PacketDef) Parse(data []byte, version uint32, flags uint64) (map[string]any, error) {
|
|
ctx := NewContext(data, version, flags)
|
|
return def.parseStruct(ctx)
|
|
}
|
|
|
|
func (def *PacketDef) parseStruct(ctx *ParseContext) (map[string]any, error) {
|
|
result := make(map[string]any)
|
|
order := def.getVersionOrder(ctx.version)
|
|
|
|
for _, fieldName := range order {
|
|
field := def.Fields[fieldName]
|
|
|
|
if !ctx.checkCondition(field.Condition) {
|
|
continue
|
|
}
|
|
|
|
fieldType := field.Type
|
|
if field.Type2 != 0 && ctx.checkCondition(field.Type2Cond) {
|
|
fieldType = field.Type2
|
|
}
|
|
|
|
value := def.parseField(ctx, field, fieldType, fieldName)
|
|
result[fieldName] = value
|
|
ctx.setVarWithArrayIndex(fieldName, value)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (def *PacketDef) parseField(ctx *ParseContext, field FieldDesc, fieldType common.EQ2DataType, fieldName string) any {
|
|
switch fieldType {
|
|
case common.TypeInt8, common.TypeSInt8:
|
|
if field.Oversized > 0 {
|
|
return ctx.readOversizedUint8(field.Oversized)
|
|
}
|
|
return ctx.readUint8()
|
|
case common.TypeInt16, common.TypeSInt16:
|
|
if field.Oversized > 0 {
|
|
return ctx.readOversizedUint16(field.Oversized)
|
|
}
|
|
return ctx.readUint16()
|
|
case common.TypeInt32, common.TypeSInt32:
|
|
if field.Oversized > 0 {
|
|
return ctx.readOversizedUint32(field.Oversized)
|
|
}
|
|
return ctx.readUint32()
|
|
case common.TypeInt64, common.TypeSInt64:
|
|
return ctx.readUint64()
|
|
case common.TypeString8:
|
|
return ctx.readEQ2String8()
|
|
case common.TypeString16:
|
|
return ctx.readEQ2String16()
|
|
case common.TypeString32:
|
|
return ctx.readEQ2String32()
|
|
case common.TypeChar:
|
|
return ctx.readBytes(field.Length)
|
|
case common.TypeFloat:
|
|
return ctx.readFloat32()
|
|
case common.TypeDouble:
|
|
return ctx.readFloat64()
|
|
case common.TypeColor:
|
|
return ctx.readEQ2Color()
|
|
case common.TypeEquipment:
|
|
return ctx.readEQ2Equipment()
|
|
case common.TypeArray:
|
|
size := ctx.getArraySize(field.Condition)
|
|
if field.MaxArraySize > 0 && size > field.MaxArraySize {
|
|
size = field.MaxArraySize
|
|
}
|
|
result := make([]map[string]any, size)
|
|
for i := 0; i < size; i++ {
|
|
ctx.pushArrayIndex(i)
|
|
item, _ := field.SubDef.parseStruct(ctx)
|
|
result[i] = item
|
|
ctx.popArrayIndex()
|
|
}
|
|
return result
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (def *PacketDef) getVersionOrder(version uint32) []string {
|
|
var bestVersion uint32
|
|
for v := range def.Orders {
|
|
if v <= version && v > bestVersion {
|
|
bestVersion = v
|
|
}
|
|
}
|
|
return def.Orders[bestVersion]
|
|
}
|
|
|
|
// FieldDesc describes a single packet field
|
|
type FieldDesc struct {
|
|
Type common.EQ2DataType // Primary data type
|
|
Condition string // Conditional parsing expression
|
|
Length int // Array length or size for fixed-size fields
|
|
SubDef *PacketDef // Nested packet definition for arrays
|
|
Type2 common.EQ2DataType // Alternative data type for conditional parsing
|
|
Type2Cond string // Condition for using Type2
|
|
Oversized int // Threshold for oversized field handling
|
|
DefaultValue int8 // Default value for initialization
|
|
MaxArraySize int // Maximum allowed array size
|
|
Optional bool // Whether this field is optional
|
|
AddToStruct bool // Whether to include in packet structure
|
|
AddType common.EQ2DataType // Type to use when adding to packet
|
|
}
|