diff --git a/README.md b/README.md index 52765f9..e42e6c6 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,335 @@ 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 -development pipeline - and as a personal experiment. \ No newline at end of file +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. \ No newline at end of file