5.8 KiB
5.8 KiB
Packet Definition Parser
Fast XML-like parser for binary packet structures with versioning and conditional fields.
Basic Syntax
<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 |
---|---|---|
i8 , i16 , i32 , i64 |
1-8 bytes | Unsigned integers |
si8 , si16 , si32 , si64 |
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
<i32 name="player_id,account_id">
<f32 name="pos_x,pos_y,pos_z">
Conditional Fields
<str16 name="guild_name" if="flag:has_guild">
<i8 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 comparisonsversion<1200
- Supports>=
,<=
,>
,<
Value Comparisons:
field>=value
- Numeric comparisonsfield!=0
- Supports>=
,<=
,>
,<
,==
,!=
String Length:
name!>5
- String longer than 5 charsname!<=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:
<group>
<i32 name="player_id">
<str16 name="player_name">
</group>
<!-- Creates: player_id, player_name (no prefix added) -->
<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. -->
Arrays
<i8 name="item_count">
<array name="items" count="var:item_count" max_size="100">
<substruct>
<i32 name="item_id">
<str16 name="item_name">
</substruct>
</array>
Advanced Field Attributes
Type Switching
<i32 name="stat_value" type2="f32" type2_if="stat_type==6">
Oversized Fields
<i16 name="large_count" oversized="255">
<i32 name="huge_value" oversized="65535">
Field Modifiers
<i8 name="data_array" size="10" default="5">
<str16 name="optional_text" optional="true">
<i32 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" |
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
<substruct name="ItemInfo">
<i32 name="item_id">
<str16 name="item_name">
<i8 name="rarity">
</substruct>
<packet name="Inventory">
<version number="1">
<i8 name="count">
<array name="items" count="var:count" substruct="ItemInfo">
</version>
</packet>
Multiple Versions
<packet name="PlayerInfo">
<version number="1">
<i32 name="id">
<str16 name="name">
</version>
<version number="562">
<i32 name="id">
<str16 name="name">
<color name="skin_color">
</version>
</packet>
Comments
<!-- This is a comment -->
<packet name="Test"> <!-- Inline comment -->
<version number="1">
<i32 name="id"> <!-- Field comment -->
</version>
</packet>
Usage
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
<substruct name="StatBonus">
<i8 name="stat_type">
<i32 name="base_value" type2="f32" type2_if="stat_type==6">
<i16 name="bonus_value" if="stat_type!=6">
</substruct>
<packet name="PlayerStats">
<version number="562">
<i32 name="player_id,account_id">
<str16 name="player_name">
<i8 name="level,race,class">
<color name="skin_color,hair_color" if="version>=562">
<str16 name="guild_name" if="flag:has_guild">
<i32 name="guild_id" if="flag:has_guild&level>=10">
<i8 name="stat_count">
<array name="stats" count="var:stat_count" max_size="50" substruct="StatBonus">
<i32 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>