223 lines
6.8 KiB
Go
223 lines
6.8 KiB
Go
package packets
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// PacketData represents processed packet information
|
|
type PacketData struct {
|
|
Opcode InternalOpcode
|
|
ClientOpcode uint16
|
|
ClientVersion int32
|
|
Data []byte
|
|
Size int32
|
|
}
|
|
|
|
// PacketContext provides context for packet handlers
|
|
type PacketContext struct {
|
|
Client ClientInterface // Client connection interface
|
|
World WorldInterface // World server interface
|
|
Database DatabaseInterface // Database interface
|
|
}
|
|
|
|
// ClientInterface defines the interface that client connections must implement
|
|
type ClientInterface interface {
|
|
GetCharacterID() int32
|
|
GetAccountID() int32
|
|
GetCharacterName() string
|
|
GetClientVersion() int32
|
|
GetAdminLevel() int
|
|
IsInZone() bool
|
|
SendPacket(opcode InternalOpcode, data []byte) error
|
|
Disconnect() error
|
|
}
|
|
|
|
// WorldInterface defines the interface for world server operations
|
|
type WorldInterface interface {
|
|
GetClientByID(characterID int32) ClientInterface
|
|
GetAllClients() []ClientInterface
|
|
BroadcastPacket(opcode InternalOpcode, data []byte)
|
|
BroadcastToZone(zoneID int32, opcode InternalOpcode, data []byte)
|
|
}
|
|
|
|
// DatabaseInterface defines database operations needed by packet handlers
|
|
type DatabaseInterface interface {
|
|
GetCharacter(characterID int32) (map[string]any, error)
|
|
SaveCharacter(characterID int32, data map[string]any) error
|
|
// Add more database methods as needed
|
|
}
|
|
|
|
// PacketHandlerFunc defines the signature for packet handler functions
|
|
type PacketHandlerFunc func(ctx *PacketContext, packet *PacketData) error
|
|
|
|
// PacketHandlerRegistry manages registration and dispatch of packet handlers
|
|
type PacketHandlerRegistry struct {
|
|
handlers map[InternalOpcode]PacketHandlerFunc
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// NewPacketHandlerRegistry creates a new packet handler registry
|
|
func NewPacketHandlerRegistry() *PacketHandlerRegistry {
|
|
return &PacketHandlerRegistry{
|
|
handlers: make(map[InternalOpcode]PacketHandlerFunc),
|
|
}
|
|
}
|
|
|
|
// RegisterHandler registers a handler for a specific opcode
|
|
func (phr *PacketHandlerRegistry) RegisterHandler(opcode InternalOpcode, handler PacketHandlerFunc) {
|
|
phr.mutex.Lock()
|
|
defer phr.mutex.Unlock()
|
|
|
|
phr.handlers[opcode] = handler
|
|
fmt.Printf("Registered handler for opcode %s (%d)\n", GetInternalOpcodeName(opcode), int(opcode))
|
|
}
|
|
|
|
// UnregisterHandler removes a handler for a specific opcode
|
|
func (phr *PacketHandlerRegistry) UnregisterHandler(opcode InternalOpcode) {
|
|
phr.mutex.Lock()
|
|
defer phr.mutex.Unlock()
|
|
|
|
delete(phr.handlers, opcode)
|
|
}
|
|
|
|
// HasHandler checks if a handler is registered for an opcode
|
|
func (phr *PacketHandlerRegistry) HasHandler(opcode InternalOpcode) bool {
|
|
phr.mutex.RLock()
|
|
defer phr.mutex.RUnlock()
|
|
|
|
_, exists := phr.handlers[opcode]
|
|
return exists
|
|
}
|
|
|
|
// HandlePacket dispatches a packet to its registered handler
|
|
func (phr *PacketHandlerRegistry) HandlePacket(ctx *PacketContext, packet *PacketData) error {
|
|
phr.mutex.RLock()
|
|
handler, exists := phr.handlers[packet.Opcode]
|
|
phr.mutex.RUnlock()
|
|
|
|
if !exists {
|
|
// No handler registered - this is not necessarily an error
|
|
fmt.Printf("No handler registered for opcode %s (%d) from client %s\n",
|
|
GetInternalOpcodeName(packet.Opcode),
|
|
int(packet.Opcode),
|
|
ctx.Client.GetCharacterName())
|
|
return nil
|
|
}
|
|
|
|
// Call the handler
|
|
return handler(ctx, packet)
|
|
}
|
|
|
|
// GetHandlerCount returns the number of registered handlers
|
|
func (phr *PacketHandlerRegistry) GetHandlerCount() int {
|
|
phr.mutex.RLock()
|
|
defer phr.mutex.RUnlock()
|
|
|
|
return len(phr.handlers)
|
|
}
|
|
|
|
// GetRegisteredOpcodes returns all opcodes with registered handlers
|
|
func (phr *PacketHandlerRegistry) GetRegisteredOpcodes() []InternalOpcode {
|
|
phr.mutex.RLock()
|
|
defer phr.mutex.RUnlock()
|
|
|
|
opcodes := make([]InternalOpcode, 0, len(phr.handlers))
|
|
for opcode := range phr.handlers {
|
|
opcodes = append(opcodes, opcode)
|
|
}
|
|
|
|
return opcodes
|
|
}
|
|
|
|
// PacketProcessor combines opcode management and handler dispatch
|
|
type PacketProcessor struct {
|
|
opcodeManager *OpcodeManager
|
|
handlerRegistry *PacketHandlerRegistry
|
|
}
|
|
|
|
// NewPacketProcessor creates a new packet processor
|
|
func NewPacketProcessor() *PacketProcessor {
|
|
return &PacketProcessor{
|
|
opcodeManager: GetOpcodeManager(),
|
|
handlerRegistry: NewPacketHandlerRegistry(),
|
|
}
|
|
}
|
|
|
|
// ProcessRawPacket processes a raw packet from the UDP layer
|
|
func (pp *PacketProcessor) ProcessRawPacket(ctx *PacketContext, rawData []byte, clientOpcode uint16) error {
|
|
if len(rawData) < 2 {
|
|
return fmt.Errorf("packet too short: %d bytes", len(rawData))
|
|
}
|
|
|
|
// Convert client opcode to internal opcode
|
|
clientVersion := ctx.Client.GetClientVersion()
|
|
internalOpcode := pp.opcodeManager.ClientOpcodeToInternal(clientVersion, clientOpcode)
|
|
|
|
if internalOpcode == OP_Unknown {
|
|
fmt.Printf("Unknown opcode 0x%04X from client version %d (client: %s)\n",
|
|
clientOpcode, clientVersion, ctx.Client.GetCharacterName())
|
|
return nil // Don't treat unknown opcodes as errors
|
|
}
|
|
|
|
// Create packet data structure
|
|
packet := &PacketData{
|
|
Opcode: internalOpcode,
|
|
ClientOpcode: clientOpcode,
|
|
ClientVersion: clientVersion,
|
|
Data: rawData,
|
|
Size: int32(len(rawData)),
|
|
}
|
|
|
|
// Dispatch to handler
|
|
return pp.handlerRegistry.HandlePacket(ctx, packet)
|
|
}
|
|
|
|
// RegisterHandler registers a packet handler
|
|
func (pp *PacketProcessor) RegisterHandler(opcode InternalOpcode, handler PacketHandlerFunc) {
|
|
pp.handlerRegistry.RegisterHandler(opcode, handler)
|
|
}
|
|
|
|
// LoadOpcodeMap loads opcode mappings for a client version
|
|
func (pp *PacketProcessor) LoadOpcodeMap(clientVersion int32, opcodeMap map[string]uint16) error {
|
|
return pp.opcodeManager.LoadOpcodeMap(clientVersion, opcodeMap)
|
|
}
|
|
|
|
// GetStats returns processor statistics
|
|
func (pp *PacketProcessor) GetStats() (int, int, []int32) {
|
|
handlerCount := pp.handlerRegistry.GetHandlerCount()
|
|
supportedVersions := pp.opcodeManager.GetSupportedVersions()
|
|
totalOpcodes := 0
|
|
|
|
for _, version := range supportedVersions {
|
|
totalOpcodes += pp.opcodeManager.GetOpcodeCount(version)
|
|
}
|
|
|
|
return handlerCount, totalOpcodes, supportedVersions
|
|
}
|
|
|
|
// Global packet processor instance
|
|
var globalPacketProcessor = NewPacketProcessor()
|
|
|
|
// GetPacketProcessor returns the global packet processor
|
|
func GetPacketProcessor() *PacketProcessor {
|
|
return globalPacketProcessor
|
|
}
|
|
|
|
// Convenience functions for global access
|
|
|
|
// RegisterGlobalHandler registers a handler with the global processor
|
|
func RegisterGlobalHandler(opcode InternalOpcode, handler PacketHandlerFunc) {
|
|
globalPacketProcessor.RegisterHandler(opcode, handler)
|
|
}
|
|
|
|
// ProcessGlobalPacket processes a packet with the global processor
|
|
func ProcessGlobalPacket(ctx *PacketContext, rawData []byte, clientOpcode uint16) error {
|
|
return globalPacketProcessor.ProcessRawPacket(ctx, rawData, clientOpcode)
|
|
}
|
|
|
|
// LoadGlobalOpcodeMappings loads opcode mappings with the global processor
|
|
func LoadGlobalOpcodeMappings(clientVersion int32, opcodeMap map[string]uint16) error {
|
|
return globalPacketProcessor.LoadOpcodeMap(clientVersion, opcodeMap)
|
|
}
|