188 lines
5.9 KiB
Go
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)
|
|
}
|
|
}
|
|
} |