package packets import ( "fmt" "sync" ) // InternalOpcode represents the internal opcode enumeration type InternalOpcode int32 // Internal opcode constants - these map to the C++ EmuOpcode enum const ( OP_Unknown InternalOpcode = iota // Login and authentication operations OP_LoginReplyMsg OP_LoginByNumRequestMsg OP_WSLoginRequestMsg // Server initialization and zone management OP_ESInitMsg OP_ESReadyForClientsMsg OP_CreateZoneInstanceMsg OP_ZoneInstanceCreateReplyMsg OP_ZoneInstanceDestroyedMsg OP_ExpectClientAsCharacterRequest OP_ExpectClientAsCharacterReplyMs OP_ZoneInfoMsg // Character creation and loading OP_CreateCharacterRequestMsg OP_DoneLoadingZoneResourcesMsg OP_DoneSendingInitialEntitiesMsg OP_DoneLoadingEntityResourcesMsg OP_DoneLoadingUIResourcesMsg // Game state updates OP_PredictionUpdateMsg OP_RemoteCmdMsg OP_SetRemoteCmdsMsg OP_GameWorldTimeMsg OP_MOTDMsg OP_ZoneMOTDMsg // Command dispatching OP_ClientCmdMsg OP_DispatchClientCmdMsg OP_DispatchESMsg // Character sheet and inventory updates OP_UpdateCharacterSheetMsg OP_UpdateSpellBookMsg OP_UpdateInventoryMsg // Zone transitions OP_ChangeZoneMsg OP_ClientTeleportRequestMsg OP_TeleportWithinZoneMsg OP_ReadyToZoneMsg // Chat system OP_ChatTellChannelMsg OP_ChatTellUserMsg // Position updates OP_UpdatePositionMsg // Achievement system OP_AchievementUpdateMsg OP_CharacterAchievements // Title system OP_TitleUpdateMsg OP_CharacterTitles OP_SetActiveTitleMsg // NPC system OP_NPCAttackMsg OP_NPCTargetMsg OP_NPCInfoMsg OP_NPCSpellCastMsg OP_NPCMovementMsg // EverQuest specific commands - Core OP_EqHearChatCmd OP_EqDisplayTextCmd OP_EqCreateGhostCmd OP_EqCreateWidgetCmd OP_EqDestroyGhostCmd OP_EqUpdateGhostCmd OP_EqSetControlGhostCmd OP_EqSetPOVGhostCmd // Add more opcodes as needed... _maxInternalOpcode // Sentinel value ) // OpcodeNames maps internal opcodes to their string names for debugging var OpcodeNames = map[InternalOpcode]string{ OP_Unknown: "OP_Unknown", OP_LoginReplyMsg: "OP_LoginReplyMsg", OP_LoginByNumRequestMsg: "OP_LoginByNumRequestMsg", OP_WSLoginRequestMsg: "OP_WSLoginRequestMsg", OP_ESInitMsg: "OP_ESInitMsg", OP_ESReadyForClientsMsg: "OP_ESReadyForClientsMsg", OP_CreateZoneInstanceMsg: "OP_CreateZoneInstanceMsg", OP_ZoneInstanceCreateReplyMsg: "OP_ZoneInstanceCreateReplyMsg", OP_ZoneInstanceDestroyedMsg: "OP_ZoneInstanceDestroyedMsg", OP_ExpectClientAsCharacterRequest: "OP_ExpectClientAsCharacterRequest", OP_ExpectClientAsCharacterReplyMs: "OP_ExpectClientAsCharacterReplyMs", OP_ZoneInfoMsg: "OP_ZoneInfoMsg", OP_CreateCharacterRequestMsg: "OP_CreateCharacterRequestMsg", OP_DoneLoadingZoneResourcesMsg: "OP_DoneLoadingZoneResourcesMsg", OP_DoneSendingInitialEntitiesMsg: "OP_DoneSendingInitialEntitiesMsg", OP_DoneLoadingEntityResourcesMsg: "OP_DoneLoadingEntityResourcesMsg", OP_DoneLoadingUIResourcesMsg: "OP_DoneLoadingUIResourcesMsg", OP_PredictionUpdateMsg: "OP_PredictionUpdateMsg", OP_RemoteCmdMsg: "OP_RemoteCmdMsg", OP_SetRemoteCmdsMsg: "OP_SetRemoteCmdsMsg", OP_GameWorldTimeMsg: "OP_GameWorldTimeMsg", OP_MOTDMsg: "OP_MOTDMsg", OP_ZoneMOTDMsg: "OP_ZoneMOTDMsg", OP_ClientCmdMsg: "OP_ClientCmdMsg", OP_DispatchClientCmdMsg: "OP_DispatchClientCmdMsg", OP_DispatchESMsg: "OP_DispatchESMsg", OP_UpdateCharacterSheetMsg: "OP_UpdateCharacterSheetMsg", OP_UpdateSpellBookMsg: "OP_UpdateSpellBookMsg", OP_UpdateInventoryMsg: "OP_UpdateInventoryMsg", OP_ChangeZoneMsg: "OP_ChangeZoneMsg", OP_ClientTeleportRequestMsg: "OP_ClientTeleportRequestMsg", OP_TeleportWithinZoneMsg: "OP_TeleportWithinZoneMsg", OP_ReadyToZoneMsg: "OP_ReadyToZoneMsg", OP_ChatTellChannelMsg: "OP_ChatTellChannelMsg", OP_ChatTellUserMsg: "OP_ChatTellUserMsg", OP_UpdatePositionMsg: "OP_UpdatePositionMsg", OP_AchievementUpdateMsg: "OP_AchievementUpdateMsg", OP_CharacterAchievements: "OP_CharacterAchievements", OP_TitleUpdateMsg: "OP_TitleUpdateMsg", OP_CharacterTitles: "OP_CharacterTitles", OP_SetActiveTitleMsg: "OP_SetActiveTitleMsg", OP_NPCAttackMsg: "OP_NPCAttackMsg", OP_NPCTargetMsg: "OP_NPCTargetMsg", OP_NPCInfoMsg: "OP_NPCInfoMsg", OP_NPCSpellCastMsg: "OP_NPCSpellCastMsg", OP_NPCMovementMsg: "OP_NPCMovementMsg", OP_EqHearChatCmd: "OP_EqHearChatCmd", OP_EqDisplayTextCmd: "OP_EqDisplayTextCmd", OP_EqCreateGhostCmd: "OP_EqCreateGhostCmd", OP_EqCreateWidgetCmd: "OP_EqCreateWidgetCmd", OP_EqDestroyGhostCmd: "OP_EqDestroyGhostCmd", OP_EqUpdateGhostCmd: "OP_EqUpdateGhostCmd", OP_EqSetControlGhostCmd: "OP_EqSetControlGhostCmd", OP_EqSetPOVGhostCmd: "OP_EqSetPOVGhostCmd", } // OpcodeManager handles the mapping between client-specific opcodes and internal opcodes type OpcodeManager struct { // Maps client version -> (client opcode -> internal opcode) clientToInternal map[int32]map[uint16]InternalOpcode // Maps internal opcode -> client version -> client opcode internalToClient map[InternalOpcode]map[int32]uint16 mutex sync.RWMutex } // NewOpcodeManager creates a new opcode manager func NewOpcodeManager() *OpcodeManager { return &OpcodeManager{ clientToInternal: make(map[int32]map[uint16]InternalOpcode), internalToClient: make(map[InternalOpcode]map[int32]uint16), } } // LoadOpcodeMap loads opcode mappings for a specific client version func (om *OpcodeManager) LoadOpcodeMap(clientVersion int32, opcodeMap map[string]uint16) error { om.mutex.Lock() defer om.mutex.Unlock() // Initialize maps for this client version if om.clientToInternal[clientVersion] == nil { om.clientToInternal[clientVersion] = make(map[uint16]InternalOpcode) } // Process each opcode mapping for opcodeName, clientOpcode := range opcodeMap { // Find the internal opcode for this name internalOpcode := OP_Unknown for intOp, name := range OpcodeNames { if name == opcodeName { internalOpcode = intOp break } } if internalOpcode == OP_Unknown && opcodeName != "OP_Unknown" { // Log warning for unknown opcode but don't fail fmt.Printf("Warning: Unknown internal opcode name: %s\n", opcodeName) continue } // Set client -> internal mapping om.clientToInternal[clientVersion][clientOpcode] = internalOpcode // Set internal -> client mapping if om.internalToClient[internalOpcode] == nil { om.internalToClient[internalOpcode] = make(map[int32]uint16) } om.internalToClient[internalOpcode][clientVersion] = clientOpcode } fmt.Printf("Loaded %d opcode mappings for client version %d\n", len(opcodeMap), clientVersion) return nil } // ClientOpcodeToInternal converts a client opcode to internal opcode func (om *OpcodeManager) ClientOpcodeToInternal(clientVersion int32, clientOpcode uint16) InternalOpcode { om.mutex.RLock() defer om.mutex.RUnlock() if versionMap, exists := om.clientToInternal[clientVersion]; exists { if internalOp, found := versionMap[clientOpcode]; found { return internalOp } } return OP_Unknown } // InternalOpcodeToClient converts an internal opcode to client opcode func (om *OpcodeManager) InternalOpcodeToClient(internalOpcode InternalOpcode, clientVersion int32) uint16 { om.mutex.RLock() defer om.mutex.RUnlock() if versionMap, exists := om.internalToClient[internalOpcode]; exists { if clientOp, found := versionMap[clientVersion]; found { return clientOp } } return 0 // Invalid client opcode } // GetOpcodeName returns the human-readable name for an internal opcode func (om *OpcodeManager) GetOpcodeName(internalOpcode InternalOpcode) string { if name, exists := OpcodeNames[internalOpcode]; exists { return name } return "OP_Unknown" } // GetSupportedVersions returns all client versions with loaded opcodes func (om *OpcodeManager) GetSupportedVersions() []int32 { om.mutex.RLock() defer om.mutex.RUnlock() versions := make([]int32, 0, len(om.clientToInternal)) for version := range om.clientToInternal { versions = append(versions, version) } return versions } // GetOpcodeCount returns the number of opcodes loaded for a client version func (om *OpcodeManager) GetOpcodeCount(clientVersion int32) int { om.mutex.RLock() defer om.mutex.RUnlock() if versionMap, exists := om.clientToInternal[clientVersion]; exists { return len(versionMap) } return 0 } // Global opcode manager instance var globalOpcodeManager = NewOpcodeManager() // GetOpcodeManager returns the global opcode manager func GetOpcodeManager() *OpcodeManager { return globalOpcodeManager } // Convenience functions for global access // LoadGlobalOpcodeMap loads opcodes into the global manager func LoadGlobalOpcodeMap(clientVersion int32, opcodeMap map[string]uint16) error { return globalOpcodeManager.LoadOpcodeMap(clientVersion, opcodeMap) } // ClientToInternal converts using the global manager func ClientToInternal(clientVersion int32, clientOpcode uint16) InternalOpcode { return globalOpcodeManager.ClientOpcodeToInternal(clientVersion, clientOpcode) } // InternalToClient converts using the global manager func InternalToClient(internalOpcode InternalOpcode, clientVersion int32) uint16 { return globalOpcodeManager.InternalOpcodeToClient(internalOpcode, clientVersion) } // GetInternalOpcodeName returns name using the global manager func GetInternalOpcodeName(internalOpcode InternalOpcode) string { return globalOpcodeManager.GetOpcodeName(internalOpcode) }