1
0
Protocol/structs/README.md

174 lines
4.5 KiB
Markdown

# 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
<packet name="LoginRequest">
<version number="1">
<str16 name="username"/>
<str16 name="password"/>
<u32 name="acctNum"/>
<u16 name="version"/>
</version>
<version number="562">
<str16 name="accesscode"/>
<str16 name="username"/>
<str16 name="password"/>
<u8 name="unknown" size="8"/>
<u32 name="version"/>
</version>
</packet>
```
Substructs use a similar format:
```xml
<substruct name="Item">
<version number="1">
<u32 name="unique_id"/>
<u32 name="bag_id"/>
<u8 name="slot_id"/>
<char name="name" size="64"/>
</version>
</substruct>
```
## 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
```