1
0

fill out readme

This commit is contained in:
Sky Johnson 2025-09-05 18:42:57 -05:00
parent 6d57815a14
commit c5d5998c8a

333
README.md
View File

@ -2,4 +2,335 @@
This library is meant to replicate EverQuest 2's UDP protocol. The work here is based on the immense This library is meant to replicate EverQuest 2's UDP protocol. The work here is based on the immense
work done by contributors to the EQ2Emu project. I am porting it to Go with the idea of a simpler, faster work done by contributors to the EQ2Emu project. I am porting it to Go with the idea of a simpler, faster
development pipeline - and as a personal experiment. development pipeline - and as a personal experiment.
## Opcodes
The opcodes package manages the mapping between internal emulator opcodes and client-specific opcodes across different client versions.
### OpcodeManager
The `OpcodeManager` handles opcode translation for specific client versions:
```go
import "git.sharkk.net/EQ2/Protocol/opcodes"
// Create a manager for client version 60085
om := opcodes.NewOpcodeManager(60085)
// Load opcode mappings from database
err := om.LoadFromDatabase(db, "opcodes_table")
// Convert between emulator and client opcodes
clientOpcode := om.EmuToEQ(opcodes.OP_LoginRequestMsg)
emuOpcode := om.EQToEmu(0x0123)
// Get opcode names
name := om.EmuToName(opcodes.OP_LoginRequestMsg)
```
### Opcode Types
- **EmuOpcode**: Internal emulator opcodes (constants like `OP_LoginRequestMsg`)
- **Protocol opcodes**: Low-level protocol opcodes (e.g., `OP_SessionRequest`, `OP_Packet`)
- **Client opcodes**: Version-specific opcodes sent to/from the game client
### Global Manager Cache
```go
// Get or create a manager for a specific version
mgr := opcodes.GetManager(version, db, tableName)
// Get all loaded versions
versions := opcodes.GetLoadedVersions()
```
## Packet Definitions
The defs package provides structured packet definitions with automatic version selection based on client version.
### PacketManager
Manages packet structure lookups with version-aware selection:
```go
import "git.sharkk.net/EQ2/Protocol/defs"
// Create a manager for client version 60085
pm := defs.NewPacketManager(60085)
// Get the appropriate packet struct for this version
ps := pm.GetStruct("CreateCharacter", 60085)
// Returns CreateCharacterV60085 struct
// Get by exact version
ps := pm.GetStructByVersion("CreateCharacter", 373)
// Get by opcode
ps := pm.GetStructByOpcode(opcodes.OP_CreateCharacterRequestMsg)
// Create a new packet instance
packet := pm.CreateInstance("CreateCharacter")
```
### Version Selection
The manager automatically selects the highest packet version that doesn't exceed the client version:
- Client 1000 requesting "CreateCharacter" gets version 869
- Client 60085 requesting "CreateCharacter" gets version 60085
- Client 70000 requesting "CreateCharacter" gets version 65534
### Code Generation
Packet structures and registrations are generated from XML definitions:
```bash
# Regenerate packet structures from XML
cd defs && go generate
# XML definitions are in defs/xml/
# Generated code goes to defs/generated/
```
## Packets
The packets package provides base packet types and interfaces for all protocol packets.
### Packet Interface
All packets implement the `Packet` interface:
```go
type Packet interface {
GetOpcode() uint16
SetOpcode(uint16)
GetVersion() uint16
SetVersion(uint16)
GetSequence() uint16
SetSequence(uint16)
GetData() []byte
GetSize() uint32
}
```
### Base Packet Types
```go
// RawPacket - Basic packet with opcode and data
packet := &packets.RawPacket{
Opcode: 0x0123,
Data: []byte{...},
}
// EncodedPacket - Packet with protocol encoding
encoded := &packets.EncodedPacket{
Sequence: seq,
Opcode: opcode,
Data: data,
Compressed: false,
}
```
### Packet Processing
```go
// Check if packet needs processing
if packet.ShouldCombine() {
// Handle combined packets
}
if packet.IsProtocolPacket() {
// Handle protocol-level packets
}
// Encode for transmission
encoded := packet.Encode()
// Decode received data
packet, err := packets.Decode(data)
```
## Stream
The stream package handles bidirectional packet streaming with buffering, fragmentation, and reassembly.
### PacketStream
Manages packet flow between client and server:
```go
import "git.sharkk.net/EQ2/Protocol/stream"
// Create a new packet stream
stream := stream.NewPacketStream(conn, bufferSize)
// Set packet handlers
stream.SetIncomingHandler(func(packet packets.Packet) {
// Process incoming packets
})
stream.SetOutgoingHandler(func(packet packets.Packet) {
// Process outgoing packets
})
// Start processing
stream.Start()
// Send a packet
err := stream.Send(packet)
// Receive packets (handled by callback)
// Packets are automatically decoded and reassembled
```
### Features
- **Automatic fragmentation**: Large packets are split into fragments
- **Reassembly**: Fragments are automatically reassembled
- **Buffering**: Configurable send/receive buffers
- **Sequencing**: Automatic sequence number management
- **Compression**: Optional packet compression support
### Stream Configuration
```go
config := &stream.Config{
MaxPacketSize: 512,
BufferSize: 8192,
EnableCompression: true,
Timeout: 30 * time.Second,
}
stream := stream.NewPacketStreamWithConfig(conn, config)
```
## Factory
The factory package provides centralized packet creation and registration.
### PacketFactory
Creates packets based on opcodes and manages packet type registration:
```go
import "git.sharkk.net/EQ2/Protocol/factory"
// Get the global factory instance
factory := factory.GetInstance()
// Register a packet type
factory.RegisterPacket(opcodes.OP_LoginRequestMsg, func() packets.Packet {
return &LoginRequestPacket{}
})
// Create a packet by opcode
packet := factory.CreatePacket(opcodes.OP_LoginRequestMsg)
// Create with data
packet := factory.CreatePacketWithData(opcode, data)
// Create from raw bytes (auto-detects type)
packet, err := factory.CreateFromBytes(rawData)
```
### Packet Registration
Packets can be registered globally or per-version:
```go
// Register for all versions
factory.RegisterPacket(opcode, constructor)
// Register version-specific
factory.RegisterVersionedPacket(opcode, version, constructor)
// Bulk registration
factory.RegisterPackets(map[uint16]PacketConstructor{
opcodes.OP_LoginRequestMsg: NewLoginRequest,
opcodes.OP_CharacterCreate: NewCharacterCreate,
})
```
### Integration with PacketManager
The factory can work with the defs package for automatic struct-based packets:
```go
// Set packet manager for automatic struct registration
factory.SetPacketManager(defs.GetManager(version))
// Now factory can create packets from struct definitions
packet := factory.CreatePacket(opcodes.OP_CreateCharacterRequestMsg)
// Returns properly versioned CreateCharacter struct
```
## Usage Example
Complete example showing protocol usage:
```go
package main
import (
"git.sharkk.net/EQ2/Protocol/opcodes"
"git.sharkk.net/EQ2/Protocol/defs"
"git.sharkk.net/EQ2/Protocol/stream"
"git.sharkk.net/EQ2/Protocol/factory"
)
func main() {
version := uint16(60085)
// Initialize managers
opcodeManager := opcodes.GetManager(version, db, "opcodes")
packetManager := defs.GetManager(version)
// Setup factory
factory := factory.GetInstance()
factory.SetPacketManager(packetManager)
// Create stream for connection
stream := stream.NewPacketStream(conn, 8192)
// Handle incoming packets
stream.SetIncomingHandler(func(packet packets.Packet) {
// Translate opcode
emuOpcode := opcodeManager.EQToEmu(packet.GetOpcode())
// Process based on opcode
switch emuOpcode {
case opcodes.OP_LoginRequestMsg:
handleLogin(packet)
case opcodes.OP_CreateCharacterRequestMsg:
handleCharacterCreate(packet)
}
})
// Send a packet
packet := packetManager.CreateInstance("LSWorldList")
populateWorldList(packet)
// Convert to client opcode
clientOpcode := opcodeManager.EmuToEQ(opcodes.OP_WorldListMsg)
packet.SetOpcode(clientOpcode)
// Send to client
stream.Send(packet)
// Start processing
stream.Start()
}
```
## Protocol Architecture
The protocol library is organized in layers:
1. **Opcodes**: Manages opcode mappings and translations
2. **Defs**: Defines packet structures with version management
3. **Packets**: Base packet types and interfaces
4. **Factory**: Creates packet instances from opcodes/data
5. **Stream**: Handles network I/O, fragmentation, and reassembly
Each layer builds on the previous, providing a complete protocol implementation for EQ2 server emulation.