1
0
Protocol/cmd_opcodes_example.go
2025-09-01 14:03:38 -05:00

188 lines
5.9 KiB
Go

package eq2net
import (
"fmt"
"log"
)
// ExampleOpcodeData provides sample opcode data for different client versions
// In production, this would be loaded from files or generated from packet captures
var ExampleOpcodeData = map[uint16]map[string]uint16{
// Version 1193 opcodes (example values)
1193: {
"OP_LoginRequestMsg": 0x00B3,
"OP_LoginByNumRequestMsg": 0x00B4,
"OP_WSLoginRequestMsg": 0x00B5,
"OP_LoginReplyMsg": 0x00B6,
"OP_WSStatusReplyMsg": 0x00B7,
"OP_WorldListMsg": 0x00B8,
"OP_WorldStatusMsg": 0x00B9,
"OP_DeleteCharacterRequestMsg": 0x00BA,
"OP_DeleteCharacterReplyMsg": 0x00BB,
"OP_CreateCharacterRequestMsg": 0x00BC,
"OP_CreateCharacterReplyMsg": 0x00BD,
"OP_PlayCharacterRequestMsg": 0x00BE,
"OP_PlayCharacterReplyMsg": 0x00BF,
"OP_ServerListRequestMsg": 0x00C0,
"OP_ServerListReplyMsg": 0x00C1,
"OP_CharacterListRequestMsg": 0x00C2,
"OP_CharacterListReplyMsg": 0x00C3,
},
// Version 1208 opcodes (example values)
1208: {
"OP_LoginRequestMsg": 0x00D1,
"OP_LoginByNumRequestMsg": 0x00D2,
"OP_WSLoginRequestMsg": 0x00D3,
"OP_LoginReplyMsg": 0x00D4,
"OP_WSStatusReplyMsg": 0x00D5,
"OP_WorldListMsg": 0x00D6,
"OP_WorldStatusMsg": 0x00D7,
"OP_DeleteCharacterRequestMsg": 0x00D8,
"OP_DeleteCharacterReplyMsg": 0x00D9,
"OP_CreateCharacterRequestMsg": 0x00DA,
"OP_CreateCharacterReplyMsg": 0x00DB,
"OP_PlayCharacterRequestMsg": 0x00DC,
"OP_PlayCharacterReplyMsg": 0x00DD,
"OP_ServerListRequestMsg": 0x00DE,
"OP_ServerListReplyMsg": 0x00DF,
"OP_CharacterListRequestMsg": 0x00E0,
"OP_CharacterListReplyMsg": 0x00E1,
},
}
// ImportExampleOpcodes imports the example opcode data into the database
func ImportExampleOpcodes(service *OpcodeService) error {
for version, opcodes := range ExampleOpcodeData {
log.Printf("Importing %d opcodes for version %d", len(opcodes), version)
if err := service.ImportOpcodes(version, opcodes); err != nil {
return fmt.Errorf("failed to import opcodes for version %d: %w", version, err)
}
}
log.Println("Successfully imported all example opcodes")
return nil
}
// PrintOpcodeTable prints a formatted table of opcodes for a version
func PrintOpcodeTable(service *OpcodeService, version uint16) error {
manager, err := service.GetManager(version)
if err != nil {
return fmt.Errorf("failed to get opcode manager for version %d: %w", version, err)
}
fmt.Printf("\n=== Opcodes for Client Version %d ===\n", version)
fmt.Printf("%-30s | %-10s | %-10s\n", "Opcode Name", "Emu Value", "EQ Value")
fmt.Printf("%-30s-+-%-10s-+-%-10s\n", "------------------------------",
"----------", "----------")
// Print all known opcodes
for emuOpcode, name := range OpcodeNames {
eqOpcode := manager.EmuToEQ(emuOpcode)
if eqOpcode != 0xFFFF {
fmt.Printf("%-30s | 0x%04X | 0x%04X\n", name, emuOpcode, eqOpcode)
}
}
return nil
}
// VerifyOpcodeIntegrity checks that opcode mappings are bidirectional
func VerifyOpcodeIntegrity(service *OpcodeService, version uint16) error {
manager, err := service.GetManager(version)
if err != nil {
return fmt.Errorf("failed to get opcode manager for version %d: %w", version, err)
}
errors := 0
for emuOpcode := range OpcodeNames {
eqOpcode := manager.EmuToEQ(emuOpcode)
if eqOpcode != 0xFFFF {
// Verify reverse mapping
reverseEmu := manager.EQToEmu(eqOpcode)
if reverseEmu != emuOpcode {
fmt.Printf("ERROR: Bidirectional mapping failed for %s (0x%04X)\n",
OpcodeNames[emuOpcode], emuOpcode)
fmt.Printf(" EmuToEQ: 0x%04X -> 0x%04X\n", emuOpcode, eqOpcode)
fmt.Printf(" EQToEmu: 0x%04X -> 0x%04X\n", eqOpcode, reverseEmu)
errors++
}
}
}
if errors > 0 {
return fmt.Errorf("found %d opcode integrity errors", errors)
}
fmt.Printf("✓ All opcode mappings verified for version %d\n", version)
return nil
}
// ExampleUsage demonstrates how to use the opcode system
func ExampleUsage() {
// Connect to database
dsn := "root:Root12!@tcp(localhost:3306)/eq2test?parseTime=true"
db, err := ConnectDB(dsn)
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
defer db.Close()
// Create tables if needed
if err := CreateOpcodeTable(db); err != nil {
log.Fatalf("Failed to create opcodes table: %v", err)
}
// Create opcode service
service := NewOpcodeService(db)
// Import example opcodes
if err := ImportExampleOpcodes(service); err != nil {
log.Fatalf("Failed to import example opcodes: %v", err)
}
// Print opcode tables
for version := range ExampleOpcodeData {
if err := PrintOpcodeTable(service, version); err != nil {
log.Printf("Failed to print opcodes for version %d: %v", version, err)
}
if err := VerifyOpcodeIntegrity(service, version); err != nil {
log.Printf("Integrity check failed for version %d: %v", version, err)
}
}
// Example: Get manager for specific client version
clientVersion := uint16(1193)
opcodeVersion := GetOpcodeVersion(clientVersion)
manager, err := service.GetManager(opcodeVersion)
if err != nil {
log.Fatalf("Failed to get opcode manager: %v", err)
}
// Example: Convert opcodes
fmt.Printf("\n=== Example Opcode Conversions (Version %d) ===\n", opcodeVersion)
// Emu to EQ
emuOp := OP_LoginRequestMsg
eqOp := manager.EmuToEQ(emuOp)
fmt.Printf("EmuToEQ: %s (0x%04X) -> 0x%04X\n",
OpcodeNames[emuOp], emuOp, eqOp)
// EQ to Emu
eqOp = 0x00B8 // OP_WorldListMsg for version 1193
emuOp = manager.EQToEmu(eqOp)
fmt.Printf("EQToEmu: 0x%04X -> %s (0x%04X)\n",
eqOp, OpcodeNames[emuOp], emuOp)
// Get all supported versions
versions, err := service.GetSupportedVersions()
if err != nil {
log.Printf("Failed to get supported versions: %v", err)
} else {
fmt.Printf("\n=== Supported Client Versions ===\n")
for _, v := range versions {
fmt.Printf(" Version %d\n", v)
}
}
}