# Packet Definition Parser

Fast XML-like parser for binary packet structures with versioning and conditional fields.

## Basic Syntax

```xml
<packet name="PacketName">
	<version number="1">
		<i32 name="player_id">
		<str16 name="player_name">
		<color name="skin_color">
	</version>
</packet>
```

## Field Types

| Type | Size | Description |
|------|------|-------------|
| `u8`, `u16`, `u32`, `u64` | 1-8 bytes | Unsigned integers |
| `i8`, `i16`, `i32`, `i64` | 1-8 bytes | Signed integers |
| `f32`, `f64`, `double` | 4-8 bytes | Floating point |
| `str8`, `str16`, `str32` | Variable | Length-prefixed strings |
| `char` | Fixed | Fixed-size byte array |
| `color` | 3 bytes | RGB color (r,g,b) |
| `equip` | 8 bytes | Equipment item |
| `array` | Variable | Array of substructures |

## Multiple Field Names

```xml
<u32 name="player_id,account_id">
<f32 name="pos_x,pos_y,pos_z">
```

## Conditional Fields

```xml
<str16 name="guild_name" if="flag:has_guild">
<u8 name="enhancement" if="item_type!=0">
<color name="aura" if="special_flags&0x01">
<str16 name="description" if="description!>0">
```

### Condition Types

**Flag Conditions:**
- `flag:name` - Flag is set
- `!flag:name` - Flag not set  

**Variable Conditions:**
- `var:name` - Variable exists and is non-zero
- `!var:name` - Variable doesn't exist or is zero

**Version Conditions:**
- `version>=562` - Version comparisons
- `version<1200` - Supports `>=`, `<=`, `>`, `<`

**Value Comparisons:**
- `field>=value` - Numeric comparisons
- `field!=0` - Supports `>=`, `<=`, `>`, `<`, `==`, `!=`

**String Length:**
- `name!>5` - String longer than 5 chars
- `name!<=100` - String 100 chars or less
- Supports `!>`, `!<`, `!>=`, `!<=`, `!=`

**Bitwise Operations:**
- `field&0x01` - Bitwise AND with hex value

**Complex Logic:**
- `cond1,cond2` - OR logic (comma-separated)
- `cond1&cond2` - AND logic (ampersand)
- `version>=562&level>10` - Multiple conditions

**Array Context:**
- `item_type_%i!=0` - `%i` substitutes current array index

## Groups

Organize related fields with automatic prefixing:

```xml
<group name="appearance">
	<color name="skin_color,hair_color,eye_color">
	<str16 name="face_file,hair_file">
</group>
<!-- Creates: appearance_skin_color, appearance_hair_color, etc. -->

```

## Templates

Define reusable field groups that can be injected into packets:

```xml
<!-- Define template -->
<template name="position">
	<f32 name="x,y,z">
	<f32 name="heading">
</template>

<template name="appearance">
	<color name="skin_color,hair_color,eye_color">
	<str16 name="face_file,hair_file">
</template>

<!-- Use templates in packets -->
<packet name="PlayerUpdate">
	<version number="1">
		<u32 name="player_id">
		<template use="position">
		<u8 name="level">
		<template use="appearance">
	</version>
</packet>
```

Templates work with groups for prefixing:

```xml
<group name="current">
	<template use="position">
</group>
<!-- Creates: current_x, current_y, current_z, current_heading -->
```

## Arrays

```xml
<u8 name="item_count">
<array name="items" count="var:item_count" max_size="100">
	<u32 name="item_id">
	<str16 name="item_name">
</array>
```

## Advanced Field Attributes

### Type Switching
```xml
<u32 name="stat_value" type2="f32" type2_if="stat_type==6">
```

### Oversized Fields
```xml
<u16 name="large_count" oversized="255">
<u32 name="huge_value" oversized="65535">
```

### Field Modifiers
```xml
<u8 name="data_array" size="10" default="5">
<str16 name="optional_text" optional="true">
<u32 name="hidden_field" add_to_struct="false" add_type="i16">
```

## Complete Attribute Reference

| Attribute | Description | Example |
|-----------|-------------|---------|
| `name` | Field name(s), comma-separated | `"id,account_id"` |
| `use` | Template name to inject | `"position"` |
| `if` | Conditional parsing expression | `"flag:has_guild"` |
| `size` | Fixed array size for `char` type | `"10"` |
| `count` | Array size variable | `"var:item_count"` |
| `substruct` | Reference to substruct | `"ItemInfo"` |
| `oversized` | Threshold for oversized handling | `"255"` |
| `type2` | Alternative field type | `"f32"` |
| `type2_if` | Condition for using type2 | `"stat_type!=6"` |
| `default` | Default value for initialization | `"0"` |
| `max_size` | Maximum array size limit | `"100"` |
| `optional` | Field is optional | `"true"` |
| `add_to_struct` | Include in packet structure | `"false"` |
| `add_type` | Type when adding to packet | `"i16"` |

## Reusable Substructs

```xml
<substruct name="ItemInfo">
	<u32 name="item_id">
	<str16 name="item_name">
	<u8 name="rarity">
</substruct>

<packet name="Inventory">
	<version number="1">
		<u8 name="count">
		<array name="items" count="var:count" substruct="ItemInfo">
	</version>
</packet>
```

## Multiple Versions

```xml
<packet name="PlayerInfo">
	<version number="1">
		<u32 name="id">
		<str16 name="name">
	</version>
	<version number="562">
		<u32 name="id">
		<str16 name="name">
		<color name="skin_color">
	</version>
</packet>
```

## Comments

```xml
<!-- This is a comment -->
<packet name="Test"> <!-- Inline comment -->
	<version number="1">
		<u32 name="id"> <!-- Field comment -->
	</version>
</packet>
```

## Usage

```go
import "eq2emu/internal/parser"

// Parse PML content
packets, err := parser.Parse(pmlContent)
if err != nil {
	log.Fatal(err)
}

// Get packet definition
packet := packets["PacketName"]

// Parse binary data with version and flags
result, err := packet.Parse(data, version, flags)
if err != nil {
	log.Fatal(err)
}

// Access parsed fields
playerID := result["player_id"].(uint32)
playerName := result["player_name"].(common.EQ2String16).Data
```

## Complete Example

```xml
<!-- Define reusable templates -->
<template name="position">
	<f32 name="x,y,z">
	<f32 name="heading">
</template>

<template name="appearance">
	<color name="skin_color,hair_color,eye_color">
	<str16 name="face_file,hair_file">
</template>

<substruct name="StatBonus">
	<u8 name="stat_type">
	<u32 name="base_value" type2="f32" type2_if="stat_type==6">
	<u16 name="bonus_value" if="stat_type!=6">
</substruct>

<packet name="PlayerStats">
	<version number="562">
		<u32 name="player_id,account_id">
		<str16 name="player_name">
		<u8 name="level,race,class">
		<template use="position">
		<template use="appearance" if="version>=562">
		<str16 name="guild_name" if="flag:has_guild">
		<u32 name="guild_id" if="flag:has_guild&level>=10">
		<u8 name="stat_count">
		<array name="stats" count="var:stat_count" max_size="50" substruct="StatBonus">
		<u32 name="special_flags">
		<str16 name="special_ability" if="special_flags&0x01">
		<color name="aura_color" if="special_flags&0x02">
		<str16 name="description" if="description!>0">
	</version>
</packet>
```