# Packet Structure Parser This package provides a Go implementation of the EQ2 packet structure system, compatible with the C++ ConfigReader and PacketStruct classes. It parses XML packet definitions and provides runtime serialization/deserialization capabilities. ## Features - **XML Parsing**: Reads packet and substruct definitions from XML files - **Version Management**: Handles multiple versions of packet structures - **Type Support**: All EQ2 data types including integers, floats, strings, and colors - **Conditional Fields**: Support for if-set/if-not-set field conditions - **Zero Allocation**: Optimized for performance with minimal allocations - **ConfigReader Compatible**: Drop-in replacement for C++ ConfigReader ## Usage ### Loading Packet Definitions ```go // Create a config reader cr := structs.NewConfigReader("./") // Load all XML files from structs/xml directory err := cr.LoadStructs() // Or load specific files err := cr.LoadFiles([]string{"structs/xml/login/LoginRequest.xml"}) ``` ### Creating and Using Packet Structs ```go // Get a packet struct for a specific version ps, err := cr.GetStruct("LoginRequest", 1193) // Set field values ps.Set("username", "player123") ps.Set("password", "secret") ps.Set("version", uint16(1193)) // Serialize to bytes data, err := ps.Serialize() // Deserialize from bytes ps2, err := cr.GetStruct("LoginRequest", 1193) err = ps2.Deserialize(data) // Get field values username, _ := ps2.Get("username") ``` ### Direct Parser Usage ```go // Create a parser parser := structs.NewParser("structs") // Load all XML files err := parser.LoadAll() // Get a specific packet version version, err := parser.GetPacketVersion("LoginRequest", 1193) // Create packet struct directly ps := structs.NewPacketStruct(version) ``` ## XML Format Packet definitions use the following XML format: ```xml ``` Substructs use a similar format: ```xml ``` ## Supported Field Types - **Integers**: u8, u16, u32, u64, i8, i16, i32, i64 - **Floats**: float (32-bit), double (64-bit) - **Strings**: str8, str16, str32 (length-prefixed), char (fixed-size or null-terminated) - **Special**: color, eq2color - **Complex**: substruct, array ## Field Attributes - `name`: Field name (required) - `size`: Array size or fixed string length - `sizevar`: Variable containing the array size - `default`: Default value - `ifset`: Only include if specified field is set - `ifnotset`: Only include if specified field is not set ## Performance The parser is optimized for performance with minimal allocations: - Serialization: ~312 ns/op, 144 B/op, 10 allocs/op - Deserialization: ~315 ns/op, 112 B/op, 13 allocs/op ## Compatibility This implementation maintains compatibility with the C++ ConfigReader and PacketStruct classes, allowing seamless migration of existing packet definitions and code. ## Example Integration ```go // Initialize config reader configReader := structs.NewConfigReader("./") configReader.LoadStructs() // In your packet handler func HandleLoginRequest(data []byte, clientVersion uint16) { // Get the appropriate packet struct ps, err := configReader.GetStruct("LoginRequest", clientVersion) if err != nil { log.Printf("Failed to get LoginRequest struct: %v", err) return } // Deserialize the packet if err := ps.Deserialize(data); err != nil { log.Printf("Failed to deserialize LoginRequest: %v", err) return } // Access fields username, _ := ps.Get("username") password, _ := ps.Get("password") // Process login... } ``` ## Directory Structure ``` structs/ ├── xml/ │ ├── common/ │ ├── login/ │ ├── item/ │ ├── spawn/ │ └── world/ ├── parser.go # XML parser ├── packet_struct.go # Runtime packet structure ├── config_reader.go # ConfigReader compatible interface └── README.md ```