Compare commits
10 Commits
4b2e0b2f26
...
4ecdcc868f
Author | SHA1 | Date | |
---|---|---|---|
4ecdcc868f | |||
1a9b7effa6 | |||
fd2ebfd6cc | |||
50d4d9d6f0 | |||
d70daa98be | |||
c692b25ac0 | |||
9cc3273a81 | |||
7a7ff3f6ba | |||
ef7dd9d4ef | |||
868ab62573 |
@ -55,3 +55,8 @@ func (c *Ciphers) Encrypt(data []byte) {
|
|||||||
c.server.XORKeyStream(data, data)
|
c.server.XORKeyStream(data, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEncrypted returns true if encryption is active
|
||||||
|
func (c *Ciphers) IsEncrypted() bool {
|
||||||
|
return c != nil && c.server != nil
|
||||||
|
}
|
||||||
|
646
opcodes/emu.go
Normal file
646
opcodes/emu.go
Normal file
@ -0,0 +1,646 @@
|
|||||||
|
package opcodes
|
||||||
|
|
||||||
|
// Emulator/Application opcodes - Complete list from emu_oplist.h
|
||||||
|
const (
|
||||||
|
OP_Unknown EmuOpcode = 0x0000
|
||||||
|
|
||||||
|
// Login and session management
|
||||||
|
OP_LoginReplyMsg EmuOpcode = 0x0001
|
||||||
|
OP_LoginByNumRequestMsg EmuOpcode = 0x0002
|
||||||
|
OP_WSLoginRequestMsg EmuOpcode = 0x0003
|
||||||
|
OP_ESInitMsg EmuOpcode = 0x0004
|
||||||
|
OP_ESReadyForClientsMsg EmuOpcode = 0x0005
|
||||||
|
|
||||||
|
// Zone instance management
|
||||||
|
OP_CreateZoneInstanceMsg EmuOpcode = 0x0010
|
||||||
|
OP_ZoneInstanceCreateReplyMsg EmuOpcode = 0x0011
|
||||||
|
OP_ZoneInstanceDestroyedMsg EmuOpcode = 0x0012
|
||||||
|
OP_ExpectClientAsCharacterRequest EmuOpcode = 0x0013
|
||||||
|
OP_ExpectClientAsCharacterReplyMs EmuOpcode = 0x0014
|
||||||
|
OP_ZoneInfoMsg EmuOpcode = 0x0015
|
||||||
|
|
||||||
|
// Character creation and loading
|
||||||
|
OP_CreateCharacterRequestMsg EmuOpcode = 0x0020
|
||||||
|
OP_CreateCharacterReplyMsg EmuOpcode = 0x0021
|
||||||
|
OP_CharacterCreateRequestMsg EmuOpcode = 0x0022
|
||||||
|
OP_CharacterCreateReplyMsg EmuOpcode = 0x0023
|
||||||
|
OP_DoneLoadingZoneResourcesMsg EmuOpcode = 0x0024
|
||||||
|
OP_DoneSendingInitialEntitiesMsg EmuOpcode = 0x0025
|
||||||
|
OP_DoneLoadingEntityResourcesMsg EmuOpcode = 0x0026
|
||||||
|
OP_DoneLoadingUIResourcesMsg EmuOpcode = 0x0027
|
||||||
|
|
||||||
|
// World and time
|
||||||
|
OP_PredictionUpdateMsg EmuOpcode = 0x0030
|
||||||
|
OP_RemoteCmdMsg EmuOpcode = 0x0031
|
||||||
|
OP_SetRemoteCmdsMsg EmuOpcode = 0x0032
|
||||||
|
OP_GameWorldTimeMsg EmuOpcode = 0x0033
|
||||||
|
OP_MOTDMsg EmuOpcode = 0x0034
|
||||||
|
OP_ZoneMOTDMsg EmuOpcode = 0x0035
|
||||||
|
OP_SetTimeMsg EmuOpcode = 0x0036
|
||||||
|
|
||||||
|
// Guild recruitment
|
||||||
|
OP_GuildRecruitingMemberInfo EmuOpcode = 0x0040
|
||||||
|
OP_GuildRecruiting EmuOpcode = 0x0041
|
||||||
|
OP_GuildRecruitingDetails EmuOpcode = 0x0042
|
||||||
|
OP_GuildRecruitingImage EmuOpcode = 0x0043
|
||||||
|
|
||||||
|
// Avatar and camping
|
||||||
|
OP_AvatarCreatedMsg EmuOpcode = 0x0050
|
||||||
|
OP_AvatarDestroyedMsg EmuOpcode = 0x0051
|
||||||
|
OP_RequestCampMsg EmuOpcode = 0x0052
|
||||||
|
OP_MapRequest EmuOpcode = 0x0053
|
||||||
|
OP_CampStartedMsg EmuOpcode = 0x0054
|
||||||
|
OP_CampAbortedMsg EmuOpcode = 0x0055
|
||||||
|
|
||||||
|
// Who and monitor
|
||||||
|
OP_WhoQueryRequestMsg EmuOpcode = 0x0060
|
||||||
|
OP_WhoQueryReplyMsg EmuOpcode = 0x0061
|
||||||
|
OP_MonitorReplyMsg EmuOpcode = 0x0062
|
||||||
|
OP_MonitorCharacterListMsg EmuOpcode = 0x0063
|
||||||
|
OP_MonitorCharacterListRequestMsg EmuOpcode = 0x0064
|
||||||
|
|
||||||
|
// Client commands
|
||||||
|
OP_ClientCmdMsg EmuOpcode = 0x0070
|
||||||
|
OP_Lottery EmuOpcode = 0x0071
|
||||||
|
OP_DispatchClientCmdMsg EmuOpcode = 0x0072
|
||||||
|
OP_DispatchESMsg EmuOpcode = 0x0073
|
||||||
|
|
||||||
|
// Target and opportunity
|
||||||
|
OP_UpdateTargetMsg EmuOpcode = 0x0080
|
||||||
|
OP_UpdateOpportunityMsg EmuOpcode = 0x0081
|
||||||
|
OP_UpdateTargetLocMsg EmuOpcode = 0x0082
|
||||||
|
OP_RequestTargetLocMsg EmuOpcode = 0x0083
|
||||||
|
|
||||||
|
// Character updates
|
||||||
|
OP_UpdateCharacterSheetMsg EmuOpcode = 0x0090
|
||||||
|
OP_UpdateSpellBookMsg EmuOpcode = 0x0091
|
||||||
|
OP_UpdateInventoryMsg EmuOpcode = 0x0092
|
||||||
|
OP_UpdateRecipeBookMsg EmuOpcode = 0x0093
|
||||||
|
OP_RequestRecipeDetailsMsg EmuOpcode = 0x0094
|
||||||
|
OP_RecipeDetailsMsg EmuOpcode = 0x0095
|
||||||
|
OP_UpdateSkillBookMsg EmuOpcode = 0x0096
|
||||||
|
OP_UpdateSkillsMsg EmuOpcode = 0x0097
|
||||||
|
|
||||||
|
// Zone changes and teleports
|
||||||
|
OP_ChangeZoneMsg EmuOpcode = 0x00a0
|
||||||
|
OP_ClientTeleportRequestMsg EmuOpcode = 0x00a1
|
||||||
|
OP_TeleportWithinZoneMsg EmuOpcode = 0x00a2
|
||||||
|
OP_TeleportWithinZoneNoReloadMsg EmuOpcode = 0x00a3
|
||||||
|
OP_MigrateClientToZoneRequestMsg EmuOpcode = 0x00a4
|
||||||
|
OP_MigrateClientToZoneReplyMsg EmuOpcode = 0x00a5
|
||||||
|
OP_ReadyToZoneMsg EmuOpcode = 0x00a6
|
||||||
|
OP_ZoneChangeMsg EmuOpcode = 0x00a7
|
||||||
|
OP_ZoneUnavailMsg EmuOpcode = 0x00a8
|
||||||
|
|
||||||
|
// Login and world interaction
|
||||||
|
OP_EnterWorldMsg EmuOpcode = 0x00f1
|
||||||
|
OP_LoginAcceptedMsg EmuOpcode = 0x00f3
|
||||||
|
OP_LoginFailedMsg2 EmuOpcode = 0x00f4
|
||||||
|
OP_ExitWorldMsg EmuOpcode = 0x00f5
|
||||||
|
OP_ClientIdMsg EmuOpcode = 0x00f8
|
||||||
|
|
||||||
|
// NPC interaction
|
||||||
|
OP_QueryHoodMsg EmuOpcode = 0x00f9
|
||||||
|
OP_QueryNpcMsg EmuOpcode = 0x00fa
|
||||||
|
OP_AttackMsg EmuOpcode = 0x00fb
|
||||||
|
OP_DialogOpenMsg EmuOpcode = 0x00fc
|
||||||
|
OP_DialogSelectMsg EmuOpcode = 0x00fd
|
||||||
|
OP_ConversationMsg EmuOpcode = 0x00fe
|
||||||
|
OP_CloseWindowMsg EmuOpcode = 0x00ff
|
||||||
|
|
||||||
|
// Group management - detailed
|
||||||
|
OP_RemoveClientFromGroupMsg EmuOpcode = 0x0200
|
||||||
|
OP_RemoveGroupFromGroupMsg EmuOpcode = 0x0201
|
||||||
|
OP_MakeGroupLeaderMsg EmuOpcode = 0x0202
|
||||||
|
OP_GroupCreatedMsg EmuOpcode = 0x0203
|
||||||
|
OP_GroupDestroyedMsg EmuOpcode = 0x0204
|
||||||
|
OP_GroupMemberAddedMsg EmuOpcode = 0x0205
|
||||||
|
OP_GroupMemberRemovedMsg EmuOpcode = 0x0206
|
||||||
|
OP_GroupRemovedFromGroupMsg EmuOpcode = 0x0207
|
||||||
|
OP_GroupLeaderChangedMsg EmuOpcode = 0x0208
|
||||||
|
OP_GroupSettingsChangedMsg EmuOpcode = 0x0209
|
||||||
|
OP_GroupOptionsMsg EmuOpcode = 0x020a
|
||||||
|
OP_GroupInviteRequestMsg EmuOpcode = 0x020b
|
||||||
|
OP_GroupInviteResponseMsg EmuOpcode = 0x020c
|
||||||
|
OP_GroupDeclineResponseMsg EmuOpcode = 0x020d
|
||||||
|
OP_DefaultGroupOptionsRequestMsg EmuOpcode = 0x020e
|
||||||
|
OP_DefaultGroupOptionsMsg EmuOpcode = 0x020f
|
||||||
|
OP_DisplayGroupOptionsScreenMsg EmuOpcode = 0x0210
|
||||||
|
OP_CloseGroupInviteWindowMsg EmuOpcode = 0x0211
|
||||||
|
OP_UpdateGroupMemberDataMsg EmuOpcode = 0x0212
|
||||||
|
|
||||||
|
// ES (Emulator Server) status
|
||||||
|
OP_SendLatestRequestMsg EmuOpcode = 0x0220
|
||||||
|
OP_ClearDataMsg EmuOpcode = 0x0221
|
||||||
|
OP_SetSocialMsg EmuOpcode = 0x0222
|
||||||
|
OP_ESStatusMsg EmuOpcode = 0x0223
|
||||||
|
OP_ESZoneInstanceStatusMsg EmuOpcode = 0x0224
|
||||||
|
OP_ZonesStatusRequestMsg EmuOpcode = 0x0225
|
||||||
|
OP_ZonesStatusMsg EmuOpcode = 0x0226
|
||||||
|
OP_ESWeatherRequestMsg EmuOpcode = 0x0227
|
||||||
|
OP_ESWeatherRequestEndMsg EmuOpcode = 0x0228
|
||||||
|
|
||||||
|
// Chat system
|
||||||
|
OP_ChatMsg EmuOpcode = 0x0300
|
||||||
|
OP_ChatFiltersMsg EmuOpcode = 0x0301
|
||||||
|
OP_TellMsg EmuOpcode = 0x0302
|
||||||
|
OP_ChatRelationshipUpdateMsg EmuOpcode = 0x0303
|
||||||
|
OP_ChatCreateChannelMsg EmuOpcode = 0x0304
|
||||||
|
OP_ChatJoinChannelMsg EmuOpcode = 0x0305
|
||||||
|
OP_ChatWhoChannelMsg EmuOpcode = 0x0306
|
||||||
|
OP_ChatLeaveChannelMsg EmuOpcode = 0x0307
|
||||||
|
OP_ChatTellChannelMsg EmuOpcode = 0x0308
|
||||||
|
OP_ChatTellUserMsg EmuOpcode = 0x0309
|
||||||
|
OP_ChatToggleFriendMsg EmuOpcode = 0x030a
|
||||||
|
OP_ChatToggleIgnoreMsg EmuOpcode = 0x030b
|
||||||
|
OP_ChatSendFriendsMsg EmuOpcode = 0x030c
|
||||||
|
OP_ChatSendIgnoresMsg EmuOpcode = 0x030d
|
||||||
|
|
||||||
|
// Trade system
|
||||||
|
OP_TradeRequestMsg EmuOpcode = 0x0400
|
||||||
|
OP_TradeResponseMsg EmuOpcode = 0x0401
|
||||||
|
OP_TradeStartMsg EmuOpcode = 0x0402
|
||||||
|
OP_TradeEndMsg EmuOpcode = 0x0403
|
||||||
|
OP_TradeAddItemMsg EmuOpcode = 0x0404
|
||||||
|
OP_TradeRemoveItemMsg EmuOpcode = 0x0405
|
||||||
|
OP_TradeAcceptMsg EmuOpcode = 0x0406
|
||||||
|
|
||||||
|
// Inventory and items
|
||||||
|
OP_InventoryMsg EmuOpcode = 0x0500
|
||||||
|
OP_EquipItemMsg EmuOpcode = 0x0501
|
||||||
|
OP_UnequipItemMsg EmuOpcode = 0x0502
|
||||||
|
OP_DeleteItemMsg EmuOpcode = 0x0503
|
||||||
|
OP_UseItemMsg EmuOpcode = 0x0504
|
||||||
|
OP_ExamineItemRequestMsg EmuOpcode = 0x0505
|
||||||
|
OP_ExamineItemMsg EmuOpcode = 0x0506
|
||||||
|
OP_ExamineInfoRequestMsg EmuOpcode = 0x0507
|
||||||
|
OP_LootItemsRequestMsg EmuOpcode = 0x0508
|
||||||
|
OP_StoppedLootingMsg EmuOpcode = 0x0509
|
||||||
|
|
||||||
|
// Combat and skills
|
||||||
|
OP_ConsiderMsg EmuOpcode = 0x0600
|
||||||
|
OP_TargetMsg EmuOpcode = 0x0601
|
||||||
|
OP_AutoAttackMsg EmuOpcode = 0x0602
|
||||||
|
OP_CastSpellMsg EmuOpcode = 0x0603
|
||||||
|
OP_InterruptSpellMsg EmuOpcode = 0x0604
|
||||||
|
OP_SkillInfoRequestMsg EmuOpcode = 0x0605
|
||||||
|
OP_SkillInfoResponseMsg EmuOpcode = 0x0606
|
||||||
|
OP_SkillInfoRequest EmuOpcode = 0x0607
|
||||||
|
OP_SkillInfoResponse EmuOpcode = 0x0608
|
||||||
|
OP_RemoveSpellEffectMsg EmuOpcode = 0x0609
|
||||||
|
OP_RemoveConcentrationMsg EmuOpcode = 0x060a
|
||||||
|
OP_CancelSpellCast EmuOpcode = 0x060b
|
||||||
|
OP_AttackNotAllowed EmuOpcode = 0x060c
|
||||||
|
OP_AttackAllowed EmuOpcode = 0x060d
|
||||||
|
OP_PopulateSkillMapsMsg EmuOpcode = 0x060e
|
||||||
|
OP_CancelledFeignMsg EmuOpcode = 0x060f
|
||||||
|
OP_SignalMsg EmuOpcode = 0x0610
|
||||||
|
OP_DispatchSpellCmdMsg EmuOpcode = 0x0611
|
||||||
|
|
||||||
|
// Player status
|
||||||
|
OP_PlayerStatsMsg EmuOpcode = 0x0700
|
||||||
|
OP_PlayerBioMsg EmuOpcode = 0x0701
|
||||||
|
OP_PlayerProfileMsg EmuOpcode = 0x0702
|
||||||
|
OP_LevelUpMsg EmuOpcode = 0x0703
|
||||||
|
OP_ExpUpdateMsg EmuOpcode = 0x0704
|
||||||
|
OP_SkillUpMsg EmuOpcode = 0x0705
|
||||||
|
OP_LevelChangedMsg EmuOpcode = 0x0706
|
||||||
|
OP_SpellGainedMsg EmuOpcode = 0x0707
|
||||||
|
OP_UpdatePositionMsg EmuOpcode = 0x0708
|
||||||
|
OP_SitMsg EmuOpcode = 0x0709
|
||||||
|
OP_StandMsg EmuOpcode = 0x070a
|
||||||
|
OP_SatMsg EmuOpcode = 0x070b
|
||||||
|
OP_StoodMsg EmuOpcode = 0x070c
|
||||||
|
OP_AvatarUpdateMsg EmuOpcode = 0x070d
|
||||||
|
OP_BioUpdateMsg EmuOpcode = 0x070e
|
||||||
|
OP_InspectPlayerMsg EmuOpcode = 0x070f
|
||||||
|
OP_AFKUpdateMsg EmuOpcode = 0x0710
|
||||||
|
OP_AnonUpdateMsg EmuOpcode = 0x0711
|
||||||
|
OP_LFGUpdateMsg EmuOpcode = 0x0712
|
||||||
|
|
||||||
|
// Zone and world
|
||||||
|
OP_ZoneListMsg EmuOpcode = 0x0800
|
||||||
|
OP_ZoneEntryMsg EmuOpcode = 0x0801
|
||||||
|
OP_ZoneExitMsg EmuOpcode = 0x0802
|
||||||
|
OP_NewZoneMsg EmuOpcode = 0x0803
|
||||||
|
OP_SendZonePointsMsg EmuOpcode = 0x0804
|
||||||
|
OP_ZonePointsMsg EmuOpcode = 0x0805
|
||||||
|
OP_WorldPingMsg EmuOpcode = 0x0806
|
||||||
|
OP_WorldShutdownUpdateMsg EmuOpcode = 0x0807
|
||||||
|
OP_RestartZoneMsg EmuOpcode = 0x0808
|
||||||
|
OP_UpdateActivePublicZonesMsg EmuOpcode = 0x0809
|
||||||
|
OP_WorldDataUpdateMsg EmuOpcode = 0x080a
|
||||||
|
OP_WorldDataChangeMsg EmuOpcode = 0x080b
|
||||||
|
OP_ClientTeleportToLocationMsg EmuOpcode = 0x080c
|
||||||
|
OP_UpdateMotdMsg EmuOpcode = 0x080d
|
||||||
|
|
||||||
|
// Housing system
|
||||||
|
OP_HousingDataMsg EmuOpcode = 0x0900
|
||||||
|
OP_HouseItemsList EmuOpcode = 0x0901
|
||||||
|
OP_HousePurchase EmuOpcode = 0x0902
|
||||||
|
OP_HousePayUpkeep EmuOpcode = 0x0903
|
||||||
|
OP_PayHouseUpkeepMsg EmuOpcode = 0x0904
|
||||||
|
OP_HouseDeletedRemotelyMsg EmuOpcode = 0x0905
|
||||||
|
OP_UpdateHouseDataMsg EmuOpcode = 0x0906
|
||||||
|
OP_UpdateHouseAccessDataMsg EmuOpcode = 0x0907
|
||||||
|
OP_PlayerHouseBaseScreenMsg EmuOpcode = 0x0908
|
||||||
|
OP_PlayerHousePurchaseScreenMsg EmuOpcode = 0x0909
|
||||||
|
OP_PlayerHouseAccessUpdateMsg EmuOpcode = 0x090a
|
||||||
|
OP_PlayerHouseDisplayStatusMsg EmuOpcode = 0x090b
|
||||||
|
OP_PlayerHouseCloseUIMsg EmuOpcode = 0x090c
|
||||||
|
OP_BuyPlayerHouseMsg EmuOpcode = 0x090d
|
||||||
|
OP_BuyPlayerHouseTintMsg EmuOpcode = 0x090e
|
||||||
|
OP_CollectAllHouseItemsMsg EmuOpcode = 0x090f
|
||||||
|
OP_RelinquishHouseMsg EmuOpcode = 0x0910
|
||||||
|
OP_EnterHouseMsg EmuOpcode = 0x0911
|
||||||
|
OP_ExitHouseMsg EmuOpcode = 0x0912
|
||||||
|
OP_HouseDefaultAccessSetMsg EmuOpcode = 0x0913
|
||||||
|
OP_HouseAccessSetMsg EmuOpcode = 0x0914
|
||||||
|
OP_HouseAccessRemoveMsg EmuOpcode = 0x0915
|
||||||
|
OP_HousingDataChangedMsg EmuOpcode = 0x0916
|
||||||
|
OP_HousingRestoreMsg EmuOpcode = 0x0917
|
||||||
|
OP_HouseCustomizationScreenMsg EmuOpcode = 0x0918
|
||||||
|
OP_CustomizationPurchaseRequestMs EmuOpcode = 0x0919
|
||||||
|
OP_CustomizationSetRequestMsg EmuOpcode = 0x091a
|
||||||
|
OP_CustomizationReplyMsg EmuOpcode = 0x091b
|
||||||
|
OP_TintWidgetsMsg EmuOpcode = 0x091c
|
||||||
|
OP_MoveableObjectPlacementCriteri EmuOpcode = 0x091d
|
||||||
|
OP_EnterMoveObjectModeMsg EmuOpcode = 0x091e
|
||||||
|
OP_PositionMoveableObject EmuOpcode = 0x091f
|
||||||
|
OP_CancelMoveObjectModeMsg EmuOpcode = 0x0920
|
||||||
|
OP_ShaderCustomizationMsg EmuOpcode = 0x0921
|
||||||
|
OP_ReplaceableSubMeshesMsg EmuOpcode = 0x0922
|
||||||
|
OP_CharacterHousingList EmuOpcode = 0x0923
|
||||||
|
OP_CharacterCreatedDungeons EmuOpcode = 0x0924
|
||||||
|
|
||||||
|
// Achievement system
|
||||||
|
OP_AchievementUpdateMsg EmuOpcode = 0x0a00
|
||||||
|
OP_AchievementCompleteMsg EmuOpcode = 0x0a01
|
||||||
|
OP_CharacterAchievements EmuOpcode = 0x0a02
|
||||||
|
|
||||||
|
// Keybinds, macros and UI
|
||||||
|
OP_KeybindUpdateMsg EmuOpcode = 0x0b00
|
||||||
|
OP_KeybindLoadMsg EmuOpcode = 0x0b01
|
||||||
|
OP_MacroUpdateMsg EmuOpcode = 0x0b02
|
||||||
|
OP_UISettingsMsg EmuOpcode = 0x0b03
|
||||||
|
OP_UISettingsResponseMsg EmuOpcode = 0x0b04
|
||||||
|
OP_UIResetMsg EmuOpcode = 0x0b05
|
||||||
|
OP_KeymapLoadMsg EmuOpcode = 0x0b06
|
||||||
|
OP_KeymapNoneMsg EmuOpcode = 0x0b07
|
||||||
|
OP_KeymapDataMsg EmuOpcode = 0x0b08
|
||||||
|
OP_KeymapSaveMsg EmuOpcode = 0x0b09
|
||||||
|
OP_QuickbarInitMsg EmuOpcode = 0x0b0a
|
||||||
|
OP_QuickbarUpdateMsg EmuOpcode = 0x0b0b
|
||||||
|
OP_MacroInitMsg EmuOpcode = 0x0b0c
|
||||||
|
OP_QuestionnaireMsg EmuOpcode = 0x0b0d
|
||||||
|
OP_DisplayInnVisitScreenMsg EmuOpcode = 0x0b0e
|
||||||
|
OP_DisplayWarningMsg EmuOpcode = 0x0b0f
|
||||||
|
OP_OnscreenMsgMsg EmuOpcode = 0x0b10
|
||||||
|
OP_DisplayMailScreenMsg EmuOpcode = 0x0b11
|
||||||
|
OP_UIEvent EmuOpcode = 0x0b12
|
||||||
|
OP_LoadWelcomeWindow EmuOpcode = 0x0b13
|
||||||
|
OP_LoadCalendarEvents EmuOpcode = 0x0b14
|
||||||
|
|
||||||
|
// Mail system
|
||||||
|
OP_MailGetHeadersRequestMsg EmuOpcode = 0x0c00
|
||||||
|
OP_MailGetHeadersReplyMsg EmuOpcode = 0x0c01
|
||||||
|
OP_MailGetMessageRequestMsg EmuOpcode = 0x0c02
|
||||||
|
OP_MailGetMessageReplyMsg EmuOpcode = 0x0c03
|
||||||
|
OP_MailSendMessageRequestMsg EmuOpcode = 0x0c04
|
||||||
|
OP_MailSendMessageReplyMsg EmuOpcode = 0x0c05
|
||||||
|
OP_MailDeleteMessageRequestMsg EmuOpcode = 0x0c06
|
||||||
|
OP_MailGetMessageMsg EmuOpcode = 0x0c07
|
||||||
|
OP_MailSendMessageMsg EmuOpcode = 0x0c08
|
||||||
|
OP_MailDeleteMessageMsg EmuOpcode = 0x0c09
|
||||||
|
OP_MailCommitSendMessageMsg EmuOpcode = 0x0c0a
|
||||||
|
OP_MailSendSystemMessageMsg EmuOpcode = 0x0c0b
|
||||||
|
OP_MailRemoveAttachFromMailMsg EmuOpcode = 0x0c0c
|
||||||
|
OP_MailEventNotificationMsg EmuOpcode = 0x0c0d
|
||||||
|
OP_CorruptedClientMsg EmuOpcode = 0x0c0e
|
||||||
|
OP_NotifyApprenticeStoppedMentori EmuOpcode = 0x0c0f
|
||||||
|
|
||||||
|
// Quest system
|
||||||
|
OP_QuestJournalUpdateMsg EmuOpcode = 0x0d00
|
||||||
|
OP_QuestJournalReplyMsg EmuOpcode = 0x0d01
|
||||||
|
OP_QuestOfferMsg EmuOpcode = 0x0d02
|
||||||
|
OP_QuestRewardMsg EmuOpcode = 0x0d03
|
||||||
|
OP_QuestCompleteMsg EmuOpcode = 0x0d04
|
||||||
|
OP_QuestFailedMsg EmuOpcode = 0x0d05
|
||||||
|
OP_OfferQuestMsg EmuOpcode = 0x0d06
|
||||||
|
OP_QuestJournalOpenMsg EmuOpcode = 0x0d07
|
||||||
|
OP_QuestJournalInspectMsg EmuOpcode = 0x0d08
|
||||||
|
OP_QuestJournalSetVisibleMsg EmuOpcode = 0x0d09
|
||||||
|
OP_QuestJournalWaypointMsg EmuOpcode = 0x0d0a
|
||||||
|
OP_QuestReward EmuOpcode = 0x0d0b
|
||||||
|
OP_JournalQuestStoryline EmuOpcode = 0x0d0c
|
||||||
|
OP_DailyObjectives EmuOpcode = 0x0d0d
|
||||||
|
|
||||||
|
// Guild operations extended
|
||||||
|
OP_GuildUpdateMsg EmuOpcode = 0x0e00
|
||||||
|
OP_CreateGuildRequestMsg EmuOpcode = 0x0e01
|
||||||
|
OP_CreateGuildReplyMsg EmuOpcode = 0x0e02
|
||||||
|
OP_GuildInviteMsg EmuOpcode = 0x0e03
|
||||||
|
OP_GuildInviteResponseMsg EmuOpcode = 0x0e04
|
||||||
|
OP_GuildKickMsg EmuOpcode = 0x0e05
|
||||||
|
OP_GuildMotdMsg EmuOpcode = 0x0e06
|
||||||
|
OP_GuildsayMsg EmuOpcode = 0x0e07
|
||||||
|
OP_FellowshipExpMsg EmuOpcode = 0x0e08
|
||||||
|
OP_ModifyGuildMsg EmuOpcode = 0x0e09
|
||||||
|
OP_GuildEventMsg EmuOpcode = 0x0e0a
|
||||||
|
OP_GuildEventAddMsg EmuOpcode = 0x0e0b
|
||||||
|
OP_GuildEventActionMsg EmuOpcode = 0x0e0c
|
||||||
|
OP_GuildEventListMsg EmuOpcode = 0x0e0d
|
||||||
|
OP_RequestGuildEventDetailsMsg EmuOpcode = 0x0e0e
|
||||||
|
OP_GuildEventDetailsMsg EmuOpcode = 0x0e0f
|
||||||
|
OP_RequestGuildBankEventDetailsMs EmuOpcode = 0x0e10
|
||||||
|
OP_GuildBankUpdateMsg EmuOpcode = 0x0e11
|
||||||
|
OP_GuildBankEventListMsg EmuOpcode = 0x0e12
|
||||||
|
OP_RenameGuildMsg EmuOpcode = 0x0e13
|
||||||
|
OP_DeleteGuildMsg EmuOpcode = 0x0e14
|
||||||
|
OP_RequestGuildMembershipMsg EmuOpcode = 0x0e15
|
||||||
|
OP_GuildMembershipResponseMsg EmuOpcode = 0x0e16
|
||||||
|
OP_LeaveGuildNotifyMsg EmuOpcode = 0x0e17
|
||||||
|
OP_JoinGuildNotifyMsg EmuOpcode = 0x0e18
|
||||||
|
OP_RequestGuildInfoMsg EmuOpcode = 0x0e19
|
||||||
|
|
||||||
|
// Consignment and broker
|
||||||
|
OP_ConsignmentCloseStoreMsg EmuOpcode = 0x0f00
|
||||||
|
OP_ConsignItemRequestMsg EmuOpcode = 0x0f01
|
||||||
|
OP_ConsignItemResponseMsg EmuOpcode = 0x0f02
|
||||||
|
OP_PurchaseConsignmentLoreCheckRe EmuOpcode = 0x0f03
|
||||||
|
OP_ExamineConsignmentRequestMsg EmuOpcode = 0x0f04
|
||||||
|
OP_ExamineConsignmentResponseMsg EmuOpcode = 0x0f05
|
||||||
|
OP_ConsignViewCreateMsg EmuOpcode = 0x0f06
|
||||||
|
OP_ConsignViewGetPageMsg EmuOpcode = 0x0f07
|
||||||
|
OP_ConsignViewReleaseMsg EmuOpcode = 0x0f08
|
||||||
|
OP_ConsignRemoveItemsMsg EmuOpcode = 0x0f09
|
||||||
|
OP_ConsignViewSortMsg EmuOpcode = 0x0f0a
|
||||||
|
OP_BrokerAddBag EmuOpcode = 0x0f0b
|
||||||
|
|
||||||
|
// Character transfer
|
||||||
|
OP_CharTransferStartRequestMsg EmuOpcode = 0x1000
|
||||||
|
OP_CharTransferStartReplyMsg EmuOpcode = 0x1001
|
||||||
|
OP_CharTransferRequestMsg EmuOpcode = 0x1002
|
||||||
|
OP_CharTransferReplyMsg EmuOpcode = 0x1003
|
||||||
|
OP_CharTransferRollbackRequestMsg EmuOpcode = 0x1004
|
||||||
|
OP_CharTransferCommitRequestMsg EmuOpcode = 0x1005
|
||||||
|
OP_CharTransferRollbackReplyMsg EmuOpcode = 0x1006
|
||||||
|
OP_CharTransferCommitReplyMsg EmuOpcode = 0x1007
|
||||||
|
OP_GetCharacterSerializedRequestM EmuOpcode = 0x1008
|
||||||
|
OP_GetCharacterSerializedReplyMsg EmuOpcode = 0x1009
|
||||||
|
OP_CreateCharFromCBBRequestMsg EmuOpcode = 0x100a
|
||||||
|
OP_CreateCharFromCBBReplyMsg EmuOpcode = 0x100b
|
||||||
|
OP_CharTransferValidateRequestMsg EmuOpcode = 0x100c
|
||||||
|
OP_CharTransferValidateReplyMsg EmuOpcode = 0x100d
|
||||||
|
OP_CharacterLinkdeadMsg EmuOpcode = 0x100e
|
||||||
|
|
||||||
|
// Auction system
|
||||||
|
OP_AuctionItem EmuOpcode = 0x1100
|
||||||
|
OP_AuctionItemReply EmuOpcode = 0x1101
|
||||||
|
OP_AuctionCoin EmuOpcode = 0x1102
|
||||||
|
OP_AuctionCoinReply EmuOpcode = 0x1103
|
||||||
|
OP_AuctionCharacter EmuOpcode = 0x1104
|
||||||
|
OP_AuctionCharacterReply EmuOpcode = 0x1105
|
||||||
|
OP_AuctionCommitMsg EmuOpcode = 0x1106
|
||||||
|
OP_AuctionAbortMsg EmuOpcode = 0x1107
|
||||||
|
|
||||||
|
// EQ command system (client commands)
|
||||||
|
OP_EqHearChatCmd EmuOpcode = 0x1200
|
||||||
|
OP_EqDisplayTextCmd EmuOpcode = 0x1201
|
||||||
|
OP_EqCreateGhostCmd EmuOpcode = 0x1202
|
||||||
|
OP_EqCreateWidgetCmd EmuOpcode = 0x1203
|
||||||
|
OP_EqCreateSignWidgetCmd EmuOpcode = 0x1204
|
||||||
|
OP_EqDestroyGhostCmd EmuOpcode = 0x1205
|
||||||
|
OP_EqUpdateGhostCmd EmuOpcode = 0x1206
|
||||||
|
OP_EqSetControlGhostCmd EmuOpcode = 0x1207
|
||||||
|
OP_EqSetPOVGhostCmd EmuOpcode = 0x1208
|
||||||
|
OP_EqHearCombatCmd EmuOpcode = 0x1209
|
||||||
|
OP_EqHearSpellCastCmd EmuOpcode = 0x120a
|
||||||
|
OP_EqHearSpellInterruptCmd EmuOpcode = 0x120b
|
||||||
|
OP_EqHearSpellFizzleCmd EmuOpcode = 0x120c
|
||||||
|
OP_EqHearConsiderCmd EmuOpcode = 0x120d
|
||||||
|
OP_EqUpdateSubClassesCmd EmuOpcode = 0x120e
|
||||||
|
OP_EqCreateListBoxCmd EmuOpcode = 0x120f
|
||||||
|
OP_EqSetDebugPathPointsCmd EmuOpcode = 0x1210
|
||||||
|
OP_EqCannedEmoteCmd EmuOpcode = 0x1211
|
||||||
|
OP_EqStateCmd EmuOpcode = 0x1212
|
||||||
|
OP_EqPlaySoundCmd EmuOpcode = 0x1213
|
||||||
|
OP_EqPlaySound3DCmd EmuOpcode = 0x1214
|
||||||
|
OP_EqPlayVoiceCmd EmuOpcode = 0x1215
|
||||||
|
OP_EqHearDrowningCmd EmuOpcode = 0x1216
|
||||||
|
OP_EqHearDeathCmd EmuOpcode = 0x1217
|
||||||
|
OP_EqGroupMemberRemovedCmd EmuOpcode = 0x1218
|
||||||
|
OP_EqHearChainEffectCmd EmuOpcode = 0x1219
|
||||||
|
OP_EqReceiveOfferCmd EmuOpcode = 0x121a
|
||||||
|
OP_EqInspectPCResultsCmd EmuOpcode = 0x121b
|
||||||
|
OP_EqDrawablePathGraphCmd EmuOpcode = 0x121c
|
||||||
|
OP_EqDialogOpenCmd EmuOpcode = 0x121d
|
||||||
|
OP_EqDialogCloseCmd EmuOpcode = 0x121e
|
||||||
|
OP_EqCollectionUpdateCmd EmuOpcode = 0x121f
|
||||||
|
OP_EqCollectionFilterCmd EmuOpcode = 0x1220
|
||||||
|
OP_EqCollectionItemCmd EmuOpcode = 0x1221
|
||||||
|
OP_EqQuestJournalUpdateCmd EmuOpcode = 0x1222
|
||||||
|
OP_EqQuestJournalReplyCmd EmuOpcode = 0x1223
|
||||||
|
OP_EqQuestGroupCmd EmuOpcode = 0x1224
|
||||||
|
OP_EqUpdateMerchantCmd EmuOpcode = 0x1225
|
||||||
|
OP_EqUpdateStoreCmd EmuOpcode = 0x1226
|
||||||
|
OP_EqUpdatePlayerTradeCmd EmuOpcode = 0x1227
|
||||||
|
OP_EqHelpPathCmd EmuOpcode = 0x1228
|
||||||
|
OP_EqHelpPathClearCmd EmuOpcode = 0x1229
|
||||||
|
OP_EqUpdateBankCmd EmuOpcode = 0x122a
|
||||||
|
OP_EqExamineInfoCmd EmuOpcode = 0x122b
|
||||||
|
OP_EqCloseWindowCmd EmuOpcode = 0x122c
|
||||||
|
OP_EqUpdateLootCmd EmuOpcode = 0x122d
|
||||||
|
OP_EqJunctionListCmd EmuOpcode = 0x122e
|
||||||
|
OP_EqShowDeathWindowCmd EmuOpcode = 0x122f
|
||||||
|
OP_EqDisplaySpellFailCmd EmuOpcode = 0x1230
|
||||||
|
OP_EqSpellCastStartCmd EmuOpcode = 0x1231
|
||||||
|
OP_EqSpellCastEndCmd EmuOpcode = 0x1232
|
||||||
|
OP_EqResurrectedCmd EmuOpcode = 0x1233
|
||||||
|
OP_EqChoiceWinCmd EmuOpcode = 0x1234
|
||||||
|
OP_EqSetDefaultVerbCmd EmuOpcode = 0x1235
|
||||||
|
OP_EqInstructionWindowCmd EmuOpcode = 0x1236
|
||||||
|
OP_EqInstructionWindowCloseCmd EmuOpcode = 0x1237
|
||||||
|
OP_EqInstructionWindowGoalCmd EmuOpcode = 0x1238
|
||||||
|
OP_EqInstructionWindowTaskCmd EmuOpcode = 0x1239
|
||||||
|
OP_EqEnableGameEventCmd EmuOpcode = 0x123a
|
||||||
|
OP_EqShowWindowCmd EmuOpcode = 0x123b
|
||||||
|
OP_EqEnableWindowCmd EmuOpcode = 0x123c
|
||||||
|
OP_EqFlashWindowCmd EmuOpcode = 0x123d
|
||||||
|
OP_EqHearPlayFlavorCmd EmuOpcode = 0x123e
|
||||||
|
OP_EqUpdateSignWidgetCmd EmuOpcode = 0x123f
|
||||||
|
OP_EqDebugPVDCmd EmuOpcode = 0x1240
|
||||||
|
OP_EqShowBookCmd EmuOpcode = 0x1241
|
||||||
|
OP_EqQuestionnaireCmd EmuOpcode = 0x1242
|
||||||
|
OP_EqGetProbsCmd EmuOpcode = 0x1243
|
||||||
|
OP_EqHearHealCmd EmuOpcode = 0x1244
|
||||||
|
OP_EqChatChannelUpdateCmd EmuOpcode = 0x1245
|
||||||
|
OP_EqWhoChannelQueryReplyCmd EmuOpcode = 0x1246
|
||||||
|
OP_EqAvailWorldChannelsCmd EmuOpcode = 0x1247
|
||||||
|
OP_EqUpdateTargetCmd EmuOpcode = 0x1248
|
||||||
|
OP_EqConsignmentItemsCmd EmuOpcode = 0x1249
|
||||||
|
OP_EqStartBrokerCmd EmuOpcode = 0x124a
|
||||||
|
OP_EqMapExplorationCmd EmuOpcode = 0x124b
|
||||||
|
OP_EqStoreLogCmd EmuOpcode = 0x124c
|
||||||
|
OP_EqSpellMoveToRangeAndRetryCmd EmuOpcode = 0x124d
|
||||||
|
OP_EqUpdatePlayerMailCmd EmuOpcode = 0x124e
|
||||||
|
OP_EqFactionUpdateCmd EmuOpcode = 0x124f
|
||||||
|
OP_EQHearThreatCmd EmuOpcode = 0x1250
|
||||||
|
OP_EqHearSpellNoLandCmd EmuOpcode = 0x1251
|
||||||
|
OP_EQHearDispellCmd EmuOpcode = 0x1252
|
||||||
|
OP_EqTargetItemCmd EmuOpcode = 0x1253
|
||||||
|
|
||||||
|
// Various game features
|
||||||
|
OP_DialogCloseMsg EmuOpcode = 0x1300
|
||||||
|
OP_UpdateTitleCmd EmuOpcode = 0x1301
|
||||||
|
OP_BadLanguageFilter EmuOpcode = 0x1302
|
||||||
|
OP_DressingRoom EmuOpcode = 0x1303
|
||||||
|
OP_TraitsList EmuOpcode = 0x1304
|
||||||
|
OP_PointOfInterest EmuOpcode = 0x1305
|
||||||
|
OP_AdventureList EmuOpcode = 0x1306
|
||||||
|
OP_RecipeList EmuOpcode = 0x1307
|
||||||
|
OP_BagOptions EmuOpcode = 0x1308
|
||||||
|
OP_PetOptions EmuOpcode = 0x1309
|
||||||
|
OP_CharacterPet EmuOpcode = 0x130a
|
||||||
|
OP_ClearForTakeOffMsg EmuOpcode = 0x130b
|
||||||
|
OP_CharacterCurrency EmuOpcode = 0x130c
|
||||||
|
OP_TradeskillList EmuOpcode = 0x130d
|
||||||
|
OP_RecipeBook EmuOpcode = 0x130e
|
||||||
|
OP_CharacterMerc EmuOpcode = 0x130f
|
||||||
|
OP_AfterInvSpellUpdate EmuOpcode = 0x1310
|
||||||
|
OP_CharacterMounts EmuOpcode = 0x1311
|
||||||
|
OP_DungeonMakerItemRequest EmuOpcode = 0x1312
|
||||||
|
OP_SysClient EmuOpcode = 0x1313
|
||||||
|
OP_LFGGroupSearch EmuOpcode = 0x1314
|
||||||
|
OP_MarketPlacePrices EmuOpcode = 0x1315
|
||||||
|
OP_MarketFundsUpdate EmuOpcode = 0x1316
|
||||||
|
OP_MarketAddFundsRequest EmuOpcode = 0x1317
|
||||||
|
OP_ZoneBgInstanceList EmuOpcode = 0x1318
|
||||||
|
OP_Launchpad EmuOpcode = 0x1319
|
||||||
|
OP_Weakness EmuOpcode = 0x131a
|
||||||
|
OP_SavageBarInitMsg EmuOpcode = 0x131b
|
||||||
|
OP_PetOptionsResponse EmuOpcode = 0x131c
|
||||||
|
OP_CurrentPet EmuOpcode = 0x131d
|
||||||
|
OP_RecipeListUnknown EmuOpcode = 0x131e
|
||||||
|
OP_ClearForLandingMsg EmuOpcode = 0x131f
|
||||||
|
OP_LikeOption EmuOpcode = 0x1320
|
||||||
|
OP_HeritageMsg EmuOpcode = 0x1321
|
||||||
|
OP_OpenCharCust EmuOpcode = 0x1322
|
||||||
|
OP_PaperdollImage EmuOpcode = 0x1323
|
||||||
|
OP_ReadyForTakeOffMsg EmuOpcode = 0x1324
|
||||||
|
OP_EarlyLandingRequestMsg EmuOpcode = 0x1325
|
||||||
|
OP_SubmitCharCust EmuOpcode = 0x1326
|
||||||
|
OP_DietyAbilityWindow EmuOpcode = 0x1327
|
||||||
|
OP_ArenaGameTypesMsg EmuOpcode = 0x1328
|
||||||
|
OP_RaceRestrictionMsg EmuOpcode = 0x1329
|
||||||
|
OP_SetInstanceDisplayNameMsg EmuOpcode = 0x132a
|
||||||
|
|
||||||
|
// Entity and verbs
|
||||||
|
OP_EntityVerbsRequestMsg EmuOpcode = 0x1400
|
||||||
|
OP_EntityVerbsReplyMsg EmuOpcode = 0x1401
|
||||||
|
OP_EntityVerbsVerbMsg EmuOpcode = 0x1402
|
||||||
|
|
||||||
|
// Waypoints and navigation
|
||||||
|
OP_WaypointRequestMsg EmuOpcode = 0x1500
|
||||||
|
OP_WaypointReplyMsg EmuOpcode = 0x1501
|
||||||
|
OP_WaypointSelectMsg EmuOpcode = 0x1502
|
||||||
|
OP_WaypointUpdateMsg EmuOpcode = 0x1503
|
||||||
|
OP_ZoneToFriendRequestMsg EmuOpcode = 0x1504
|
||||||
|
OP_ZoneToFriendReplyMsg EmuOpcode = 0x1505
|
||||||
|
OP_FlightPathsMsg EmuOpcode = 0x1506
|
||||||
|
OP_ShowZoneTeleporterDestinations EmuOpcode = 0x1507
|
||||||
|
OP_SelectZoneTeleporterDestinatio EmuOpcode = 0x1508
|
||||||
|
|
||||||
|
// CS Tools and tickets
|
||||||
|
OP_CSTicketHeaderRequestMsg EmuOpcode = 0x1600
|
||||||
|
OP_CSTicketInfoMsg EmuOpcode = 0x1601
|
||||||
|
OP_CSTicketCommentRequestMsg EmuOpcode = 0x1602
|
||||||
|
OP_CSTicketCommentResponseMsg EmuOpcode = 0x1603
|
||||||
|
OP_CSTicketCreateMsg EmuOpcode = 0x1604
|
||||||
|
OP_CSTicketAddCommentMsg EmuOpcode = 0x1605
|
||||||
|
OP_CSTicketDeleteMsg EmuOpcode = 0x1606
|
||||||
|
OP_CSTicketChangeNotificationMsg EmuOpcode = 0x1607
|
||||||
|
OP_CSToolsRequestMsg EmuOpcode = 0x1608
|
||||||
|
OP_CSToolsResponseMsg EmuOpcode = 0x1609
|
||||||
|
OP_CSToolAccessResponseMsg EmuOpcode = 0x160a
|
||||||
|
OP_GetAvatarAccessRequestForCSToo EmuOpcode = 0x160b
|
||||||
|
OP_CsCategoryRequestMsg EmuOpcode = 0x160c
|
||||||
|
OP_CsCategoryResponseMsg EmuOpcode = 0x160d
|
||||||
|
|
||||||
|
// Knowledge base
|
||||||
|
OP_KnowledgebaseRequestMsg EmuOpcode = 0x1700
|
||||||
|
OP_KnowledgebaseResponseMsg EmuOpcode = 0x1701
|
||||||
|
OP_KnowledgeWindowSlotMappingMsg EmuOpcode = 0x1702
|
||||||
|
OP_KnownLanguagesMsg EmuOpcode = 0x1703
|
||||||
|
|
||||||
|
// Tracking
|
||||||
|
OP_TrackingUpdateMsg EmuOpcode = 0x1800
|
||||||
|
OP_BeginTrackingMsg EmuOpcode = 0x1801
|
||||||
|
OP_StopTrackingMsg EmuOpcode = 0x1802
|
||||||
|
|
||||||
|
// Advancement
|
||||||
|
OP_AdvancementRequestMsg EmuOpcode = 0x1900
|
||||||
|
|
||||||
|
// Map fog
|
||||||
|
OP_MapFogDataInitMsg EmuOpcode = 0x1a00
|
||||||
|
OP_MapFogDataUpdateMsg EmuOpcode = 0x1a01
|
||||||
|
|
||||||
|
// Crafting
|
||||||
|
OP_ShowCreateFromRecipeUIMsg EmuOpcode = 0x1b00
|
||||||
|
OP_CancelCreateFromRecipeMsg EmuOpcode = 0x1b01
|
||||||
|
OP_BeginItemCreationMsg EmuOpcode = 0x1b02
|
||||||
|
OP_StopItemCreationMsg EmuOpcode = 0x1b03
|
||||||
|
OP_ShowItemCreationProcessUIMsg EmuOpcode = 0x1b04
|
||||||
|
OP_UpdateItemCreationProcessUIMsg EmuOpcode = 0x1b05
|
||||||
|
OP_DisplayTSEventReactionMsg EmuOpcode = 0x1b06
|
||||||
|
OP_ShowRecipeBookMsg EmuOpcode = 0x1b07
|
||||||
|
|
||||||
|
// Boat transport
|
||||||
|
OP_CreateBoatTransportsMsg EmuOpcode = 0x1c00
|
||||||
|
OP_PositionBoatTransportMsg EmuOpcode = 0x1c01
|
||||||
|
OP_MigrateBoatTransportMsg EmuOpcode = 0x1c02
|
||||||
|
OP_MigrateBoatTransportReplyMsg EmuOpcode = 0x1c03
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
OP_DisplayDebugNLLPointsMsg EmuOpcode = 0x1d00
|
||||||
|
OP_UpdateDebugRadiiMsg EmuOpcode = 0x1d01
|
||||||
|
OP_DumpSchedulerMsg EmuOpcode = 0x1d02
|
||||||
|
|
||||||
|
// Client state
|
||||||
|
OP_UpdateClientPredFlagsMsg EmuOpcode = 0x1e00
|
||||||
|
OP_ChangeServerControlFlagMsg EmuOpcode = 0x1e01
|
||||||
|
OP_ClientIdleBeginMsg EmuOpcode = 0x1e02
|
||||||
|
OP_ClientIdleEndMsg EmuOpcode = 0x1e03
|
||||||
|
OP_ClientFellMsg EmuOpcode = 0x1e04
|
||||||
|
OP_ClientInDeathRegionMsg EmuOpcode = 0x1e05
|
||||||
|
OP_CampClientMsg EmuOpcode = 0x1e06
|
||||||
|
|
||||||
|
// Various
|
||||||
|
OP_RewardPackMsg EmuOpcode = 0x1f00
|
||||||
|
OP_CharNameChangedMsg EmuOpcode = 0x1f01
|
||||||
|
OP_ReloadLocalizedTxtMsg EmuOpcode = 0x1f02
|
||||||
|
OP_UnknownNpcMsg EmuOpcode = 0x1f03
|
||||||
|
OP_PromoFlagsDetailsMsg EmuOpcode = 0x1f04
|
||||||
|
OP_ReportMsg EmuOpcode = 0x1f05
|
||||||
|
OP_UpdateRaidMsg EmuOpcode = 0x1f06
|
||||||
|
OP_TitleUpdateMsg EmuOpcode = 0x1f07
|
||||||
|
OP_MoveLogUpdateMsg EmuOpcode = 0x1f08
|
||||||
|
OP_PerformPlayerKnockbackMsg EmuOpcode = 0x1f09
|
||||||
|
OP_PerformCameraShakeMsg EmuOpcode = 0x1f0a
|
||||||
|
OP_EncounterBrokenMsg EmuOpcode = 0x1f0b
|
||||||
|
OP_RequestHelpRepathMsg EmuOpcode = 0x1f0c
|
||||||
|
|
||||||
|
// Crash logs
|
||||||
|
OP_LsRequestClientCrashLogMsg EmuOpcode = 0x2000
|
||||||
|
OP_LsClientBaselogReplyMsg EmuOpcode = 0x2001
|
||||||
|
OP_LsClientCrashlogReplyMsg EmuOpcode = 0x2002
|
||||||
|
OP_LsClientAlertlogReplyMsg EmuOpcode = 0x2003
|
||||||
|
OP_LsClientVerifylogReplyMsg EmuOpcode = 0x2004
|
||||||
|
|
||||||
|
// Server lock
|
||||||
|
OP_WSServerLockMsg EmuOpcode = 0x2100
|
||||||
|
OP_WSServerHideMsg EmuOpcode = 0x2101
|
||||||
|
OP_LSServerLockMsg EmuOpcode = 0x2102
|
||||||
|
OP_WSAcctLockStatusMsg EmuOpcode = 0x2103
|
||||||
|
OP_LSCheckAcctLockMsg EmuOpcode = 0x2104
|
||||||
|
)
|
84
opcodes/gen/main.go
Normal file
84
opcodes/gen/main.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//go:build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
const outputTemplate = `// Code generated by gen/main.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
package opcodes
|
||||||
|
|
||||||
|
// initializeNameMappings populates nameToEmu from constants
|
||||||
|
func (om *OpcodeManager) initializeNameMappings() {
|
||||||
|
{{- range . }}
|
||||||
|
om.nameToEmu["{{ .Name }}"] = {{ .Name }}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
type OpcodeInfo struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
opcodes := []OpcodeInfo{}
|
||||||
|
|
||||||
|
// Parse each source file for OP_ constants
|
||||||
|
files := []string{"login.go", "emu.go"}
|
||||||
|
|
||||||
|
for _, filename := range files {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
node, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to parse %s: %v\n", filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all OP_ and LS_ constants
|
||||||
|
ast.Inspect(node, func(n ast.Node) bool {
|
||||||
|
spec, ok := n.(*ast.ValueSpec)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range spec.Names {
|
||||||
|
if strings.HasPrefix(name.Name, "OP_") || strings.HasPrefix(name.Name, "LS_") {
|
||||||
|
opcodes = append(opcodes, OpcodeInfo{Name: name.Name})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort for consistent output
|
||||||
|
sort.Slice(opcodes, func(i, j int) bool {
|
||||||
|
return opcodes[i].Name < opcodes[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
// Generate output
|
||||||
|
tmpl, err := template.New("opcodes").Parse(outputTemplate)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Create("generated.go")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if err := tmpl.Execute(file, opcodes); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Generated %d opcode mappings\n", len(opcodes))
|
||||||
|
}
|
621
opcodes/generated.go
Normal file
621
opcodes/generated.go
Normal file
@ -0,0 +1,621 @@
|
|||||||
|
// Code generated by gen/main.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
package opcodes
|
||||||
|
|
||||||
|
// initializeNameMappings populates nameToEmu from constants
|
||||||
|
func (om *OpcodeManager) initializeNameMappings() {
|
||||||
|
om.nameToEmu["LS_AccessGrantedMsg"] = LS_AccessGrantedMsg
|
||||||
|
om.nameToEmu["LS_AllCharactersDescReplyMsg"] = LS_AllCharactersDescReplyMsg
|
||||||
|
om.nameToEmu["LS_AllCharactersDescRequestMsg"] = LS_AllCharactersDescRequestMsg
|
||||||
|
om.nameToEmu["LS_AllWSDescRequestMsg"] = LS_AllWSDescRequestMsg
|
||||||
|
om.nameToEmu["LS_AllWorldsDescReplyMsg"] = LS_AllWorldsDescReplyMsg
|
||||||
|
om.nameToEmu["LS_AllWorldsDescRequestMsg"] = LS_AllWorldsDescRequestMsg
|
||||||
|
om.nameToEmu["LS_BadLanguageFilter"] = LS_BadLanguageFilter
|
||||||
|
om.nameToEmu["LS_CharListReplyMsg"] = LS_CharListReplyMsg
|
||||||
|
om.nameToEmu["LS_CharListRequestMsg"] = LS_CharListRequestMsg
|
||||||
|
om.nameToEmu["LS_CharSelectMsg"] = LS_CharSelectMsg
|
||||||
|
om.nameToEmu["LS_CreateAccountReplyMsg"] = LS_CreateAccountReplyMsg
|
||||||
|
om.nameToEmu["LS_CreateAccountRequestMsg"] = LS_CreateAccountRequestMsg
|
||||||
|
om.nameToEmu["LS_CreateCharReplyMsg"] = LS_CreateCharReplyMsg
|
||||||
|
om.nameToEmu["LS_CreateCharRequestMsg"] = LS_CreateCharRequestMsg
|
||||||
|
om.nameToEmu["LS_CreateCharacterReplyMsg"] = LS_CreateCharacterReplyMsg
|
||||||
|
om.nameToEmu["LS_CreateCharacterRequestMsg"] = LS_CreateCharacterRequestMsg
|
||||||
|
om.nameToEmu["LS_DeleteCharReplyMsg"] = LS_DeleteCharReplyMsg
|
||||||
|
om.nameToEmu["LS_DeleteCharRequestMsg"] = LS_DeleteCharRequestMsg
|
||||||
|
om.nameToEmu["LS_DeleteCharacterReplyMsg"] = LS_DeleteCharacterReplyMsg
|
||||||
|
om.nameToEmu["LS_DeleteCharacterRequestMsg"] = LS_DeleteCharacterRequestMsg
|
||||||
|
om.nameToEmu["LS_ESLoginRequestMsg"] = LS_ESLoginRequestMsg
|
||||||
|
om.nameToEmu["LS_KeymapDataMsg"] = LS_KeymapDataMsg
|
||||||
|
om.nameToEmu["LS_KeymapLoadMsg"] = LS_KeymapLoadMsg
|
||||||
|
om.nameToEmu["LS_KeymapNoneMsg"] = LS_KeymapNoneMsg
|
||||||
|
om.nameToEmu["LS_KeymapSaveMsg"] = LS_KeymapSaveMsg
|
||||||
|
om.nameToEmu["LS_LSCheckAcctLockMsg"] = LS_LSCheckAcctLockMsg
|
||||||
|
om.nameToEmu["LS_LSServerLockMsg"] = LS_LSServerLockMsg
|
||||||
|
om.nameToEmu["LS_LSStatusReplyMsg"] = LS_LSStatusReplyMsg
|
||||||
|
om.nameToEmu["LS_LSStatusRequestMsg"] = LS_LSStatusRequestMsg
|
||||||
|
om.nameToEmu["LS_LoginBannedMsg"] = LS_LoginBannedMsg
|
||||||
|
om.nameToEmu["LS_LoginByNumRequestMsg"] = LS_LoginByNumRequestMsg
|
||||||
|
om.nameToEmu["LS_LoginFailedMsg"] = LS_LoginFailedMsg
|
||||||
|
om.nameToEmu["LS_LoginReplyMsg"] = LS_LoginReplyMsg
|
||||||
|
om.nameToEmu["LS_LoginRequestMsg"] = LS_LoginRequestMsg
|
||||||
|
om.nameToEmu["LS_LsClientAlertlogReplyMsg"] = LS_LsClientAlertlogReplyMsg
|
||||||
|
om.nameToEmu["LS_LsClientBaselogReplyMsg"] = LS_LsClientBaselogReplyMsg
|
||||||
|
om.nameToEmu["LS_LsClientCrashlogReplyMsg"] = LS_LsClientCrashlogReplyMsg
|
||||||
|
om.nameToEmu["LS_LsClientVerifylogReplyMsg"] = LS_LsClientVerifylogReplyMsg
|
||||||
|
om.nameToEmu["LS_LsRequestClientCrashLogMsg"] = LS_LsRequestClientCrashLogMsg
|
||||||
|
om.nameToEmu["LS_PlayCharReplyMsg"] = LS_PlayCharReplyMsg
|
||||||
|
om.nameToEmu["LS_PlayCharRequestMsg"] = LS_PlayCharRequestMsg
|
||||||
|
om.nameToEmu["LS_PlayCharacterReplyMsg"] = LS_PlayCharacterReplyMsg
|
||||||
|
om.nameToEmu["LS_PlayCharacterRequestMsg"] = LS_PlayCharacterRequestMsg
|
||||||
|
om.nameToEmu["LS_ReskinCharacterRequestMsg"] = LS_ReskinCharacterRequestMsg
|
||||||
|
om.nameToEmu["LS_ServerListReplyMsg"] = LS_ServerListReplyMsg
|
||||||
|
om.nameToEmu["LS_ServerListRequestMsg"] = LS_ServerListRequestMsg
|
||||||
|
om.nameToEmu["LS_ServerPlayCharacterReplyMsg"] = LS_ServerPlayCharacterReplyMsg
|
||||||
|
om.nameToEmu["LS_ServerPlayCharacterRequestMsg"] = LS_ServerPlayCharacterRequestMsg
|
||||||
|
om.nameToEmu["LS_ServerStatusReplyMsg"] = LS_ServerStatusReplyMsg
|
||||||
|
om.nameToEmu["LS_ServerStatusRequestMsg"] = LS_ServerStatusRequestMsg
|
||||||
|
om.nameToEmu["LS_SessionReadyMsg"] = LS_SessionReadyMsg
|
||||||
|
om.nameToEmu["LS_UpdateCharacterSheetMsg"] = LS_UpdateCharacterSheetMsg
|
||||||
|
om.nameToEmu["LS_UpdateInventoryMsg"] = LS_UpdateInventoryMsg
|
||||||
|
om.nameToEmu["LS_UsertoWorldReq"] = LS_UsertoWorldReq
|
||||||
|
om.nameToEmu["LS_UsertoWorldResp"] = LS_UsertoWorldResp
|
||||||
|
om.nameToEmu["LS_WSAcctLockStatusMsg"] = LS_WSAcctLockStatusMsg
|
||||||
|
om.nameToEmu["LS_WSCreateCharacterReplyMsg"] = LS_WSCreateCharacterReplyMsg
|
||||||
|
om.nameToEmu["LS_WSCreateCharacterRequestMsg"] = LS_WSCreateCharacterRequestMsg
|
||||||
|
om.nameToEmu["LS_WSLoginRequestMsg"] = LS_WSLoginRequestMsg
|
||||||
|
om.nameToEmu["LS_WSServerHideMsg"] = LS_WSServerHideMsg
|
||||||
|
om.nameToEmu["LS_WSServerLockMsg"] = LS_WSServerLockMsg
|
||||||
|
om.nameToEmu["LS_WSStatusReplyMsg"] = LS_WSStatusReplyMsg
|
||||||
|
om.nameToEmu["LS_WorldListMsg"] = LS_WorldListMsg
|
||||||
|
om.nameToEmu["LS_WorldStatusChangeMsg"] = LS_WorldStatusChangeMsg
|
||||||
|
om.nameToEmu["LS_WorldStatusMsg"] = LS_WorldStatusMsg
|
||||||
|
om.nameToEmu["OP_AFKUpdateMsg"] = OP_AFKUpdateMsg
|
||||||
|
om.nameToEmu["OP_AchievementCompleteMsg"] = OP_AchievementCompleteMsg
|
||||||
|
om.nameToEmu["OP_AchievementUpdateMsg"] = OP_AchievementUpdateMsg
|
||||||
|
om.nameToEmu["OP_AdvancementRequestMsg"] = OP_AdvancementRequestMsg
|
||||||
|
om.nameToEmu["OP_AdventureList"] = OP_AdventureList
|
||||||
|
om.nameToEmu["OP_AfterInvSpellUpdate"] = OP_AfterInvSpellUpdate
|
||||||
|
om.nameToEmu["OP_AnonUpdateMsg"] = OP_AnonUpdateMsg
|
||||||
|
om.nameToEmu["OP_ArenaGameTypesMsg"] = OP_ArenaGameTypesMsg
|
||||||
|
om.nameToEmu["OP_AttackAllowed"] = OP_AttackAllowed
|
||||||
|
om.nameToEmu["OP_AttackMsg"] = OP_AttackMsg
|
||||||
|
om.nameToEmu["OP_AttackNotAllowed"] = OP_AttackNotAllowed
|
||||||
|
om.nameToEmu["OP_AuctionAbortMsg"] = OP_AuctionAbortMsg
|
||||||
|
om.nameToEmu["OP_AuctionCharacter"] = OP_AuctionCharacter
|
||||||
|
om.nameToEmu["OP_AuctionCharacterReply"] = OP_AuctionCharacterReply
|
||||||
|
om.nameToEmu["OP_AuctionCoin"] = OP_AuctionCoin
|
||||||
|
om.nameToEmu["OP_AuctionCoinReply"] = OP_AuctionCoinReply
|
||||||
|
om.nameToEmu["OP_AuctionCommitMsg"] = OP_AuctionCommitMsg
|
||||||
|
om.nameToEmu["OP_AuctionItem"] = OP_AuctionItem
|
||||||
|
om.nameToEmu["OP_AuctionItemReply"] = OP_AuctionItemReply
|
||||||
|
om.nameToEmu["OP_AutoAttackMsg"] = OP_AutoAttackMsg
|
||||||
|
om.nameToEmu["OP_AvatarCreatedMsg"] = OP_AvatarCreatedMsg
|
||||||
|
om.nameToEmu["OP_AvatarDestroyedMsg"] = OP_AvatarDestroyedMsg
|
||||||
|
om.nameToEmu["OP_AvatarUpdateMsg"] = OP_AvatarUpdateMsg
|
||||||
|
om.nameToEmu["OP_BadLanguageFilter"] = OP_BadLanguageFilter
|
||||||
|
om.nameToEmu["OP_BagOptions"] = OP_BagOptions
|
||||||
|
om.nameToEmu["OP_BeginItemCreationMsg"] = OP_BeginItemCreationMsg
|
||||||
|
om.nameToEmu["OP_BeginTrackingMsg"] = OP_BeginTrackingMsg
|
||||||
|
om.nameToEmu["OP_BioUpdateMsg"] = OP_BioUpdateMsg
|
||||||
|
om.nameToEmu["OP_BrokerAddBag"] = OP_BrokerAddBag
|
||||||
|
om.nameToEmu["OP_BuyPlayerHouseMsg"] = OP_BuyPlayerHouseMsg
|
||||||
|
om.nameToEmu["OP_BuyPlayerHouseTintMsg"] = OP_BuyPlayerHouseTintMsg
|
||||||
|
om.nameToEmu["OP_CSTicketAddCommentMsg"] = OP_CSTicketAddCommentMsg
|
||||||
|
om.nameToEmu["OP_CSTicketChangeNotificationMsg"] = OP_CSTicketChangeNotificationMsg
|
||||||
|
om.nameToEmu["OP_CSTicketCommentRequestMsg"] = OP_CSTicketCommentRequestMsg
|
||||||
|
om.nameToEmu["OP_CSTicketCommentResponseMsg"] = OP_CSTicketCommentResponseMsg
|
||||||
|
om.nameToEmu["OP_CSTicketCreateMsg"] = OP_CSTicketCreateMsg
|
||||||
|
om.nameToEmu["OP_CSTicketDeleteMsg"] = OP_CSTicketDeleteMsg
|
||||||
|
om.nameToEmu["OP_CSTicketHeaderRequestMsg"] = OP_CSTicketHeaderRequestMsg
|
||||||
|
om.nameToEmu["OP_CSTicketInfoMsg"] = OP_CSTicketInfoMsg
|
||||||
|
om.nameToEmu["OP_CSToolAccessResponseMsg"] = OP_CSToolAccessResponseMsg
|
||||||
|
om.nameToEmu["OP_CSToolsRequestMsg"] = OP_CSToolsRequestMsg
|
||||||
|
om.nameToEmu["OP_CSToolsResponseMsg"] = OP_CSToolsResponseMsg
|
||||||
|
om.nameToEmu["OP_CampAbortedMsg"] = OP_CampAbortedMsg
|
||||||
|
om.nameToEmu["OP_CampClientMsg"] = OP_CampClientMsg
|
||||||
|
om.nameToEmu["OP_CampStartedMsg"] = OP_CampStartedMsg
|
||||||
|
om.nameToEmu["OP_CancelCreateFromRecipeMsg"] = OP_CancelCreateFromRecipeMsg
|
||||||
|
om.nameToEmu["OP_CancelMoveObjectModeMsg"] = OP_CancelMoveObjectModeMsg
|
||||||
|
om.nameToEmu["OP_CancelSpellCast"] = OP_CancelSpellCast
|
||||||
|
om.nameToEmu["OP_CancelledFeignMsg"] = OP_CancelledFeignMsg
|
||||||
|
om.nameToEmu["OP_CastSpellMsg"] = OP_CastSpellMsg
|
||||||
|
om.nameToEmu["OP_ChangeServerControlFlagMsg"] = OP_ChangeServerControlFlagMsg
|
||||||
|
om.nameToEmu["OP_ChangeZoneMsg"] = OP_ChangeZoneMsg
|
||||||
|
om.nameToEmu["OP_CharNameChangedMsg"] = OP_CharNameChangedMsg
|
||||||
|
om.nameToEmu["OP_CharTransferCommitReplyMsg"] = OP_CharTransferCommitReplyMsg
|
||||||
|
om.nameToEmu["OP_CharTransferCommitRequestMsg"] = OP_CharTransferCommitRequestMsg
|
||||||
|
om.nameToEmu["OP_CharTransferReplyMsg"] = OP_CharTransferReplyMsg
|
||||||
|
om.nameToEmu["OP_CharTransferRequestMsg"] = OP_CharTransferRequestMsg
|
||||||
|
om.nameToEmu["OP_CharTransferRollbackReplyMsg"] = OP_CharTransferRollbackReplyMsg
|
||||||
|
om.nameToEmu["OP_CharTransferRollbackRequestMsg"] = OP_CharTransferRollbackRequestMsg
|
||||||
|
om.nameToEmu["OP_CharTransferStartReplyMsg"] = OP_CharTransferStartReplyMsg
|
||||||
|
om.nameToEmu["OP_CharTransferStartRequestMsg"] = OP_CharTransferStartRequestMsg
|
||||||
|
om.nameToEmu["OP_CharTransferValidateReplyMsg"] = OP_CharTransferValidateReplyMsg
|
||||||
|
om.nameToEmu["OP_CharTransferValidateRequestMsg"] = OP_CharTransferValidateRequestMsg
|
||||||
|
om.nameToEmu["OP_CharacterAchievements"] = OP_CharacterAchievements
|
||||||
|
om.nameToEmu["OP_CharacterCreateReplyMsg"] = OP_CharacterCreateReplyMsg
|
||||||
|
om.nameToEmu["OP_CharacterCreateRequestMsg"] = OP_CharacterCreateRequestMsg
|
||||||
|
om.nameToEmu["OP_CharacterCreatedDungeons"] = OP_CharacterCreatedDungeons
|
||||||
|
om.nameToEmu["OP_CharacterCurrency"] = OP_CharacterCurrency
|
||||||
|
om.nameToEmu["OP_CharacterHousingList"] = OP_CharacterHousingList
|
||||||
|
om.nameToEmu["OP_CharacterLinkdeadMsg"] = OP_CharacterLinkdeadMsg
|
||||||
|
om.nameToEmu["OP_CharacterMerc"] = OP_CharacterMerc
|
||||||
|
om.nameToEmu["OP_CharacterMounts"] = OP_CharacterMounts
|
||||||
|
om.nameToEmu["OP_CharacterPet"] = OP_CharacterPet
|
||||||
|
om.nameToEmu["OP_ChatCreateChannelMsg"] = OP_ChatCreateChannelMsg
|
||||||
|
om.nameToEmu["OP_ChatFiltersMsg"] = OP_ChatFiltersMsg
|
||||||
|
om.nameToEmu["OP_ChatJoinChannelMsg"] = OP_ChatJoinChannelMsg
|
||||||
|
om.nameToEmu["OP_ChatLeaveChannelMsg"] = OP_ChatLeaveChannelMsg
|
||||||
|
om.nameToEmu["OP_ChatMsg"] = OP_ChatMsg
|
||||||
|
om.nameToEmu["OP_ChatRelationshipUpdateMsg"] = OP_ChatRelationshipUpdateMsg
|
||||||
|
om.nameToEmu["OP_ChatSendFriendsMsg"] = OP_ChatSendFriendsMsg
|
||||||
|
om.nameToEmu["OP_ChatSendIgnoresMsg"] = OP_ChatSendIgnoresMsg
|
||||||
|
om.nameToEmu["OP_ChatTellChannelMsg"] = OP_ChatTellChannelMsg
|
||||||
|
om.nameToEmu["OP_ChatTellUserMsg"] = OP_ChatTellUserMsg
|
||||||
|
om.nameToEmu["OP_ChatToggleFriendMsg"] = OP_ChatToggleFriendMsg
|
||||||
|
om.nameToEmu["OP_ChatToggleIgnoreMsg"] = OP_ChatToggleIgnoreMsg
|
||||||
|
om.nameToEmu["OP_ChatWhoChannelMsg"] = OP_ChatWhoChannelMsg
|
||||||
|
om.nameToEmu["OP_ClearDataMsg"] = OP_ClearDataMsg
|
||||||
|
om.nameToEmu["OP_ClearForLandingMsg"] = OP_ClearForLandingMsg
|
||||||
|
om.nameToEmu["OP_ClearForTakeOffMsg"] = OP_ClearForTakeOffMsg
|
||||||
|
om.nameToEmu["OP_ClientCmdMsg"] = OP_ClientCmdMsg
|
||||||
|
om.nameToEmu["OP_ClientFellMsg"] = OP_ClientFellMsg
|
||||||
|
om.nameToEmu["OP_ClientIdMsg"] = OP_ClientIdMsg
|
||||||
|
om.nameToEmu["OP_ClientIdleBeginMsg"] = OP_ClientIdleBeginMsg
|
||||||
|
om.nameToEmu["OP_ClientIdleEndMsg"] = OP_ClientIdleEndMsg
|
||||||
|
om.nameToEmu["OP_ClientInDeathRegionMsg"] = OP_ClientInDeathRegionMsg
|
||||||
|
om.nameToEmu["OP_ClientTeleportRequestMsg"] = OP_ClientTeleportRequestMsg
|
||||||
|
om.nameToEmu["OP_ClientTeleportToLocationMsg"] = OP_ClientTeleportToLocationMsg
|
||||||
|
om.nameToEmu["OP_CloseGroupInviteWindowMsg"] = OP_CloseGroupInviteWindowMsg
|
||||||
|
om.nameToEmu["OP_CloseWindowMsg"] = OP_CloseWindowMsg
|
||||||
|
om.nameToEmu["OP_CollectAllHouseItemsMsg"] = OP_CollectAllHouseItemsMsg
|
||||||
|
om.nameToEmu["OP_ConsiderMsg"] = OP_ConsiderMsg
|
||||||
|
om.nameToEmu["OP_ConsignItemRequestMsg"] = OP_ConsignItemRequestMsg
|
||||||
|
om.nameToEmu["OP_ConsignItemResponseMsg"] = OP_ConsignItemResponseMsg
|
||||||
|
om.nameToEmu["OP_ConsignRemoveItemsMsg"] = OP_ConsignRemoveItemsMsg
|
||||||
|
om.nameToEmu["OP_ConsignViewCreateMsg"] = OP_ConsignViewCreateMsg
|
||||||
|
om.nameToEmu["OP_ConsignViewGetPageMsg"] = OP_ConsignViewGetPageMsg
|
||||||
|
om.nameToEmu["OP_ConsignViewReleaseMsg"] = OP_ConsignViewReleaseMsg
|
||||||
|
om.nameToEmu["OP_ConsignViewSortMsg"] = OP_ConsignViewSortMsg
|
||||||
|
om.nameToEmu["OP_ConsignmentCloseStoreMsg"] = OP_ConsignmentCloseStoreMsg
|
||||||
|
om.nameToEmu["OP_ConversationMsg"] = OP_ConversationMsg
|
||||||
|
om.nameToEmu["OP_CorruptedClientMsg"] = OP_CorruptedClientMsg
|
||||||
|
om.nameToEmu["OP_CreateBoatTransportsMsg"] = OP_CreateBoatTransportsMsg
|
||||||
|
om.nameToEmu["OP_CreateCharFromCBBReplyMsg"] = OP_CreateCharFromCBBReplyMsg
|
||||||
|
om.nameToEmu["OP_CreateCharFromCBBRequestMsg"] = OP_CreateCharFromCBBRequestMsg
|
||||||
|
om.nameToEmu["OP_CreateCharacterReplyMsg"] = OP_CreateCharacterReplyMsg
|
||||||
|
om.nameToEmu["OP_CreateCharacterRequestMsg"] = OP_CreateCharacterRequestMsg
|
||||||
|
om.nameToEmu["OP_CreateGuildReplyMsg"] = OP_CreateGuildReplyMsg
|
||||||
|
om.nameToEmu["OP_CreateGuildRequestMsg"] = OP_CreateGuildRequestMsg
|
||||||
|
om.nameToEmu["OP_CreateZoneInstanceMsg"] = OP_CreateZoneInstanceMsg
|
||||||
|
om.nameToEmu["OP_CsCategoryRequestMsg"] = OP_CsCategoryRequestMsg
|
||||||
|
om.nameToEmu["OP_CsCategoryResponseMsg"] = OP_CsCategoryResponseMsg
|
||||||
|
om.nameToEmu["OP_CurrentPet"] = OP_CurrentPet
|
||||||
|
om.nameToEmu["OP_CustomizationPurchaseRequestMs"] = OP_CustomizationPurchaseRequestMs
|
||||||
|
om.nameToEmu["OP_CustomizationReplyMsg"] = OP_CustomizationReplyMsg
|
||||||
|
om.nameToEmu["OP_CustomizationSetRequestMsg"] = OP_CustomizationSetRequestMsg
|
||||||
|
om.nameToEmu["OP_DailyObjectives"] = OP_DailyObjectives
|
||||||
|
om.nameToEmu["OP_DefaultGroupOptionsMsg"] = OP_DefaultGroupOptionsMsg
|
||||||
|
om.nameToEmu["OP_DefaultGroupOptionsRequestMsg"] = OP_DefaultGroupOptionsRequestMsg
|
||||||
|
om.nameToEmu["OP_DeleteGuildMsg"] = OP_DeleteGuildMsg
|
||||||
|
om.nameToEmu["OP_DeleteItemMsg"] = OP_DeleteItemMsg
|
||||||
|
om.nameToEmu["OP_DialogCloseMsg"] = OP_DialogCloseMsg
|
||||||
|
om.nameToEmu["OP_DialogOpenMsg"] = OP_DialogOpenMsg
|
||||||
|
om.nameToEmu["OP_DialogSelectMsg"] = OP_DialogSelectMsg
|
||||||
|
om.nameToEmu["OP_DietyAbilityWindow"] = OP_DietyAbilityWindow
|
||||||
|
om.nameToEmu["OP_DispatchClientCmdMsg"] = OP_DispatchClientCmdMsg
|
||||||
|
om.nameToEmu["OP_DispatchESMsg"] = OP_DispatchESMsg
|
||||||
|
om.nameToEmu["OP_DispatchSpellCmdMsg"] = OP_DispatchSpellCmdMsg
|
||||||
|
om.nameToEmu["OP_DisplayDebugNLLPointsMsg"] = OP_DisplayDebugNLLPointsMsg
|
||||||
|
om.nameToEmu["OP_DisplayGroupOptionsScreenMsg"] = OP_DisplayGroupOptionsScreenMsg
|
||||||
|
om.nameToEmu["OP_DisplayInnVisitScreenMsg"] = OP_DisplayInnVisitScreenMsg
|
||||||
|
om.nameToEmu["OP_DisplayMailScreenMsg"] = OP_DisplayMailScreenMsg
|
||||||
|
om.nameToEmu["OP_DisplayTSEventReactionMsg"] = OP_DisplayTSEventReactionMsg
|
||||||
|
om.nameToEmu["OP_DisplayWarningMsg"] = OP_DisplayWarningMsg
|
||||||
|
om.nameToEmu["OP_DoneLoadingEntityResourcesMsg"] = OP_DoneLoadingEntityResourcesMsg
|
||||||
|
om.nameToEmu["OP_DoneLoadingUIResourcesMsg"] = OP_DoneLoadingUIResourcesMsg
|
||||||
|
om.nameToEmu["OP_DoneLoadingZoneResourcesMsg"] = OP_DoneLoadingZoneResourcesMsg
|
||||||
|
om.nameToEmu["OP_DoneSendingInitialEntitiesMsg"] = OP_DoneSendingInitialEntitiesMsg
|
||||||
|
om.nameToEmu["OP_DressingRoom"] = OP_DressingRoom
|
||||||
|
om.nameToEmu["OP_DumpSchedulerMsg"] = OP_DumpSchedulerMsg
|
||||||
|
om.nameToEmu["OP_DungeonMakerItemRequest"] = OP_DungeonMakerItemRequest
|
||||||
|
om.nameToEmu["OP_EQHearDispellCmd"] = OP_EQHearDispellCmd
|
||||||
|
om.nameToEmu["OP_EQHearThreatCmd"] = OP_EQHearThreatCmd
|
||||||
|
om.nameToEmu["OP_ESInitMsg"] = OP_ESInitMsg
|
||||||
|
om.nameToEmu["OP_ESReadyForClientsMsg"] = OP_ESReadyForClientsMsg
|
||||||
|
om.nameToEmu["OP_ESStatusMsg"] = OP_ESStatusMsg
|
||||||
|
om.nameToEmu["OP_ESWeatherRequestEndMsg"] = OP_ESWeatherRequestEndMsg
|
||||||
|
om.nameToEmu["OP_ESWeatherRequestMsg"] = OP_ESWeatherRequestMsg
|
||||||
|
om.nameToEmu["OP_ESZoneInstanceStatusMsg"] = OP_ESZoneInstanceStatusMsg
|
||||||
|
om.nameToEmu["OP_EarlyLandingRequestMsg"] = OP_EarlyLandingRequestMsg
|
||||||
|
om.nameToEmu["OP_EncounterBrokenMsg"] = OP_EncounterBrokenMsg
|
||||||
|
om.nameToEmu["OP_EnterHouseMsg"] = OP_EnterHouseMsg
|
||||||
|
om.nameToEmu["OP_EnterMoveObjectModeMsg"] = OP_EnterMoveObjectModeMsg
|
||||||
|
om.nameToEmu["OP_EnterWorldMsg"] = OP_EnterWorldMsg
|
||||||
|
om.nameToEmu["OP_EntityVerbsReplyMsg"] = OP_EntityVerbsReplyMsg
|
||||||
|
om.nameToEmu["OP_EntityVerbsRequestMsg"] = OP_EntityVerbsRequestMsg
|
||||||
|
om.nameToEmu["OP_EntityVerbsVerbMsg"] = OP_EntityVerbsVerbMsg
|
||||||
|
om.nameToEmu["OP_EqAvailWorldChannelsCmd"] = OP_EqAvailWorldChannelsCmd
|
||||||
|
om.nameToEmu["OP_EqCannedEmoteCmd"] = OP_EqCannedEmoteCmd
|
||||||
|
om.nameToEmu["OP_EqChatChannelUpdateCmd"] = OP_EqChatChannelUpdateCmd
|
||||||
|
om.nameToEmu["OP_EqChoiceWinCmd"] = OP_EqChoiceWinCmd
|
||||||
|
om.nameToEmu["OP_EqCloseWindowCmd"] = OP_EqCloseWindowCmd
|
||||||
|
om.nameToEmu["OP_EqCollectionFilterCmd"] = OP_EqCollectionFilterCmd
|
||||||
|
om.nameToEmu["OP_EqCollectionItemCmd"] = OP_EqCollectionItemCmd
|
||||||
|
om.nameToEmu["OP_EqCollectionUpdateCmd"] = OP_EqCollectionUpdateCmd
|
||||||
|
om.nameToEmu["OP_EqConsignmentItemsCmd"] = OP_EqConsignmentItemsCmd
|
||||||
|
om.nameToEmu["OP_EqCreateGhostCmd"] = OP_EqCreateGhostCmd
|
||||||
|
om.nameToEmu["OP_EqCreateListBoxCmd"] = OP_EqCreateListBoxCmd
|
||||||
|
om.nameToEmu["OP_EqCreateSignWidgetCmd"] = OP_EqCreateSignWidgetCmd
|
||||||
|
om.nameToEmu["OP_EqCreateWidgetCmd"] = OP_EqCreateWidgetCmd
|
||||||
|
om.nameToEmu["OP_EqDebugPVDCmd"] = OP_EqDebugPVDCmd
|
||||||
|
om.nameToEmu["OP_EqDestroyGhostCmd"] = OP_EqDestroyGhostCmd
|
||||||
|
om.nameToEmu["OP_EqDialogCloseCmd"] = OP_EqDialogCloseCmd
|
||||||
|
om.nameToEmu["OP_EqDialogOpenCmd"] = OP_EqDialogOpenCmd
|
||||||
|
om.nameToEmu["OP_EqDisplaySpellFailCmd"] = OP_EqDisplaySpellFailCmd
|
||||||
|
om.nameToEmu["OP_EqDisplayTextCmd"] = OP_EqDisplayTextCmd
|
||||||
|
om.nameToEmu["OP_EqDrawablePathGraphCmd"] = OP_EqDrawablePathGraphCmd
|
||||||
|
om.nameToEmu["OP_EqEnableGameEventCmd"] = OP_EqEnableGameEventCmd
|
||||||
|
om.nameToEmu["OP_EqEnableWindowCmd"] = OP_EqEnableWindowCmd
|
||||||
|
om.nameToEmu["OP_EqExamineInfoCmd"] = OP_EqExamineInfoCmd
|
||||||
|
om.nameToEmu["OP_EqFactionUpdateCmd"] = OP_EqFactionUpdateCmd
|
||||||
|
om.nameToEmu["OP_EqFlashWindowCmd"] = OP_EqFlashWindowCmd
|
||||||
|
om.nameToEmu["OP_EqGetProbsCmd"] = OP_EqGetProbsCmd
|
||||||
|
om.nameToEmu["OP_EqGroupMemberRemovedCmd"] = OP_EqGroupMemberRemovedCmd
|
||||||
|
om.nameToEmu["OP_EqHearChainEffectCmd"] = OP_EqHearChainEffectCmd
|
||||||
|
om.nameToEmu["OP_EqHearChatCmd"] = OP_EqHearChatCmd
|
||||||
|
om.nameToEmu["OP_EqHearCombatCmd"] = OP_EqHearCombatCmd
|
||||||
|
om.nameToEmu["OP_EqHearConsiderCmd"] = OP_EqHearConsiderCmd
|
||||||
|
om.nameToEmu["OP_EqHearDeathCmd"] = OP_EqHearDeathCmd
|
||||||
|
om.nameToEmu["OP_EqHearDrowningCmd"] = OP_EqHearDrowningCmd
|
||||||
|
om.nameToEmu["OP_EqHearHealCmd"] = OP_EqHearHealCmd
|
||||||
|
om.nameToEmu["OP_EqHearPlayFlavorCmd"] = OP_EqHearPlayFlavorCmd
|
||||||
|
om.nameToEmu["OP_EqHearSpellCastCmd"] = OP_EqHearSpellCastCmd
|
||||||
|
om.nameToEmu["OP_EqHearSpellFizzleCmd"] = OP_EqHearSpellFizzleCmd
|
||||||
|
om.nameToEmu["OP_EqHearSpellInterruptCmd"] = OP_EqHearSpellInterruptCmd
|
||||||
|
om.nameToEmu["OP_EqHearSpellNoLandCmd"] = OP_EqHearSpellNoLandCmd
|
||||||
|
om.nameToEmu["OP_EqHelpPathClearCmd"] = OP_EqHelpPathClearCmd
|
||||||
|
om.nameToEmu["OP_EqHelpPathCmd"] = OP_EqHelpPathCmd
|
||||||
|
om.nameToEmu["OP_EqInspectPCResultsCmd"] = OP_EqInspectPCResultsCmd
|
||||||
|
om.nameToEmu["OP_EqInstructionWindowCloseCmd"] = OP_EqInstructionWindowCloseCmd
|
||||||
|
om.nameToEmu["OP_EqInstructionWindowCmd"] = OP_EqInstructionWindowCmd
|
||||||
|
om.nameToEmu["OP_EqInstructionWindowGoalCmd"] = OP_EqInstructionWindowGoalCmd
|
||||||
|
om.nameToEmu["OP_EqInstructionWindowTaskCmd"] = OP_EqInstructionWindowTaskCmd
|
||||||
|
om.nameToEmu["OP_EqJunctionListCmd"] = OP_EqJunctionListCmd
|
||||||
|
om.nameToEmu["OP_EqMapExplorationCmd"] = OP_EqMapExplorationCmd
|
||||||
|
om.nameToEmu["OP_EqPlaySound3DCmd"] = OP_EqPlaySound3DCmd
|
||||||
|
om.nameToEmu["OP_EqPlaySoundCmd"] = OP_EqPlaySoundCmd
|
||||||
|
om.nameToEmu["OP_EqPlayVoiceCmd"] = OP_EqPlayVoiceCmd
|
||||||
|
om.nameToEmu["OP_EqQuestGroupCmd"] = OP_EqQuestGroupCmd
|
||||||
|
om.nameToEmu["OP_EqQuestJournalReplyCmd"] = OP_EqQuestJournalReplyCmd
|
||||||
|
om.nameToEmu["OP_EqQuestJournalUpdateCmd"] = OP_EqQuestJournalUpdateCmd
|
||||||
|
om.nameToEmu["OP_EqQuestionnaireCmd"] = OP_EqQuestionnaireCmd
|
||||||
|
om.nameToEmu["OP_EqReceiveOfferCmd"] = OP_EqReceiveOfferCmd
|
||||||
|
om.nameToEmu["OP_EqResurrectedCmd"] = OP_EqResurrectedCmd
|
||||||
|
om.nameToEmu["OP_EqSetControlGhostCmd"] = OP_EqSetControlGhostCmd
|
||||||
|
om.nameToEmu["OP_EqSetDebugPathPointsCmd"] = OP_EqSetDebugPathPointsCmd
|
||||||
|
om.nameToEmu["OP_EqSetDefaultVerbCmd"] = OP_EqSetDefaultVerbCmd
|
||||||
|
om.nameToEmu["OP_EqSetPOVGhostCmd"] = OP_EqSetPOVGhostCmd
|
||||||
|
om.nameToEmu["OP_EqShowBookCmd"] = OP_EqShowBookCmd
|
||||||
|
om.nameToEmu["OP_EqShowDeathWindowCmd"] = OP_EqShowDeathWindowCmd
|
||||||
|
om.nameToEmu["OP_EqShowWindowCmd"] = OP_EqShowWindowCmd
|
||||||
|
om.nameToEmu["OP_EqSpellCastEndCmd"] = OP_EqSpellCastEndCmd
|
||||||
|
om.nameToEmu["OP_EqSpellCastStartCmd"] = OP_EqSpellCastStartCmd
|
||||||
|
om.nameToEmu["OP_EqSpellMoveToRangeAndRetryCmd"] = OP_EqSpellMoveToRangeAndRetryCmd
|
||||||
|
om.nameToEmu["OP_EqStartBrokerCmd"] = OP_EqStartBrokerCmd
|
||||||
|
om.nameToEmu["OP_EqStateCmd"] = OP_EqStateCmd
|
||||||
|
om.nameToEmu["OP_EqStoreLogCmd"] = OP_EqStoreLogCmd
|
||||||
|
om.nameToEmu["OP_EqTargetItemCmd"] = OP_EqTargetItemCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateBankCmd"] = OP_EqUpdateBankCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateGhostCmd"] = OP_EqUpdateGhostCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateLootCmd"] = OP_EqUpdateLootCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateMerchantCmd"] = OP_EqUpdateMerchantCmd
|
||||||
|
om.nameToEmu["OP_EqUpdatePlayerMailCmd"] = OP_EqUpdatePlayerMailCmd
|
||||||
|
om.nameToEmu["OP_EqUpdatePlayerTradeCmd"] = OP_EqUpdatePlayerTradeCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateSignWidgetCmd"] = OP_EqUpdateSignWidgetCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateStoreCmd"] = OP_EqUpdateStoreCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateSubClassesCmd"] = OP_EqUpdateSubClassesCmd
|
||||||
|
om.nameToEmu["OP_EqUpdateTargetCmd"] = OP_EqUpdateTargetCmd
|
||||||
|
om.nameToEmu["OP_EqWhoChannelQueryReplyCmd"] = OP_EqWhoChannelQueryReplyCmd
|
||||||
|
om.nameToEmu["OP_EquipItemMsg"] = OP_EquipItemMsg
|
||||||
|
om.nameToEmu["OP_ExamineConsignmentRequestMsg"] = OP_ExamineConsignmentRequestMsg
|
||||||
|
om.nameToEmu["OP_ExamineConsignmentResponseMsg"] = OP_ExamineConsignmentResponseMsg
|
||||||
|
om.nameToEmu["OP_ExamineInfoRequestMsg"] = OP_ExamineInfoRequestMsg
|
||||||
|
om.nameToEmu["OP_ExamineItemMsg"] = OP_ExamineItemMsg
|
||||||
|
om.nameToEmu["OP_ExamineItemRequestMsg"] = OP_ExamineItemRequestMsg
|
||||||
|
om.nameToEmu["OP_ExitHouseMsg"] = OP_ExitHouseMsg
|
||||||
|
om.nameToEmu["OP_ExitWorldMsg"] = OP_ExitWorldMsg
|
||||||
|
om.nameToEmu["OP_ExpUpdateMsg"] = OP_ExpUpdateMsg
|
||||||
|
om.nameToEmu["OP_ExpectClientAsCharacterReplyMs"] = OP_ExpectClientAsCharacterReplyMs
|
||||||
|
om.nameToEmu["OP_ExpectClientAsCharacterRequest"] = OP_ExpectClientAsCharacterRequest
|
||||||
|
om.nameToEmu["OP_FellowshipExpMsg"] = OP_FellowshipExpMsg
|
||||||
|
om.nameToEmu["OP_FlightPathsMsg"] = OP_FlightPathsMsg
|
||||||
|
om.nameToEmu["OP_GameWorldTimeMsg"] = OP_GameWorldTimeMsg
|
||||||
|
om.nameToEmu["OP_GetAvatarAccessRequestForCSToo"] = OP_GetAvatarAccessRequestForCSToo
|
||||||
|
om.nameToEmu["OP_GetCharacterSerializedReplyMsg"] = OP_GetCharacterSerializedReplyMsg
|
||||||
|
om.nameToEmu["OP_GetCharacterSerializedRequestM"] = OP_GetCharacterSerializedRequestM
|
||||||
|
om.nameToEmu["OP_GroupCreatedMsg"] = OP_GroupCreatedMsg
|
||||||
|
om.nameToEmu["OP_GroupDeclineResponseMsg"] = OP_GroupDeclineResponseMsg
|
||||||
|
om.nameToEmu["OP_GroupDestroyedMsg"] = OP_GroupDestroyedMsg
|
||||||
|
om.nameToEmu["OP_GroupInviteRequestMsg"] = OP_GroupInviteRequestMsg
|
||||||
|
om.nameToEmu["OP_GroupInviteResponseMsg"] = OP_GroupInviteResponseMsg
|
||||||
|
om.nameToEmu["OP_GroupLeaderChangedMsg"] = OP_GroupLeaderChangedMsg
|
||||||
|
om.nameToEmu["OP_GroupMemberAddedMsg"] = OP_GroupMemberAddedMsg
|
||||||
|
om.nameToEmu["OP_GroupMemberRemovedMsg"] = OP_GroupMemberRemovedMsg
|
||||||
|
om.nameToEmu["OP_GroupOptionsMsg"] = OP_GroupOptionsMsg
|
||||||
|
om.nameToEmu["OP_GroupRemovedFromGroupMsg"] = OP_GroupRemovedFromGroupMsg
|
||||||
|
om.nameToEmu["OP_GroupSettingsChangedMsg"] = OP_GroupSettingsChangedMsg
|
||||||
|
om.nameToEmu["OP_GuildBankEventListMsg"] = OP_GuildBankEventListMsg
|
||||||
|
om.nameToEmu["OP_GuildBankUpdateMsg"] = OP_GuildBankUpdateMsg
|
||||||
|
om.nameToEmu["OP_GuildEventActionMsg"] = OP_GuildEventActionMsg
|
||||||
|
om.nameToEmu["OP_GuildEventAddMsg"] = OP_GuildEventAddMsg
|
||||||
|
om.nameToEmu["OP_GuildEventDetailsMsg"] = OP_GuildEventDetailsMsg
|
||||||
|
om.nameToEmu["OP_GuildEventListMsg"] = OP_GuildEventListMsg
|
||||||
|
om.nameToEmu["OP_GuildEventMsg"] = OP_GuildEventMsg
|
||||||
|
om.nameToEmu["OP_GuildInviteMsg"] = OP_GuildInviteMsg
|
||||||
|
om.nameToEmu["OP_GuildInviteResponseMsg"] = OP_GuildInviteResponseMsg
|
||||||
|
om.nameToEmu["OP_GuildKickMsg"] = OP_GuildKickMsg
|
||||||
|
om.nameToEmu["OP_GuildMembershipResponseMsg"] = OP_GuildMembershipResponseMsg
|
||||||
|
om.nameToEmu["OP_GuildMotdMsg"] = OP_GuildMotdMsg
|
||||||
|
om.nameToEmu["OP_GuildRecruiting"] = OP_GuildRecruiting
|
||||||
|
om.nameToEmu["OP_GuildRecruitingDetails"] = OP_GuildRecruitingDetails
|
||||||
|
om.nameToEmu["OP_GuildRecruitingImage"] = OP_GuildRecruitingImage
|
||||||
|
om.nameToEmu["OP_GuildRecruitingMemberInfo"] = OP_GuildRecruitingMemberInfo
|
||||||
|
om.nameToEmu["OP_GuildUpdateMsg"] = OP_GuildUpdateMsg
|
||||||
|
om.nameToEmu["OP_GuildsayMsg"] = OP_GuildsayMsg
|
||||||
|
om.nameToEmu["OP_HeritageMsg"] = OP_HeritageMsg
|
||||||
|
om.nameToEmu["OP_HouseAccessRemoveMsg"] = OP_HouseAccessRemoveMsg
|
||||||
|
om.nameToEmu["OP_HouseAccessSetMsg"] = OP_HouseAccessSetMsg
|
||||||
|
om.nameToEmu["OP_HouseCustomizationScreenMsg"] = OP_HouseCustomizationScreenMsg
|
||||||
|
om.nameToEmu["OP_HouseDefaultAccessSetMsg"] = OP_HouseDefaultAccessSetMsg
|
||||||
|
om.nameToEmu["OP_HouseDeletedRemotelyMsg"] = OP_HouseDeletedRemotelyMsg
|
||||||
|
om.nameToEmu["OP_HouseItemsList"] = OP_HouseItemsList
|
||||||
|
om.nameToEmu["OP_HousePayUpkeep"] = OP_HousePayUpkeep
|
||||||
|
om.nameToEmu["OP_HousePurchase"] = OP_HousePurchase
|
||||||
|
om.nameToEmu["OP_HousingDataChangedMsg"] = OP_HousingDataChangedMsg
|
||||||
|
om.nameToEmu["OP_HousingDataMsg"] = OP_HousingDataMsg
|
||||||
|
om.nameToEmu["OP_HousingRestoreMsg"] = OP_HousingRestoreMsg
|
||||||
|
om.nameToEmu["OP_InspectPlayerMsg"] = OP_InspectPlayerMsg
|
||||||
|
om.nameToEmu["OP_InterruptSpellMsg"] = OP_InterruptSpellMsg
|
||||||
|
om.nameToEmu["OP_InventoryMsg"] = OP_InventoryMsg
|
||||||
|
om.nameToEmu["OP_JoinGuildNotifyMsg"] = OP_JoinGuildNotifyMsg
|
||||||
|
om.nameToEmu["OP_JournalQuestStoryline"] = OP_JournalQuestStoryline
|
||||||
|
om.nameToEmu["OP_KeybindLoadMsg"] = OP_KeybindLoadMsg
|
||||||
|
om.nameToEmu["OP_KeybindUpdateMsg"] = OP_KeybindUpdateMsg
|
||||||
|
om.nameToEmu["OP_KeymapDataMsg"] = OP_KeymapDataMsg
|
||||||
|
om.nameToEmu["OP_KeymapLoadMsg"] = OP_KeymapLoadMsg
|
||||||
|
om.nameToEmu["OP_KeymapNoneMsg"] = OP_KeymapNoneMsg
|
||||||
|
om.nameToEmu["OP_KeymapSaveMsg"] = OP_KeymapSaveMsg
|
||||||
|
om.nameToEmu["OP_KnowledgeWindowSlotMappingMsg"] = OP_KnowledgeWindowSlotMappingMsg
|
||||||
|
om.nameToEmu["OP_KnowledgebaseRequestMsg"] = OP_KnowledgebaseRequestMsg
|
||||||
|
om.nameToEmu["OP_KnowledgebaseResponseMsg"] = OP_KnowledgebaseResponseMsg
|
||||||
|
om.nameToEmu["OP_KnownLanguagesMsg"] = OP_KnownLanguagesMsg
|
||||||
|
om.nameToEmu["OP_LFGGroupSearch"] = OP_LFGGroupSearch
|
||||||
|
om.nameToEmu["OP_LFGUpdateMsg"] = OP_LFGUpdateMsg
|
||||||
|
om.nameToEmu["OP_LSCheckAcctLockMsg"] = OP_LSCheckAcctLockMsg
|
||||||
|
om.nameToEmu["OP_LSServerLockMsg"] = OP_LSServerLockMsg
|
||||||
|
om.nameToEmu["OP_Launchpad"] = OP_Launchpad
|
||||||
|
om.nameToEmu["OP_LeaveGuildNotifyMsg"] = OP_LeaveGuildNotifyMsg
|
||||||
|
om.nameToEmu["OP_LevelChangedMsg"] = OP_LevelChangedMsg
|
||||||
|
om.nameToEmu["OP_LevelUpMsg"] = OP_LevelUpMsg
|
||||||
|
om.nameToEmu["OP_LikeOption"] = OP_LikeOption
|
||||||
|
om.nameToEmu["OP_LoadCalendarEvents"] = OP_LoadCalendarEvents
|
||||||
|
om.nameToEmu["OP_LoadWelcomeWindow"] = OP_LoadWelcomeWindow
|
||||||
|
om.nameToEmu["OP_LoginAcceptedMsg"] = OP_LoginAcceptedMsg
|
||||||
|
om.nameToEmu["OP_LoginByNumRequestMsg"] = OP_LoginByNumRequestMsg
|
||||||
|
om.nameToEmu["OP_LoginFailedMsg2"] = OP_LoginFailedMsg2
|
||||||
|
om.nameToEmu["OP_LoginReplyMsg"] = OP_LoginReplyMsg
|
||||||
|
om.nameToEmu["OP_LootItemsRequestMsg"] = OP_LootItemsRequestMsg
|
||||||
|
om.nameToEmu["OP_Lottery"] = OP_Lottery
|
||||||
|
om.nameToEmu["OP_LsClientAlertlogReplyMsg"] = OP_LsClientAlertlogReplyMsg
|
||||||
|
om.nameToEmu["OP_LsClientBaselogReplyMsg"] = OP_LsClientBaselogReplyMsg
|
||||||
|
om.nameToEmu["OP_LsClientCrashlogReplyMsg"] = OP_LsClientCrashlogReplyMsg
|
||||||
|
om.nameToEmu["OP_LsClientVerifylogReplyMsg"] = OP_LsClientVerifylogReplyMsg
|
||||||
|
om.nameToEmu["OP_LsRequestClientCrashLogMsg"] = OP_LsRequestClientCrashLogMsg
|
||||||
|
om.nameToEmu["OP_MOTDMsg"] = OP_MOTDMsg
|
||||||
|
om.nameToEmu["OP_MacroInitMsg"] = OP_MacroInitMsg
|
||||||
|
om.nameToEmu["OP_MacroUpdateMsg"] = OP_MacroUpdateMsg
|
||||||
|
om.nameToEmu["OP_MailCommitSendMessageMsg"] = OP_MailCommitSendMessageMsg
|
||||||
|
om.nameToEmu["OP_MailDeleteMessageMsg"] = OP_MailDeleteMessageMsg
|
||||||
|
om.nameToEmu["OP_MailDeleteMessageRequestMsg"] = OP_MailDeleteMessageRequestMsg
|
||||||
|
om.nameToEmu["OP_MailEventNotificationMsg"] = OP_MailEventNotificationMsg
|
||||||
|
om.nameToEmu["OP_MailGetHeadersReplyMsg"] = OP_MailGetHeadersReplyMsg
|
||||||
|
om.nameToEmu["OP_MailGetHeadersRequestMsg"] = OP_MailGetHeadersRequestMsg
|
||||||
|
om.nameToEmu["OP_MailGetMessageMsg"] = OP_MailGetMessageMsg
|
||||||
|
om.nameToEmu["OP_MailGetMessageReplyMsg"] = OP_MailGetMessageReplyMsg
|
||||||
|
om.nameToEmu["OP_MailGetMessageRequestMsg"] = OP_MailGetMessageRequestMsg
|
||||||
|
om.nameToEmu["OP_MailRemoveAttachFromMailMsg"] = OP_MailRemoveAttachFromMailMsg
|
||||||
|
om.nameToEmu["OP_MailSendMessageMsg"] = OP_MailSendMessageMsg
|
||||||
|
om.nameToEmu["OP_MailSendMessageReplyMsg"] = OP_MailSendMessageReplyMsg
|
||||||
|
om.nameToEmu["OP_MailSendMessageRequestMsg"] = OP_MailSendMessageRequestMsg
|
||||||
|
om.nameToEmu["OP_MailSendSystemMessageMsg"] = OP_MailSendSystemMessageMsg
|
||||||
|
om.nameToEmu["OP_MakeGroupLeaderMsg"] = OP_MakeGroupLeaderMsg
|
||||||
|
om.nameToEmu["OP_MapFogDataInitMsg"] = OP_MapFogDataInitMsg
|
||||||
|
om.nameToEmu["OP_MapFogDataUpdateMsg"] = OP_MapFogDataUpdateMsg
|
||||||
|
om.nameToEmu["OP_MapRequest"] = OP_MapRequest
|
||||||
|
om.nameToEmu["OP_MarketAddFundsRequest"] = OP_MarketAddFundsRequest
|
||||||
|
om.nameToEmu["OP_MarketFundsUpdate"] = OP_MarketFundsUpdate
|
||||||
|
om.nameToEmu["OP_MarketPlacePrices"] = OP_MarketPlacePrices
|
||||||
|
om.nameToEmu["OP_MigrateBoatTransportMsg"] = OP_MigrateBoatTransportMsg
|
||||||
|
om.nameToEmu["OP_MigrateBoatTransportReplyMsg"] = OP_MigrateBoatTransportReplyMsg
|
||||||
|
om.nameToEmu["OP_MigrateClientToZoneReplyMsg"] = OP_MigrateClientToZoneReplyMsg
|
||||||
|
om.nameToEmu["OP_MigrateClientToZoneRequestMsg"] = OP_MigrateClientToZoneRequestMsg
|
||||||
|
om.nameToEmu["OP_ModifyGuildMsg"] = OP_ModifyGuildMsg
|
||||||
|
om.nameToEmu["OP_MonitorCharacterListMsg"] = OP_MonitorCharacterListMsg
|
||||||
|
om.nameToEmu["OP_MonitorCharacterListRequestMsg"] = OP_MonitorCharacterListRequestMsg
|
||||||
|
om.nameToEmu["OP_MonitorReplyMsg"] = OP_MonitorReplyMsg
|
||||||
|
om.nameToEmu["OP_MoveLogUpdateMsg"] = OP_MoveLogUpdateMsg
|
||||||
|
om.nameToEmu["OP_MoveableObjectPlacementCriteri"] = OP_MoveableObjectPlacementCriteri
|
||||||
|
om.nameToEmu["OP_NewZoneMsg"] = OP_NewZoneMsg
|
||||||
|
om.nameToEmu["OP_NotifyApprenticeStoppedMentori"] = OP_NotifyApprenticeStoppedMentori
|
||||||
|
om.nameToEmu["OP_OfferQuestMsg"] = OP_OfferQuestMsg
|
||||||
|
om.nameToEmu["OP_OnscreenMsgMsg"] = OP_OnscreenMsgMsg
|
||||||
|
om.nameToEmu["OP_OpenCharCust"] = OP_OpenCharCust
|
||||||
|
om.nameToEmu["OP_PaperdollImage"] = OP_PaperdollImage
|
||||||
|
om.nameToEmu["OP_PayHouseUpkeepMsg"] = OP_PayHouseUpkeepMsg
|
||||||
|
om.nameToEmu["OP_PerformCameraShakeMsg"] = OP_PerformCameraShakeMsg
|
||||||
|
om.nameToEmu["OP_PerformPlayerKnockbackMsg"] = OP_PerformPlayerKnockbackMsg
|
||||||
|
om.nameToEmu["OP_PetOptions"] = OP_PetOptions
|
||||||
|
om.nameToEmu["OP_PetOptionsResponse"] = OP_PetOptionsResponse
|
||||||
|
om.nameToEmu["OP_PlayerBioMsg"] = OP_PlayerBioMsg
|
||||||
|
om.nameToEmu["OP_PlayerHouseAccessUpdateMsg"] = OP_PlayerHouseAccessUpdateMsg
|
||||||
|
om.nameToEmu["OP_PlayerHouseBaseScreenMsg"] = OP_PlayerHouseBaseScreenMsg
|
||||||
|
om.nameToEmu["OP_PlayerHouseCloseUIMsg"] = OP_PlayerHouseCloseUIMsg
|
||||||
|
om.nameToEmu["OP_PlayerHouseDisplayStatusMsg"] = OP_PlayerHouseDisplayStatusMsg
|
||||||
|
om.nameToEmu["OP_PlayerHousePurchaseScreenMsg"] = OP_PlayerHousePurchaseScreenMsg
|
||||||
|
om.nameToEmu["OP_PlayerProfileMsg"] = OP_PlayerProfileMsg
|
||||||
|
om.nameToEmu["OP_PlayerStatsMsg"] = OP_PlayerStatsMsg
|
||||||
|
om.nameToEmu["OP_PointOfInterest"] = OP_PointOfInterest
|
||||||
|
om.nameToEmu["OP_PopulateSkillMapsMsg"] = OP_PopulateSkillMapsMsg
|
||||||
|
om.nameToEmu["OP_PositionBoatTransportMsg"] = OP_PositionBoatTransportMsg
|
||||||
|
om.nameToEmu["OP_PositionMoveableObject"] = OP_PositionMoveableObject
|
||||||
|
om.nameToEmu["OP_PredictionUpdateMsg"] = OP_PredictionUpdateMsg
|
||||||
|
om.nameToEmu["OP_PromoFlagsDetailsMsg"] = OP_PromoFlagsDetailsMsg
|
||||||
|
om.nameToEmu["OP_PurchaseConsignmentLoreCheckRe"] = OP_PurchaseConsignmentLoreCheckRe
|
||||||
|
om.nameToEmu["OP_QueryHoodMsg"] = OP_QueryHoodMsg
|
||||||
|
om.nameToEmu["OP_QueryNpcMsg"] = OP_QueryNpcMsg
|
||||||
|
om.nameToEmu["OP_QuestCompleteMsg"] = OP_QuestCompleteMsg
|
||||||
|
om.nameToEmu["OP_QuestFailedMsg"] = OP_QuestFailedMsg
|
||||||
|
om.nameToEmu["OP_QuestJournalInspectMsg"] = OP_QuestJournalInspectMsg
|
||||||
|
om.nameToEmu["OP_QuestJournalOpenMsg"] = OP_QuestJournalOpenMsg
|
||||||
|
om.nameToEmu["OP_QuestJournalReplyMsg"] = OP_QuestJournalReplyMsg
|
||||||
|
om.nameToEmu["OP_QuestJournalSetVisibleMsg"] = OP_QuestJournalSetVisibleMsg
|
||||||
|
om.nameToEmu["OP_QuestJournalUpdateMsg"] = OP_QuestJournalUpdateMsg
|
||||||
|
om.nameToEmu["OP_QuestJournalWaypointMsg"] = OP_QuestJournalWaypointMsg
|
||||||
|
om.nameToEmu["OP_QuestOfferMsg"] = OP_QuestOfferMsg
|
||||||
|
om.nameToEmu["OP_QuestReward"] = OP_QuestReward
|
||||||
|
om.nameToEmu["OP_QuestRewardMsg"] = OP_QuestRewardMsg
|
||||||
|
om.nameToEmu["OP_QuestionnaireMsg"] = OP_QuestionnaireMsg
|
||||||
|
om.nameToEmu["OP_QuickbarInitMsg"] = OP_QuickbarInitMsg
|
||||||
|
om.nameToEmu["OP_QuickbarUpdateMsg"] = OP_QuickbarUpdateMsg
|
||||||
|
om.nameToEmu["OP_RaceRestrictionMsg"] = OP_RaceRestrictionMsg
|
||||||
|
om.nameToEmu["OP_ReadyForTakeOffMsg"] = OP_ReadyForTakeOffMsg
|
||||||
|
om.nameToEmu["OP_ReadyToZoneMsg"] = OP_ReadyToZoneMsg
|
||||||
|
om.nameToEmu["OP_RecipeBook"] = OP_RecipeBook
|
||||||
|
om.nameToEmu["OP_RecipeDetailsMsg"] = OP_RecipeDetailsMsg
|
||||||
|
om.nameToEmu["OP_RecipeList"] = OP_RecipeList
|
||||||
|
om.nameToEmu["OP_RecipeListUnknown"] = OP_RecipeListUnknown
|
||||||
|
om.nameToEmu["OP_RelinquishHouseMsg"] = OP_RelinquishHouseMsg
|
||||||
|
om.nameToEmu["OP_ReloadLocalizedTxtMsg"] = OP_ReloadLocalizedTxtMsg
|
||||||
|
om.nameToEmu["OP_RemoteCmdMsg"] = OP_RemoteCmdMsg
|
||||||
|
om.nameToEmu["OP_RemoveClientFromGroupMsg"] = OP_RemoveClientFromGroupMsg
|
||||||
|
om.nameToEmu["OP_RemoveConcentrationMsg"] = OP_RemoveConcentrationMsg
|
||||||
|
om.nameToEmu["OP_RemoveGroupFromGroupMsg"] = OP_RemoveGroupFromGroupMsg
|
||||||
|
om.nameToEmu["OP_RemoveSpellEffectMsg"] = OP_RemoveSpellEffectMsg
|
||||||
|
om.nameToEmu["OP_RenameGuildMsg"] = OP_RenameGuildMsg
|
||||||
|
om.nameToEmu["OP_ReplaceableSubMeshesMsg"] = OP_ReplaceableSubMeshesMsg
|
||||||
|
om.nameToEmu["OP_ReportMsg"] = OP_ReportMsg
|
||||||
|
om.nameToEmu["OP_RequestCampMsg"] = OP_RequestCampMsg
|
||||||
|
om.nameToEmu["OP_RequestGuildBankEventDetailsMs"] = OP_RequestGuildBankEventDetailsMs
|
||||||
|
om.nameToEmu["OP_RequestGuildEventDetailsMsg"] = OP_RequestGuildEventDetailsMsg
|
||||||
|
om.nameToEmu["OP_RequestGuildInfoMsg"] = OP_RequestGuildInfoMsg
|
||||||
|
om.nameToEmu["OP_RequestGuildMembershipMsg"] = OP_RequestGuildMembershipMsg
|
||||||
|
om.nameToEmu["OP_RequestHelpRepathMsg"] = OP_RequestHelpRepathMsg
|
||||||
|
om.nameToEmu["OP_RequestRecipeDetailsMsg"] = OP_RequestRecipeDetailsMsg
|
||||||
|
om.nameToEmu["OP_RequestTargetLocMsg"] = OP_RequestTargetLocMsg
|
||||||
|
om.nameToEmu["OP_RestartZoneMsg"] = OP_RestartZoneMsg
|
||||||
|
om.nameToEmu["OP_RewardPackMsg"] = OP_RewardPackMsg
|
||||||
|
om.nameToEmu["OP_SatMsg"] = OP_SatMsg
|
||||||
|
om.nameToEmu["OP_SavageBarInitMsg"] = OP_SavageBarInitMsg
|
||||||
|
om.nameToEmu["OP_SelectZoneTeleporterDestinatio"] = OP_SelectZoneTeleporterDestinatio
|
||||||
|
om.nameToEmu["OP_SendLatestRequestMsg"] = OP_SendLatestRequestMsg
|
||||||
|
om.nameToEmu["OP_SendZonePointsMsg"] = OP_SendZonePointsMsg
|
||||||
|
om.nameToEmu["OP_SetInstanceDisplayNameMsg"] = OP_SetInstanceDisplayNameMsg
|
||||||
|
om.nameToEmu["OP_SetRemoteCmdsMsg"] = OP_SetRemoteCmdsMsg
|
||||||
|
om.nameToEmu["OP_SetSocialMsg"] = OP_SetSocialMsg
|
||||||
|
om.nameToEmu["OP_SetTimeMsg"] = OP_SetTimeMsg
|
||||||
|
om.nameToEmu["OP_ShaderCustomizationMsg"] = OP_ShaderCustomizationMsg
|
||||||
|
om.nameToEmu["OP_ShowCreateFromRecipeUIMsg"] = OP_ShowCreateFromRecipeUIMsg
|
||||||
|
om.nameToEmu["OP_ShowItemCreationProcessUIMsg"] = OP_ShowItemCreationProcessUIMsg
|
||||||
|
om.nameToEmu["OP_ShowRecipeBookMsg"] = OP_ShowRecipeBookMsg
|
||||||
|
om.nameToEmu["OP_ShowZoneTeleporterDestinations"] = OP_ShowZoneTeleporterDestinations
|
||||||
|
om.nameToEmu["OP_SignalMsg"] = OP_SignalMsg
|
||||||
|
om.nameToEmu["OP_SitMsg"] = OP_SitMsg
|
||||||
|
om.nameToEmu["OP_SkillInfoRequest"] = OP_SkillInfoRequest
|
||||||
|
om.nameToEmu["OP_SkillInfoRequestMsg"] = OP_SkillInfoRequestMsg
|
||||||
|
om.nameToEmu["OP_SkillInfoResponse"] = OP_SkillInfoResponse
|
||||||
|
om.nameToEmu["OP_SkillInfoResponseMsg"] = OP_SkillInfoResponseMsg
|
||||||
|
om.nameToEmu["OP_SkillUpMsg"] = OP_SkillUpMsg
|
||||||
|
om.nameToEmu["OP_SpellGainedMsg"] = OP_SpellGainedMsg
|
||||||
|
om.nameToEmu["OP_StandMsg"] = OP_StandMsg
|
||||||
|
om.nameToEmu["OP_StoodMsg"] = OP_StoodMsg
|
||||||
|
om.nameToEmu["OP_StopItemCreationMsg"] = OP_StopItemCreationMsg
|
||||||
|
om.nameToEmu["OP_StopTrackingMsg"] = OP_StopTrackingMsg
|
||||||
|
om.nameToEmu["OP_StoppedLootingMsg"] = OP_StoppedLootingMsg
|
||||||
|
om.nameToEmu["OP_SubmitCharCust"] = OP_SubmitCharCust
|
||||||
|
om.nameToEmu["OP_SysClient"] = OP_SysClient
|
||||||
|
om.nameToEmu["OP_TargetMsg"] = OP_TargetMsg
|
||||||
|
om.nameToEmu["OP_TeleportWithinZoneMsg"] = OP_TeleportWithinZoneMsg
|
||||||
|
om.nameToEmu["OP_TeleportWithinZoneNoReloadMsg"] = OP_TeleportWithinZoneNoReloadMsg
|
||||||
|
om.nameToEmu["OP_TellMsg"] = OP_TellMsg
|
||||||
|
om.nameToEmu["OP_TintWidgetsMsg"] = OP_TintWidgetsMsg
|
||||||
|
om.nameToEmu["OP_TitleUpdateMsg"] = OP_TitleUpdateMsg
|
||||||
|
om.nameToEmu["OP_TrackingUpdateMsg"] = OP_TrackingUpdateMsg
|
||||||
|
om.nameToEmu["OP_TradeAcceptMsg"] = OP_TradeAcceptMsg
|
||||||
|
om.nameToEmu["OP_TradeAddItemMsg"] = OP_TradeAddItemMsg
|
||||||
|
om.nameToEmu["OP_TradeEndMsg"] = OP_TradeEndMsg
|
||||||
|
om.nameToEmu["OP_TradeRemoveItemMsg"] = OP_TradeRemoveItemMsg
|
||||||
|
om.nameToEmu["OP_TradeRequestMsg"] = OP_TradeRequestMsg
|
||||||
|
om.nameToEmu["OP_TradeResponseMsg"] = OP_TradeResponseMsg
|
||||||
|
om.nameToEmu["OP_TradeStartMsg"] = OP_TradeStartMsg
|
||||||
|
om.nameToEmu["OP_TradeskillList"] = OP_TradeskillList
|
||||||
|
om.nameToEmu["OP_TraitsList"] = OP_TraitsList
|
||||||
|
om.nameToEmu["OP_UIEvent"] = OP_UIEvent
|
||||||
|
om.nameToEmu["OP_UIResetMsg"] = OP_UIResetMsg
|
||||||
|
om.nameToEmu["OP_UISettingsMsg"] = OP_UISettingsMsg
|
||||||
|
om.nameToEmu["OP_UISettingsResponseMsg"] = OP_UISettingsResponseMsg
|
||||||
|
om.nameToEmu["OP_UnequipItemMsg"] = OP_UnequipItemMsg
|
||||||
|
om.nameToEmu["OP_Unknown"] = OP_Unknown
|
||||||
|
om.nameToEmu["OP_UnknownNpcMsg"] = OP_UnknownNpcMsg
|
||||||
|
om.nameToEmu["OP_UpdateActivePublicZonesMsg"] = OP_UpdateActivePublicZonesMsg
|
||||||
|
om.nameToEmu["OP_UpdateCharacterSheetMsg"] = OP_UpdateCharacterSheetMsg
|
||||||
|
om.nameToEmu["OP_UpdateClientPredFlagsMsg"] = OP_UpdateClientPredFlagsMsg
|
||||||
|
om.nameToEmu["OP_UpdateDebugRadiiMsg"] = OP_UpdateDebugRadiiMsg
|
||||||
|
om.nameToEmu["OP_UpdateGroupMemberDataMsg"] = OP_UpdateGroupMemberDataMsg
|
||||||
|
om.nameToEmu["OP_UpdateHouseAccessDataMsg"] = OP_UpdateHouseAccessDataMsg
|
||||||
|
om.nameToEmu["OP_UpdateHouseDataMsg"] = OP_UpdateHouseDataMsg
|
||||||
|
om.nameToEmu["OP_UpdateInventoryMsg"] = OP_UpdateInventoryMsg
|
||||||
|
om.nameToEmu["OP_UpdateItemCreationProcessUIMsg"] = OP_UpdateItemCreationProcessUIMsg
|
||||||
|
om.nameToEmu["OP_UpdateMotdMsg"] = OP_UpdateMotdMsg
|
||||||
|
om.nameToEmu["OP_UpdateOpportunityMsg"] = OP_UpdateOpportunityMsg
|
||||||
|
om.nameToEmu["OP_UpdatePositionMsg"] = OP_UpdatePositionMsg
|
||||||
|
om.nameToEmu["OP_UpdateRaidMsg"] = OP_UpdateRaidMsg
|
||||||
|
om.nameToEmu["OP_UpdateRecipeBookMsg"] = OP_UpdateRecipeBookMsg
|
||||||
|
om.nameToEmu["OP_UpdateSkillBookMsg"] = OP_UpdateSkillBookMsg
|
||||||
|
om.nameToEmu["OP_UpdateSkillsMsg"] = OP_UpdateSkillsMsg
|
||||||
|
om.nameToEmu["OP_UpdateSpellBookMsg"] = OP_UpdateSpellBookMsg
|
||||||
|
om.nameToEmu["OP_UpdateTargetLocMsg"] = OP_UpdateTargetLocMsg
|
||||||
|
om.nameToEmu["OP_UpdateTargetMsg"] = OP_UpdateTargetMsg
|
||||||
|
om.nameToEmu["OP_UpdateTitleCmd"] = OP_UpdateTitleCmd
|
||||||
|
om.nameToEmu["OP_UseItemMsg"] = OP_UseItemMsg
|
||||||
|
om.nameToEmu["OP_WSAcctLockStatusMsg"] = OP_WSAcctLockStatusMsg
|
||||||
|
om.nameToEmu["OP_WSLoginRequestMsg"] = OP_WSLoginRequestMsg
|
||||||
|
om.nameToEmu["OP_WSServerHideMsg"] = OP_WSServerHideMsg
|
||||||
|
om.nameToEmu["OP_WSServerLockMsg"] = OP_WSServerLockMsg
|
||||||
|
om.nameToEmu["OP_WaypointReplyMsg"] = OP_WaypointReplyMsg
|
||||||
|
om.nameToEmu["OP_WaypointRequestMsg"] = OP_WaypointRequestMsg
|
||||||
|
om.nameToEmu["OP_WaypointSelectMsg"] = OP_WaypointSelectMsg
|
||||||
|
om.nameToEmu["OP_WaypointUpdateMsg"] = OP_WaypointUpdateMsg
|
||||||
|
om.nameToEmu["OP_Weakness"] = OP_Weakness
|
||||||
|
om.nameToEmu["OP_WhoQueryReplyMsg"] = OP_WhoQueryReplyMsg
|
||||||
|
om.nameToEmu["OP_WhoQueryRequestMsg"] = OP_WhoQueryRequestMsg
|
||||||
|
om.nameToEmu["OP_WorldDataChangeMsg"] = OP_WorldDataChangeMsg
|
||||||
|
om.nameToEmu["OP_WorldDataUpdateMsg"] = OP_WorldDataUpdateMsg
|
||||||
|
om.nameToEmu["OP_WorldPingMsg"] = OP_WorldPingMsg
|
||||||
|
om.nameToEmu["OP_WorldShutdownUpdateMsg"] = OP_WorldShutdownUpdateMsg
|
||||||
|
om.nameToEmu["OP_ZoneBgInstanceList"] = OP_ZoneBgInstanceList
|
||||||
|
om.nameToEmu["OP_ZoneChangeMsg"] = OP_ZoneChangeMsg
|
||||||
|
om.nameToEmu["OP_ZoneEntryMsg"] = OP_ZoneEntryMsg
|
||||||
|
om.nameToEmu["OP_ZoneExitMsg"] = OP_ZoneExitMsg
|
||||||
|
om.nameToEmu["OP_ZoneInfoMsg"] = OP_ZoneInfoMsg
|
||||||
|
om.nameToEmu["OP_ZoneInstanceCreateReplyMsg"] = OP_ZoneInstanceCreateReplyMsg
|
||||||
|
om.nameToEmu["OP_ZoneInstanceDestroyedMsg"] = OP_ZoneInstanceDestroyedMsg
|
||||||
|
om.nameToEmu["OP_ZoneListMsg"] = OP_ZoneListMsg
|
||||||
|
om.nameToEmu["OP_ZoneMOTDMsg"] = OP_ZoneMOTDMsg
|
||||||
|
om.nameToEmu["OP_ZonePointsMsg"] = OP_ZonePointsMsg
|
||||||
|
om.nameToEmu["OP_ZoneToFriendReplyMsg"] = OP_ZoneToFriendReplyMsg
|
||||||
|
om.nameToEmu["OP_ZoneToFriendRequestMsg"] = OP_ZoneToFriendRequestMsg
|
||||||
|
om.nameToEmu["OP_ZoneUnavailMsg"] = OP_ZoneUnavailMsg
|
||||||
|
om.nameToEmu["OP_ZonesStatusMsg"] = OP_ZonesStatusMsg
|
||||||
|
om.nameToEmu["OP_ZonesStatusRequestMsg"] = OP_ZonesStatusRequestMsg
|
||||||
|
}
|
70
opcodes/login.go
Normal file
70
opcodes/login.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package opcodes
|
||||||
|
|
||||||
|
// Login server opcodes
|
||||||
|
const (
|
||||||
|
LS_LoginRequestMsg EmuOpcode = 0x0000
|
||||||
|
LS_LoginReplyMsg EmuOpcode = 0x0001
|
||||||
|
LS_WorldListMsg EmuOpcode = 0x0002
|
||||||
|
LS_WorldStatusMsg EmuOpcode = 0x0003
|
||||||
|
LS_AccessGrantedMsg EmuOpcode = 0x0004
|
||||||
|
LS_SessionReadyMsg EmuOpcode = 0x0005
|
||||||
|
LS_LoginFailedMsg EmuOpcode = 0x0006
|
||||||
|
LS_LoginBannedMsg EmuOpcode = 0x0007
|
||||||
|
LS_PlayCharRequestMsg EmuOpcode = 0x0008
|
||||||
|
LS_PlayCharReplyMsg EmuOpcode = 0x0009
|
||||||
|
LS_CreateCharRequestMsg EmuOpcode = 0x000a
|
||||||
|
LS_CreateCharReplyMsg EmuOpcode = 0x000b
|
||||||
|
LS_DeleteCharRequestMsg EmuOpcode = 0x000c
|
||||||
|
LS_DeleteCharReplyMsg EmuOpcode = 0x000d
|
||||||
|
LS_CharSelectMsg EmuOpcode = 0x000e
|
||||||
|
LS_CharListRequestMsg EmuOpcode = 0x000f
|
||||||
|
LS_CharListReplyMsg EmuOpcode = 0x0010
|
||||||
|
LS_ServerListRequestMsg EmuOpcode = 0x0011
|
||||||
|
LS_ServerListReplyMsg EmuOpcode = 0x0012
|
||||||
|
LS_ServerStatusRequestMsg EmuOpcode = 0x0013
|
||||||
|
LS_ServerStatusReplyMsg EmuOpcode = 0x0014
|
||||||
|
LS_LSStatusRequestMsg EmuOpcode = 0x0015
|
||||||
|
LS_LSStatusReplyMsg EmuOpcode = 0x0016
|
||||||
|
LS_UsertoWorldReq EmuOpcode = 0x0017
|
||||||
|
LS_UsertoWorldResp EmuOpcode = 0x0018
|
||||||
|
LS_AllWorldsDescRequestMsg EmuOpcode = 0x0019
|
||||||
|
LS_AllWorldsDescReplyMsg EmuOpcode = 0x001a
|
||||||
|
LS_CreateAccountRequestMsg EmuOpcode = 0x001b
|
||||||
|
LS_CreateAccountReplyMsg EmuOpcode = 0x001c
|
||||||
|
LS_LoginByNumRequestMsg EmuOpcode = 0x001d
|
||||||
|
LS_WSLoginRequestMsg EmuOpcode = 0x001e
|
||||||
|
LS_ESLoginRequestMsg EmuOpcode = 0x001f
|
||||||
|
LS_WorldStatusChangeMsg EmuOpcode = 0x0020
|
||||||
|
LS_AllWSDescRequestMsg EmuOpcode = 0x0021
|
||||||
|
LS_WSStatusReplyMsg EmuOpcode = 0x0022
|
||||||
|
LS_AllCharactersDescRequestMsg EmuOpcode = 0x0023
|
||||||
|
LS_AllCharactersDescReplyMsg EmuOpcode = 0x0024
|
||||||
|
LS_CreateCharacterRequestMsg EmuOpcode = 0x0025
|
||||||
|
LS_CreateCharacterReplyMsg EmuOpcode = 0x0026
|
||||||
|
LS_ReskinCharacterRequestMsg EmuOpcode = 0x0027
|
||||||
|
LS_WSCreateCharacterRequestMsg EmuOpcode = 0x0028
|
||||||
|
LS_WSCreateCharacterReplyMsg EmuOpcode = 0x0029
|
||||||
|
LS_DeleteCharacterRequestMsg EmuOpcode = 0x002a
|
||||||
|
LS_DeleteCharacterReplyMsg EmuOpcode = 0x002b
|
||||||
|
LS_PlayCharacterRequestMsg EmuOpcode = 0x002c
|
||||||
|
LS_PlayCharacterReplyMsg EmuOpcode = 0x002d
|
||||||
|
LS_ServerPlayCharacterRequestMsg EmuOpcode = 0x002e
|
||||||
|
LS_ServerPlayCharacterReplyMsg EmuOpcode = 0x002f
|
||||||
|
LS_KeymapLoadMsg EmuOpcode = 0x0030
|
||||||
|
LS_KeymapNoneMsg EmuOpcode = 0x0031
|
||||||
|
LS_KeymapDataMsg EmuOpcode = 0x0032
|
||||||
|
LS_KeymapSaveMsg EmuOpcode = 0x0033
|
||||||
|
LS_LSCheckAcctLockMsg EmuOpcode = 0x0034
|
||||||
|
LS_WSAcctLockStatusMsg EmuOpcode = 0x0035
|
||||||
|
LS_LsRequestClientCrashLogMsg EmuOpcode = 0x0036
|
||||||
|
LS_LsClientBaselogReplyMsg EmuOpcode = 0x0037
|
||||||
|
LS_LsClientCrashlogReplyMsg EmuOpcode = 0x0038
|
||||||
|
LS_LsClientAlertlogReplyMsg EmuOpcode = 0x0039
|
||||||
|
LS_LsClientVerifylogReplyMsg EmuOpcode = 0x003a
|
||||||
|
LS_BadLanguageFilter EmuOpcode = 0x003b
|
||||||
|
LS_WSServerLockMsg EmuOpcode = 0x003c
|
||||||
|
LS_WSServerHideMsg EmuOpcode = 0x003d
|
||||||
|
LS_LSServerLockMsg EmuOpcode = 0x003e
|
||||||
|
LS_UpdateCharacterSheetMsg EmuOpcode = 0x003f
|
||||||
|
LS_UpdateInventoryMsg EmuOpcode = 0x0040
|
||||||
|
)
|
257
opcodes/manager.go
Normal file
257
opcodes/manager.go
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
package opcodes
|
||||||
|
|
||||||
|
//go:generate go run gen/main.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OpcodeManager manages opcode translations for a specific client version
|
||||||
|
type OpcodeManager struct {
|
||||||
|
version int16
|
||||||
|
emuToEQ map[EmuOpcode]uint16
|
||||||
|
eqToEmu map[uint16]EmuOpcode
|
||||||
|
emuToName map[EmuOpcode]string
|
||||||
|
eqToName map[uint16]string
|
||||||
|
nameToEmu map[string]EmuOpcode
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOpcodeManager creates a new opcode manager for the specified version
|
||||||
|
func NewOpcodeManager(version int16) *OpcodeManager {
|
||||||
|
om := &OpcodeManager{
|
||||||
|
version: version,
|
||||||
|
emuToEQ: make(map[EmuOpcode]uint16),
|
||||||
|
eqToEmu: make(map[uint16]EmuOpcode),
|
||||||
|
emuToName: make(map[EmuOpcode]string),
|
||||||
|
eqToName: make(map[uint16]string),
|
||||||
|
nameToEmu: make(map[string]EmuOpcode),
|
||||||
|
}
|
||||||
|
om.initializeNameMappings() // Generated by go:generate
|
||||||
|
return om
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadFromDatabase loads opcode mappings from database
|
||||||
|
func (om *OpcodeManager) LoadFromDatabase(db *sql.DB, tableName string) error {
|
||||||
|
query := `
|
||||||
|
SELECT name, opcode
|
||||||
|
FROM ` + tableName + `
|
||||||
|
WHERE ? >= version_range1
|
||||||
|
AND (version_range2 = 0 OR ? <= version_range2)
|
||||||
|
ORDER BY version_range1 DESC, version_range2 DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := db.Query(query, om.version, om.version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
om.mu.Lock()
|
||||||
|
defer om.mu.Unlock()
|
||||||
|
|
||||||
|
loaded := make(map[string]bool)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var name string
|
||||||
|
var opcode int16
|
||||||
|
|
||||||
|
if err := rows.Scan(&name, &opcode); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if loaded[name] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
loaded[name] = true
|
||||||
|
|
||||||
|
eqOpcode := uint16(opcode)
|
||||||
|
|
||||||
|
// Only map if we have a constant for this opcode name
|
||||||
|
if emuOp, ok := om.nameToEmu[name]; ok {
|
||||||
|
om.emuToEQ[emuOp] = eqOpcode
|
||||||
|
om.eqToEmu[eqOpcode] = emuOp
|
||||||
|
om.emuToName[emuOp] = name
|
||||||
|
om.eqToName[eqOpcode] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map missing opcodes to 0xFFFF
|
||||||
|
for name, emuOp := range om.nameToEmu {
|
||||||
|
if _, ok := om.emuToEQ[emuOp]; !ok {
|
||||||
|
om.emuToEQ[emuOp] = 0xFFFF
|
||||||
|
om.emuToName[emuOp] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmuToEQ converts emulator opcode to EQ opcode
|
||||||
|
func (om *OpcodeManager) EmuToEQ(emu EmuOpcode) uint16 {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
if eq, ok := om.emuToEQ[emu]; ok {
|
||||||
|
return eq
|
||||||
|
}
|
||||||
|
return 0xFFFF
|
||||||
|
}
|
||||||
|
|
||||||
|
// EQToEmu converts EQ opcode to emulator opcode
|
||||||
|
func (om *OpcodeManager) EQToEmu(eq uint16) EmuOpcode {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
if emu, ok := om.eqToEmu[eq]; ok {
|
||||||
|
return emu
|
||||||
|
}
|
||||||
|
return OP_Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmuToName returns the name of an emulator opcode
|
||||||
|
func (om *OpcodeManager) EmuToName(emu EmuOpcode) string {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
if name, ok := om.emuToName[emu]; ok {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return "OP_Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// EQToName returns the name of an EQ opcode
|
||||||
|
func (om *OpcodeManager) EQToName(eq uint16) string {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
if name, ok := om.eqToName[eq]; ok {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return "OP_Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMissingOpcodes returns list of opcodes that map to 0xFFFF
|
||||||
|
func (om *OpcodeManager) GetMissingOpcodes() []string {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
var missing []string
|
||||||
|
for emu, eq := range om.emuToEQ {
|
||||||
|
if eq == 0xFFFF {
|
||||||
|
if name, ok := om.emuToName[emu]; ok {
|
||||||
|
missing = append(missing, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return missing
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidOpcode checks if an EQ opcode is valid/known
|
||||||
|
func (om *OpcodeManager) IsValidOpcode(eq uint16) bool {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
_, exists := om.eqToEmu[eq]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpOpcodes returns a formatted string of all loaded opcodes for debugging
|
||||||
|
func (om *OpcodeManager) DumpOpcodes() string {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(fmt.Sprintf("Opcode Manager for version %d:\n", om.version))
|
||||||
|
sb.WriteString("=====================================\n")
|
||||||
|
|
||||||
|
var eqOpcodes []uint16
|
||||||
|
for eq := range om.eqToEmu {
|
||||||
|
eqOpcodes = append(eqOpcodes, eq)
|
||||||
|
}
|
||||||
|
sort.Slice(eqOpcodes, func(i, j int) bool {
|
||||||
|
return eqOpcodes[i] < eqOpcodes[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, eq := range eqOpcodes {
|
||||||
|
emu := om.eqToEmu[eq]
|
||||||
|
name := om.eqToName[eq]
|
||||||
|
sb.WriteString(fmt.Sprintf("0x%04x -> 0x%04x : %s\n", eq, emu, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats returns statistics about loaded opcodes
|
||||||
|
func (om *OpcodeManager) GetStats() map[string]int {
|
||||||
|
om.mu.RLock()
|
||||||
|
defer om.mu.RUnlock()
|
||||||
|
|
||||||
|
return map[string]int{
|
||||||
|
"version": int(om.version),
|
||||||
|
"total_opcodes": len(om.eqToEmu),
|
||||||
|
"named_opcodes": len(om.emuToName),
|
||||||
|
"mapped_opcodes": len(om.emuToEQ),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global managers cache
|
||||||
|
var (
|
||||||
|
managers = make(map[int16]*OpcodeManager)
|
||||||
|
managersMu sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetManager returns opcode manager for a version
|
||||||
|
func GetManager(version int16, db *sql.DB, tableName string) *OpcodeManager {
|
||||||
|
managersMu.RLock()
|
||||||
|
if mgr, ok := managers[version]; ok {
|
||||||
|
managersMu.RUnlock()
|
||||||
|
return mgr
|
||||||
|
}
|
||||||
|
managersMu.RUnlock()
|
||||||
|
|
||||||
|
managersMu.Lock()
|
||||||
|
defer managersMu.Unlock()
|
||||||
|
|
||||||
|
if mgr, ok := managers[version]; ok {
|
||||||
|
return mgr
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr := NewOpcodeManager(version)
|
||||||
|
if db != nil {
|
||||||
|
if err := mgr.LoadFromDatabase(db, tableName); err != nil {
|
||||||
|
fmt.Printf("Warning: Failed to load opcodes for version %d: %v\n", version, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
managers[version] = mgr
|
||||||
|
return mgr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearCache clears the cached managers (useful for testing)
|
||||||
|
func ClearCache() {
|
||||||
|
managersMu.Lock()
|
||||||
|
defer managersMu.Unlock()
|
||||||
|
managers = make(map[int16]*OpcodeManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLoadedVersions returns all versions that have managers loaded
|
||||||
|
func GetLoadedVersions() []int16 {
|
||||||
|
managersMu.RLock()
|
||||||
|
defer managersMu.RUnlock()
|
||||||
|
|
||||||
|
var versions []int16
|
||||||
|
for v := range managers {
|
||||||
|
versions = append(versions, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(versions, func(i, j int) bool {
|
||||||
|
return versions[i] < versions[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
return versions
|
||||||
|
}
|
18
opcodes/protocol.go
Normal file
18
opcodes/protocol.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package opcodes
|
||||||
|
|
||||||
|
// Protocol-level opcodes used by the network layer
|
||||||
|
const (
|
||||||
|
OP_SessionRequest uint16 = 0x0001
|
||||||
|
OP_SessionResponse uint16 = 0x0002
|
||||||
|
OP_Combined uint16 = 0x0003
|
||||||
|
OP_SessionDisconnect uint16 = 0x0005
|
||||||
|
OP_KeepAlive uint16 = 0x0006
|
||||||
|
OP_SessionStatRequest uint16 = 0x0007
|
||||||
|
OP_SessionStatResponse uint16 = 0x0008
|
||||||
|
OP_Packet uint16 = 0x0009
|
||||||
|
OP_Fragment uint16 = 0x000d
|
||||||
|
OP_Ack uint16 = 0x0015
|
||||||
|
OP_AppCombined uint16 = 0x0019
|
||||||
|
OP_OutOfOrderAck uint16 = 0x001d
|
||||||
|
OP_OutOfSession uint16 = 0x001e
|
||||||
|
)
|
12
opcodes/types.go
Normal file
12
opcodes/types.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package opcodes
|
||||||
|
|
||||||
|
// EmuOpcode represents an emulator opcode
|
||||||
|
type EmuOpcode uint16
|
||||||
|
|
||||||
|
// Manager handles opcode translation between emulator and EQ2 formats
|
||||||
|
type Manager interface {
|
||||||
|
EmuToEQ(emu EmuOpcode) uint16
|
||||||
|
EQToEmu(eq uint16) EmuOpcode
|
||||||
|
EmuToName(emu EmuOpcode) string
|
||||||
|
EQToName(eq uint16) string
|
||||||
|
}
|
208
packets/apppacket.go
Normal file
208
packets/apppacket.go
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
package packets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"git.sharkk.net/EQ2/Protocol/opcodes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultOpcodeSize is the default opcode size for application packets
|
||||||
|
var DefaultOpcodeSize uint8 = 2
|
||||||
|
|
||||||
|
// AppPacket handles high-level game opcodes (matches EQApplicationPacket)
|
||||||
|
type AppPacket struct {
|
||||||
|
*Packet
|
||||||
|
|
||||||
|
emuOpcode opcodes.EmuOpcode // Cached emulator opcode
|
||||||
|
opcodeSize uint8 // Size of opcode in bytes (1 or 2)
|
||||||
|
manager opcodes.Manager // Opcode manager for translation
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppPacket creates a new application packet
|
||||||
|
func NewAppPacket(manager opcodes.Manager) *AppPacket {
|
||||||
|
return &AppPacket{
|
||||||
|
Packet: NewPacket(0, nil),
|
||||||
|
emuOpcode: opcodes.OP_Unknown,
|
||||||
|
opcodeSize: DefaultOpcodeSize,
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppPacketWithOp creates with opcode
|
||||||
|
func NewAppPacketWithOp(op opcodes.EmuOpcode, manager opcodes.Manager) *AppPacket {
|
||||||
|
app := &AppPacket{
|
||||||
|
Packet: NewPacket(0, nil),
|
||||||
|
opcodeSize: DefaultOpcodeSize,
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
app.SetOpcode(op)
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppPacketWithSize creates with opcode and size
|
||||||
|
func NewAppPacketWithSize(op opcodes.EmuOpcode, size uint32, manager opcodes.Manager) *AppPacket {
|
||||||
|
app := &AppPacket{
|
||||||
|
Packet: NewPacket(0, make([]byte, size)),
|
||||||
|
opcodeSize: DefaultOpcodeSize,
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
app.SetOpcode(op)
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppPacketWithData creates with opcode and data
|
||||||
|
func NewAppPacketWithData(op opcodes.EmuOpcode, data []byte, manager opcodes.Manager) *AppPacket {
|
||||||
|
app := &AppPacket{
|
||||||
|
Packet: NewPacket(0, data),
|
||||||
|
opcodeSize: DefaultOpcodeSize,
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
app.SetOpcode(op)
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppPacketFromRaw creates from raw buffer (matches EQApplicationPacket constructor)
|
||||||
|
func NewAppPacketFromRaw(buf []byte, opcodeSize uint8, manager opcodes.Manager) *AppPacket {
|
||||||
|
if opcodeSize == 0 {
|
||||||
|
opcodeSize = DefaultOpcodeSize
|
||||||
|
}
|
||||||
|
|
||||||
|
app := &AppPacket{
|
||||||
|
Packet: NewPacket(0, nil),
|
||||||
|
opcodeSize: opcodeSize,
|
||||||
|
manager: manager,
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := 0
|
||||||
|
|
||||||
|
// Extract opcode based on size
|
||||||
|
if opcodeSize == 1 && len(buf) >= 1 {
|
||||||
|
app.Opcode = uint16(buf[0])
|
||||||
|
offset = 1
|
||||||
|
} else if len(buf) >= 2 {
|
||||||
|
app.Opcode = binary.BigEndian.Uint16(buf[:2])
|
||||||
|
offset = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy remaining data as payload
|
||||||
|
if len(buf) > offset {
|
||||||
|
app.Buffer = make([]byte, len(buf)-offset)
|
||||||
|
copy(app.Buffer, buf[offset:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert EQ opcode to emulator opcode
|
||||||
|
if app.manager != nil {
|
||||||
|
app.emuOpcode = app.manager.EQToEmu(app.Opcode)
|
||||||
|
} else {
|
||||||
|
app.emuOpcode = opcodes.EmuOpcode(app.Opcode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns total packet size including opcode
|
||||||
|
func (a *AppPacket) Size() uint32 {
|
||||||
|
// Handle special encoding where low byte = 0x00 needs extra byte
|
||||||
|
extraBytes := uint32(0)
|
||||||
|
if a.opcodeSize == 2 && (a.Opcode&0x00ff) == 0 {
|
||||||
|
extraBytes = 1
|
||||||
|
}
|
||||||
|
return uint32(len(a.Buffer)) + uint32(a.opcodeSize) + extraBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOpcode sets the emulator opcode and translates to EQ opcode
|
||||||
|
func (a *AppPacket) SetOpcode(op opcodes.EmuOpcode) {
|
||||||
|
a.emuOpcode = op
|
||||||
|
if a.manager != nil {
|
||||||
|
a.Opcode = a.manager.EmuToEQ(op)
|
||||||
|
} else {
|
||||||
|
a.Opcode = uint16(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOpcode returns the emulator opcode
|
||||||
|
func (a *AppPacket) GetOpcode() opcodes.EmuOpcode {
|
||||||
|
if a.emuOpcode == opcodes.OP_Unknown && a.manager != nil {
|
||||||
|
a.emuOpcode = a.manager.EQToEmu(a.Opcode)
|
||||||
|
}
|
||||||
|
return a.emuOpcode
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOpcodeName returns the name of the current opcode
|
||||||
|
func (a *AppPacket) GetOpcodeName() string {
|
||||||
|
if a.manager != nil {
|
||||||
|
return a.manager.EmuToName(a.GetOpcode())
|
||||||
|
}
|
||||||
|
return "OP_Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetManager sets the opcode manager
|
||||||
|
func (a *AppPacket) SetManager(manager opcodes.Manager) {
|
||||||
|
a.manager = manager
|
||||||
|
// Re-translate if we have an opcode
|
||||||
|
if a.emuOpcode != opcodes.OP_Unknown && a.manager != nil {
|
||||||
|
a.Opcode = a.manager.EmuToEQ(a.emuOpcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize writes to destination (matches EQApplicationPacket::serialize)
|
||||||
|
func (a *AppPacket) Serialize(dest []byte) uint32 {
|
||||||
|
opcodeBytes := a.opcodeSize
|
||||||
|
pos := 0
|
||||||
|
|
||||||
|
if a.opcodeSize == 1 {
|
||||||
|
// Single-byte opcode
|
||||||
|
dest[pos] = byte(a.Opcode)
|
||||||
|
pos++
|
||||||
|
} else {
|
||||||
|
// Two-byte opcode with special encoding rules
|
||||||
|
// Application opcodes with low byte = 0x00 need extra 0x00 prefix
|
||||||
|
if (a.Opcode & 0x00ff) == 0 {
|
||||||
|
dest[pos] = 0
|
||||||
|
pos++
|
||||||
|
binary.BigEndian.PutUint16(dest[pos:], a.Opcode)
|
||||||
|
pos += 2
|
||||||
|
opcodeBytes++
|
||||||
|
} else {
|
||||||
|
binary.BigEndian.PutUint16(dest[pos:], a.Opcode)
|
||||||
|
pos += 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy packet data after opcode
|
||||||
|
copy(dest[pos:], a.Buffer)
|
||||||
|
|
||||||
|
return uint32(len(a.Buffer)) + uint32(opcodeBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine combines with another app packet (matches EQApplicationPacket::combine)
|
||||||
|
func (a *AppPacket) Combine(rhs *AppPacket) bool {
|
||||||
|
// Application packet combining is not implemented in original
|
||||||
|
// Use protocol-level combining instead
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a deep copy
|
||||||
|
func (a *AppPacket) Copy() *AppPacket {
|
||||||
|
newApp := &AppPacket{
|
||||||
|
Packet: NewPacket(a.Opcode, a.Buffer),
|
||||||
|
emuOpcode: a.emuOpcode,
|
||||||
|
opcodeSize: a.opcodeSize,
|
||||||
|
manager: a.manager,
|
||||||
|
}
|
||||||
|
newApp.Packet.CopyInfo(a.Packet)
|
||||||
|
return newApp
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToProto converts to protocol packet
|
||||||
|
func (a *AppPacket) ToProto() *ProtoPacket {
|
||||||
|
// Serialize the application packet
|
||||||
|
tmpBuf := make([]byte, a.Size())
|
||||||
|
a.Serialize(tmpBuf)
|
||||||
|
|
||||||
|
proto := NewProtoPacket(opcodes.OP_Packet, tmpBuf, a.manager)
|
||||||
|
proto.LoginOp = a.emuOpcode
|
||||||
|
proto.CopyInfo(a.Packet)
|
||||||
|
|
||||||
|
return proto
|
||||||
|
}
|
347
packets/helpers.go
Normal file
347
packets/helpers.go
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
package packets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/zlib"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.sharkk.net/EQ2/Protocol/crypto"
|
||||||
|
"git.sharkk.net/EQ2/Protocol/opcodes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateCRC validates packet CRC using EQ2's custom CRC16 (matches C++ EQProtocolPacket::ValidateCRC)
|
||||||
|
func ValidateCRC(buffer []byte, key uint32) bool {
|
||||||
|
if len(buffer) < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Session packets are not CRC protected
|
||||||
|
if len(buffer) >= 2 && buffer[0] == 0x00 &&
|
||||||
|
(buffer[1] == byte(opcodes.OP_SessionRequest) ||
|
||||||
|
buffer[1] == byte(opcodes.OP_SessionResponse) ||
|
||||||
|
buffer[1] == byte(opcodes.OP_OutOfSession)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combined application packets are also exempt (OP_AppCombined = 0x0019)
|
||||||
|
if len(buffer) >= 4 && buffer[2] == 0x00 && buffer[3] == 0x19 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other packets must have valid CRC
|
||||||
|
// Extract CRC from last 2 bytes (network byte order)
|
||||||
|
packetCRC := binary.BigEndian.Uint16(buffer[len(buffer)-2:])
|
||||||
|
|
||||||
|
// Calculate CRC on data portion (excluding CRC bytes)
|
||||||
|
data := buffer[:len(buffer)-2]
|
||||||
|
calculatedCRC := crypto.CalculateCRC(data, key)
|
||||||
|
|
||||||
|
// Valid if no CRC present (packetCRC == 0) or CRCs match
|
||||||
|
return packetCRC == 0 || calculatedCRC == packetCRC
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendCRC appends CRC16 to packet buffer using EQ2's custom CRC
|
||||||
|
func AppendCRC(buffer []byte, key uint32) []byte {
|
||||||
|
crc := crypto.CalculateCRC(buffer, key)
|
||||||
|
result := make([]byte, len(buffer)+2)
|
||||||
|
copy(result, buffer)
|
||||||
|
binary.BigEndian.PutUint16(result[len(buffer):], crc)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// StripCRC removes CRC16 from packet buffer
|
||||||
|
func StripCRC(buffer []byte) []byte {
|
||||||
|
if len(buffer) < 2 {
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
return buffer[:len(buffer)-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress compresses packet data using zlib or simple encoding (matches C++ EQProtocolPacket::Compress)
|
||||||
|
// Uses zlib for packets > 30 bytes, simple encoding for smaller packets
|
||||||
|
func Compress(src []byte) ([]byte, error) {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return src, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// C++ uses 30 bytes as threshold between simple encoding and zlib
|
||||||
|
if len(src) > 30 {
|
||||||
|
// Use zlib compression for larger packets
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
// Write uncompressed length first (4 bytes) - EQ protocol requirement
|
||||||
|
if err := binary.Write(&buf, binary.BigEndian, uint32(len(src))); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress the data
|
||||||
|
w := zlib.NewWriter(&buf)
|
||||||
|
if _, err := w.Write(src); err != nil {
|
||||||
|
w.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use simple encoding for smaller packets (just return data as-is)
|
||||||
|
// The 0xa5 flag is added by the caller, not here
|
||||||
|
return src, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompress decompresses packet data using zlib
|
||||||
|
// This is called after the compression flag has already been checked and removed
|
||||||
|
func Decompress(src []byte) ([]byte, error) {
|
||||||
|
if len(src) < 4 {
|
||||||
|
return nil, fmt.Errorf("compressed data too small")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read uncompressed length (first 4 bytes)
|
||||||
|
uncompressedLen := binary.BigEndian.Uint32(src[:4])
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if uncompressedLen > MaxPacketSize {
|
||||||
|
return nil, fmt.Errorf("uncompressed size %d exceeds max packet size", uncompressedLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create reader for compressed data (skip length prefix)
|
||||||
|
r, err := zlib.NewReader(bytes.NewReader(src[4:]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
// Read decompressed data
|
||||||
|
decompressed := make([]byte, uncompressedLen)
|
||||||
|
if _, err := io.ReadFull(r, decompressed); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decompressed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompressPacket adds compression with proper flag handling (matches C++ EQProtocolPacket::Compress)
|
||||||
|
// Uses zlib (0x5a) for packets > 30 bytes, simple encoding (0xa5) for smaller packets
|
||||||
|
func CompressPacket(buffer []byte) ([]byte, error) {
|
||||||
|
if len(buffer) < 2 {
|
||||||
|
return buffer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine flag offset based on opcode size
|
||||||
|
flagOffset := 1
|
||||||
|
if buffer[0] == 0x00 {
|
||||||
|
flagOffset = 2 // Two-byte opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(buffer) <= flagOffset {
|
||||||
|
return buffer, nil // Too small to compress
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get data to compress (after opcode)
|
||||||
|
dataToCompress := buffer[flagOffset:]
|
||||||
|
|
||||||
|
// Choose compression method based on size (C++ uses 30 byte threshold)
|
||||||
|
if len(dataToCompress) > 30 {
|
||||||
|
// Use zlib compression
|
||||||
|
compressed, err := Compress(dataToCompress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use if compression actually reduced size
|
||||||
|
if len(compressed) < len(dataToCompress) {
|
||||||
|
result := make([]byte, flagOffset+1+len(compressed))
|
||||||
|
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||||
|
result[flagOffset] = 0x5a // Zlib flag
|
||||||
|
copy(result[flagOffset+1:], compressed) // Compressed data
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Use simple encoding - just add flag
|
||||||
|
result := make([]byte, len(buffer)+1)
|
||||||
|
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||||
|
result[flagOffset] = 0xa5 // Simple encoding flag
|
||||||
|
copy(result[flagOffset+1:], dataToCompress) // Original data
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No compression if it doesn't help
|
||||||
|
return buffer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecompressPacket handles decompression with flag checking (matches C++ EQProtocolPacket::Decompress)
|
||||||
|
// Supports both zlib compression (0x5a) and simple encoding (0xa5)
|
||||||
|
func DecompressPacket(buffer []byte) ([]byte, error) {
|
||||||
|
if len(buffer) < 3 {
|
||||||
|
return buffer, nil // Too small to be compressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine flag offset based on opcode size
|
||||||
|
flagOffset := uint32(1)
|
||||||
|
if buffer[0] == 0x00 {
|
||||||
|
flagOffset = 2 // Two-byte opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint32(len(buffer)) <= flagOffset {
|
||||||
|
return buffer, nil // No room for compression flag
|
||||||
|
}
|
||||||
|
|
||||||
|
compressionFlag := buffer[flagOffset]
|
||||||
|
|
||||||
|
// Check compression type
|
||||||
|
if compressionFlag == 0x5a {
|
||||||
|
// Zlib compression
|
||||||
|
// Decompress data after flag, excluding last 2 CRC bytes
|
||||||
|
dataStart := flagOffset + 1
|
||||||
|
dataEnd := uint32(len(buffer)) - 2
|
||||||
|
if dataEnd <= dataStart {
|
||||||
|
return nil, fmt.Errorf("invalid compressed packet size")
|
||||||
|
}
|
||||||
|
|
||||||
|
decompressed, err := Decompress(buffer[dataStart:dataEnd])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("zlib decompression failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild packet: opcode + decompressed data + CRC
|
||||||
|
result := make([]byte, flagOffset+uint32(len(decompressed))+2)
|
||||||
|
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||||
|
copy(result[flagOffset:], decompressed) // Copy decompressed data
|
||||||
|
// Copy CRC bytes
|
||||||
|
result[len(result)-2] = buffer[len(buffer)-2]
|
||||||
|
result[len(result)-1] = buffer[len(buffer)-1]
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
} else if compressionFlag == 0xa5 {
|
||||||
|
// Simple encoding - just remove the encoding flag
|
||||||
|
result := make([]byte, len(buffer)-1)
|
||||||
|
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||||
|
copy(result[flagOffset:], buffer[flagOffset+1:]) // Skip flag, copy rest
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No compression
|
||||||
|
return buffer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatEncode encodes chat data using EQ's XOR-based encoding (matches C++ EQProtocolPacket::ChatEncode)
|
||||||
|
// Uses 4-byte block XOR with rolling key that updates from encrypted data
|
||||||
|
func ChatEncode(buffer []byte, encodeKey int) {
|
||||||
|
if len(buffer) <= 2 || encodeKey == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip encoding for certain packet types (matches C++ conditions)
|
||||||
|
if buffer[1] == 0x01 || buffer[0] == 0x02 || buffer[0] == 0x1d {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip first 2 bytes (opcode)
|
||||||
|
data := buffer[2:]
|
||||||
|
size := len(data)
|
||||||
|
key := int32(encodeKey)
|
||||||
|
|
||||||
|
// Encode 4-byte blocks with rolling key
|
||||||
|
i := 0
|
||||||
|
for ; i+4 <= size; i += 4 {
|
||||||
|
// Read 4 bytes as int32 (little-endian like C++)
|
||||||
|
pt := binary.LittleEndian.Uint32(data[i:i+4])
|
||||||
|
encrypted := pt ^ uint32(key)
|
||||||
|
key = int32(encrypted) // Update key with encrypted data
|
||||||
|
binary.LittleEndian.PutUint32(data[i:i+4], encrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode remaining bytes with last key byte
|
||||||
|
keyByte := byte(key & 0xFF)
|
||||||
|
for ; i < size; i++ {
|
||||||
|
data[i] ^= keyByte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatDecode decodes chat data using EQ's XOR-based encoding (matches C++ EQProtocolPacket::ChatDecode)
|
||||||
|
// Uses 4-byte block XOR with rolling key that updates from encrypted data
|
||||||
|
func ChatDecode(buffer []byte, decodeKey int) {
|
||||||
|
if len(buffer) <= 2 || decodeKey == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip decoding for certain packet types (matches C++ conditions)
|
||||||
|
if buffer[1] == 0x01 || buffer[0] == 0x02 || buffer[0] == 0x1d {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip first 2 bytes (opcode)
|
||||||
|
data := buffer[2:]
|
||||||
|
size := len(data)
|
||||||
|
key := int32(decodeKey)
|
||||||
|
|
||||||
|
// Decode 4-byte blocks with rolling key
|
||||||
|
i := 0
|
||||||
|
for ; i+4 <= size; i += 4 {
|
||||||
|
// Read 4 bytes as int32 (little-endian like C++)
|
||||||
|
encrypted := binary.LittleEndian.Uint32(data[i:i+4])
|
||||||
|
decrypted := encrypted ^ uint32(key)
|
||||||
|
key = int32(encrypted) // Update key with encrypted data (before decryption)
|
||||||
|
binary.LittleEndian.PutUint32(data[i:i+4], decrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode remaining bytes with last key byte
|
||||||
|
keyByte := byte(key & 0xFF)
|
||||||
|
for ; i < size; i++ {
|
||||||
|
data[i] ^= keyByte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsChatPacket checks if opcode is a chat-related packet
|
||||||
|
func IsChatPacket(opcode uint16) bool {
|
||||||
|
chatOpcodes := map[uint16]bool{
|
||||||
|
0x0300: true, // OP_ChatMsg
|
||||||
|
0x0302: true, // OP_TellMsg
|
||||||
|
0x0307: true, // OP_ChatLeaveChannelMsg
|
||||||
|
0x0308: true, // OP_ChatTellChannelMsg
|
||||||
|
0x0309: true, // OP_ChatTellUserMsg
|
||||||
|
0x0e07: true, // OP_GuildsayMsg
|
||||||
|
}
|
||||||
|
return chatOpcodes[opcode]
|
||||||
|
}
|
||||||
|
|
||||||
|
// longToIP converts uint32 IP to string
|
||||||
|
func longToIP(ip uint32) string {
|
||||||
|
return fmt.Sprintf("%d.%d.%d.%d",
|
||||||
|
byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsProtocolPacket checks if buffer contains a valid protocol packet (matches C++ EQProtocolPacket::IsProtocolPacket)
|
||||||
|
func IsProtocolPacket(buffer []byte) bool {
|
||||||
|
if len(buffer) < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode := binary.BigEndian.Uint16(buffer[:2])
|
||||||
|
|
||||||
|
// Check against known protocol opcodes
|
||||||
|
switch opcode {
|
||||||
|
case opcodes.OP_SessionRequest,
|
||||||
|
opcodes.OP_SessionResponse,
|
||||||
|
opcodes.OP_Combined,
|
||||||
|
opcodes.OP_SessionDisconnect,
|
||||||
|
opcodes.OP_KeepAlive,
|
||||||
|
opcodes.OP_SessionStatRequest,
|
||||||
|
opcodes.OP_SessionStatResponse,
|
||||||
|
opcodes.OP_Packet,
|
||||||
|
opcodes.OP_Fragment,
|
||||||
|
opcodes.OP_Ack,
|
||||||
|
opcodes.OP_AppCombined,
|
||||||
|
opcodes.OP_OutOfOrderAck,
|
||||||
|
opcodes.OP_OutOfSession:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
89
packets/packet.go
Normal file
89
packets/packet.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package packets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Packet is the base struct for all EverQuest packet types
|
||||||
|
type Packet struct {
|
||||||
|
Buffer []byte
|
||||||
|
Opcode uint16
|
||||||
|
|
||||||
|
SrcIP uint32
|
||||||
|
DstIP uint32
|
||||||
|
SrcPort uint16
|
||||||
|
DstPort uint16
|
||||||
|
|
||||||
|
Priority uint32
|
||||||
|
Timestamp time.Time
|
||||||
|
Version int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPacket creates a new packet with the given opcode and data
|
||||||
|
func NewPacket(opcode uint16, data []byte) *Packet {
|
||||||
|
p := &Packet{
|
||||||
|
Opcode: opcode,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
}
|
||||||
|
if len(data) > 0 {
|
||||||
|
p.Buffer = make([]byte, len(data))
|
||||||
|
copy(p.Buffer, data)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the total packet size including opcode
|
||||||
|
func (p *Packet) Size() uint32 {
|
||||||
|
return uint32(len(p.Buffer)) + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawOpcode returns the raw opcode value
|
||||||
|
func (p *Packet) RawOpcode() uint16 {
|
||||||
|
return p.Opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSrcInfo sets source IP and port
|
||||||
|
func (p *Packet) SetSrcInfo(ip uint32, port uint16) {
|
||||||
|
p.SrcIP = ip
|
||||||
|
p.SrcPort = port
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDstInfo sets destination IP and port
|
||||||
|
func (p *Packet) SetDstInfo(ip uint32, port uint16) {
|
||||||
|
p.DstIP = ip
|
||||||
|
p.DstPort = port
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyInfo copies network and timing info from another packet
|
||||||
|
func (p *Packet) CopyInfo(other *Packet) {
|
||||||
|
p.SrcIP = other.SrcIP
|
||||||
|
p.SrcPort = other.SrcPort
|
||||||
|
p.DstIP = other.DstIP
|
||||||
|
p.DstPort = other.DstPort
|
||||||
|
p.Timestamp = other.Timestamp
|
||||||
|
p.Version = other.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpRaw writes packet contents to writer for debugging
|
||||||
|
func (p *Packet) DumpRaw(w io.Writer) {
|
||||||
|
p.DumpRawHeader(0xffff, w)
|
||||||
|
if len(p.Buffer) > 0 {
|
||||||
|
// TODO: Implement dump_message_column equivalent
|
||||||
|
fmt.Fprintf(w, "[Data: %d bytes]\n", len(p.Buffer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DumpRawHeader writes packet header info to writer
|
||||||
|
func (p *Packet) DumpRawHeader(seq uint16, w io.Writer) {
|
||||||
|
if p.SrcIP != 0 {
|
||||||
|
fmt.Fprintf(w, "[%s:%d->%s:%d] ",
|
||||||
|
longToIP(p.SrcIP), p.SrcPort,
|
||||||
|
longToIP(p.DstIP), p.DstPort)
|
||||||
|
}
|
||||||
|
if seq != 0xffff {
|
||||||
|
fmt.Fprintf(w, "[Seq=%d] ", seq)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "[OpCode 0x%04x Size=%d]\n", p.Opcode, len(p.Buffer))
|
||||||
|
}
|
561
packets/protopacket.go
Normal file
561
packets/protopacket.go
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
package packets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.sharkk.net/EQ2/Protocol/crypto"
|
||||||
|
"git.sharkk.net/EQ2/Protocol/opcodes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProtoPacket handles low-level protocol features (matches EQProtocolPacket/EQ2Packet)
|
||||||
|
type ProtoPacket struct {
|
||||||
|
*Packet
|
||||||
|
|
||||||
|
// Protocol state flags
|
||||||
|
eq2Compressed bool
|
||||||
|
packetPrepared bool
|
||||||
|
packetEncrypted bool
|
||||||
|
acked bool
|
||||||
|
|
||||||
|
// EQ2-specific
|
||||||
|
LoginOp opcodes.EmuOpcode
|
||||||
|
|
||||||
|
// Reliability and sequencing
|
||||||
|
Sequence int32
|
||||||
|
SentTime int32
|
||||||
|
AttemptCount int8
|
||||||
|
|
||||||
|
// Opcode manager for translation
|
||||||
|
manager opcodes.Manager
|
||||||
|
|
||||||
|
// Compression/encoding settings
|
||||||
|
CompressThreshold int
|
||||||
|
EncodeKey int
|
||||||
|
|
||||||
|
// Client version for protocol compatibility
|
||||||
|
clientVersion int16
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultCompressThreshold = 100
|
||||||
|
|
||||||
|
// NewProtoPacket creates a protocol packet with opcode and buffer
|
||||||
|
func NewProtoPacket(op uint16, buf []byte, manager opcodes.Manager) *ProtoPacket {
|
||||||
|
return &ProtoPacket{
|
||||||
|
Packet: NewPacket(op, buf),
|
||||||
|
manager: manager,
|
||||||
|
CompressThreshold: DefaultCompressThreshold,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEQ2Packet creates an EQ2 protocol packet (matches EQ2Packet constructor)
|
||||||
|
func NewEQ2Packet(loginOp opcodes.EmuOpcode, buf []byte, manager opcodes.Manager) *ProtoPacket {
|
||||||
|
return &ProtoPacket{
|
||||||
|
Packet: NewPacket(opcodes.OP_Packet, buf),
|
||||||
|
LoginOp: loginOp,
|
||||||
|
manager: manager,
|
||||||
|
CompressThreshold: DefaultCompressThreshold,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProtoPacketFromRaw creates from raw buffer (matches EQProtocolPacket constructor)
|
||||||
|
func NewProtoPacketFromRaw(buf []byte, opcodeOverride int, manager opcodes.Manager) *ProtoPacket {
|
||||||
|
var offset uint32
|
||||||
|
var opcode uint16
|
||||||
|
|
||||||
|
if opcodeOverride >= 0 {
|
||||||
|
opcode = uint16(opcodeOverride)
|
||||||
|
} else if len(buf) >= 2 {
|
||||||
|
opcode = binary.BigEndian.Uint16(buf[:2])
|
||||||
|
offset = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []byte
|
||||||
|
if uint32(len(buf)) > offset {
|
||||||
|
data = make([]byte, len(buf)-int(offset))
|
||||||
|
copy(data, buf[offset:])
|
||||||
|
}
|
||||||
|
|
||||||
|
pp := &ProtoPacket{
|
||||||
|
Packet: &Packet{
|
||||||
|
Opcode: opcode,
|
||||||
|
Buffer: data,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
},
|
||||||
|
manager: manager,
|
||||||
|
CompressThreshold: DefaultCompressThreshold,
|
||||||
|
}
|
||||||
|
|
||||||
|
if pp.manager != nil {
|
||||||
|
pp.LoginOp = pp.manager.EQToEmu(opcode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVersion sets the client version
|
||||||
|
func (p *ProtoPacket) SetVersion(version int16) {
|
||||||
|
p.clientVersion = version
|
||||||
|
p.Version = version
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSequence sets the packet sequence number
|
||||||
|
func (p *ProtoPacket) SetSequence(seq int32) {
|
||||||
|
p.Sequence = seq
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPrepared returns whether packet has been prepared
|
||||||
|
func (p *ProtoPacket) IsPrepared() bool {
|
||||||
|
return p.packetPrepared
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEncrypted returns whether packet is encrypted
|
||||||
|
func (p *ProtoPacket) IsEncrypted() bool {
|
||||||
|
return p.packetEncrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreparePacket prepares an EQ2 packet for transmission (matches EQ2Packet::PreparePacket)
|
||||||
|
func (p *ProtoPacket) PreparePacket(maxLen uint16) int8 {
|
||||||
|
if p.packetPrepared {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.manager == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
p.packetPrepared = true
|
||||||
|
|
||||||
|
// Convert emulator opcode to network opcode
|
||||||
|
loginOpcode := p.manager.EmuToEQ(p.LoginOp)
|
||||||
|
if loginOpcode == 0xcdcd { // Invalid opcode
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Compression is NOT done here in C++, it's done separately
|
||||||
|
// via EQ2_Compress after PreparePacket
|
||||||
|
|
||||||
|
// Calculate new size: sequence(2) + compressed_flag(1) + opcode + data
|
||||||
|
var offset int8
|
||||||
|
newSize := len(p.Buffer) + 2 + 1 // seq(2) + compress_flag(1)
|
||||||
|
oversized := false
|
||||||
|
|
||||||
|
// Handle different opcode sizes and formats
|
||||||
|
if loginOpcode != 2 { // Not OP_SessionResponse
|
||||||
|
newSize++ // for opcode type byte
|
||||||
|
if loginOpcode >= 255 {
|
||||||
|
newSize += 2 // oversized opcode needs extra 2 bytes
|
||||||
|
oversized = true
|
||||||
|
} else {
|
||||||
|
// Swap bytes for network order
|
||||||
|
loginOpcode = (loginOpcode>>8)&0xFF | (loginOpcode<<8)&0xFF00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build new buffer
|
||||||
|
newBuffer := make([]byte, newSize)
|
||||||
|
// Leave first 2 bytes for sequence (filled by SequencedPush)
|
||||||
|
ptr := 2
|
||||||
|
|
||||||
|
// Space for compress flag (will be 0 for uncompressed)
|
||||||
|
ptr++ // This is at position 2, will be overwritten if compressed
|
||||||
|
|
||||||
|
if loginOpcode != 2 {
|
||||||
|
if oversized {
|
||||||
|
newBuffer[ptr] = 0xff // Oversized marker
|
||||||
|
ptr++
|
||||||
|
}
|
||||||
|
// Write opcode as 2 bytes
|
||||||
|
binary.BigEndian.PutUint16(newBuffer[ptr:], loginOpcode)
|
||||||
|
ptr += 2
|
||||||
|
} else {
|
||||||
|
// OP_SessionResponse: just 1 byte
|
||||||
|
newBuffer[ptr] = byte(loginOpcode)
|
||||||
|
ptr++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy original packet data
|
||||||
|
copy(newBuffer[ptr:], p.Buffer)
|
||||||
|
|
||||||
|
// Replace buffer
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
offset = int8(newSize - len(p.Buffer) - 1)
|
||||||
|
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCompressed returns whether the packet is compressed
|
||||||
|
func (p *ProtoPacket) IsCompressed() bool {
|
||||||
|
return p.eq2Compressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// EQ2Compress compresses packet data (matches EQStream::EQ2_Compress and C++ EQProtocolPacket::Compress)
|
||||||
|
func (p *ProtoPacket) EQ2Compress(offset int8) int8 {
|
||||||
|
if offset <= 0 || int(offset) >= len(p.Buffer) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress data from offset onwards
|
||||||
|
dataToCompress := p.Buffer[offset:]
|
||||||
|
dataLen := len(dataToCompress)
|
||||||
|
|
||||||
|
// C++ uses 30 bytes as threshold - match this exactly
|
||||||
|
if dataLen > 30 {
|
||||||
|
// Use zlib compression for larger packets
|
||||||
|
compressed, err := Compress(dataToCompress)
|
||||||
|
if err != nil || len(compressed) >= dataLen {
|
||||||
|
return 0 // Compression failed or didn't reduce size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild buffer with zlib compression flag (0x5a)
|
||||||
|
newSize := int(offset) + len(compressed)
|
||||||
|
newBuffer := make([]byte, newSize)
|
||||||
|
|
||||||
|
// Copy header bytes before offset
|
||||||
|
copy(newBuffer[:offset], p.Buffer[:offset])
|
||||||
|
|
||||||
|
// Set zlib compression flag at offset-1
|
||||||
|
newBuffer[offset-1] = 0x5a
|
||||||
|
|
||||||
|
// Copy compressed data
|
||||||
|
copy(newBuffer[offset:], compressed)
|
||||||
|
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
p.eq2Compressed = true
|
||||||
|
|
||||||
|
return offset - 1 // Return compression flag position
|
||||||
|
} else {
|
||||||
|
// Use simple encoding for smaller packets (0xa5)
|
||||||
|
// Simple encoding just adds a flag, doesn't change data
|
||||||
|
newSize := len(p.Buffer) + 1
|
||||||
|
newBuffer := make([]byte, newSize)
|
||||||
|
|
||||||
|
// Copy header bytes before offset
|
||||||
|
copy(newBuffer[:offset], p.Buffer[:offset])
|
||||||
|
|
||||||
|
// Set simple encoding flag at offset-1
|
||||||
|
newBuffer[offset-1] = 0xa5
|
||||||
|
|
||||||
|
// Copy data after flag (shift by 1 byte)
|
||||||
|
copy(newBuffer[offset:], p.Buffer[offset-1:])
|
||||||
|
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
p.eq2Compressed = true
|
||||||
|
|
||||||
|
return offset - 1 // Return compression flag position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptPacket encrypts packet data (matches EQStream::EncryptPacket)
|
||||||
|
func (p *ProtoPacket) EncryptPacket(cipher *crypto.Ciphers, compressOffset int8, offset int8) {
|
||||||
|
if cipher == nil || !cipher.IsEncrypted() || len(p.Buffer) <= 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.packetEncrypted = true
|
||||||
|
|
||||||
|
if p.eq2Compressed && compressOffset > 0 {
|
||||||
|
// Encrypted compressed data from compress offset
|
||||||
|
if int(compressOffset) < len(p.Buffer) {
|
||||||
|
cipher.Encrypt(p.Buffer[compressOffset:])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Encrypt uncompressed data from 2 + offset
|
||||||
|
startPos := 2 + int(offset)
|
||||||
|
if startPos < len(p.Buffer) {
|
||||||
|
cipher.Encrypt(p.Buffer[startPos:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize writes the protocol packet to a destination buffer
|
||||||
|
func (p *ProtoPacket) Serialize(dest []byte, offset int8) uint32 {
|
||||||
|
pos := 0
|
||||||
|
|
||||||
|
// Write compression flag if compressed
|
||||||
|
if p.eq2Compressed {
|
||||||
|
dest[pos] = 0x5a
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write opcode (2 bytes)
|
||||||
|
binary.BigEndian.PutUint16(dest[pos:], p.Opcode)
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
// Copy packet data after opcode
|
||||||
|
if offset < int8(len(p.Buffer)) {
|
||||||
|
copy(dest[pos:], p.Buffer[offset:])
|
||||||
|
return uint32(len(p.Buffer)-int(offset)) + uint32(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine combines this protocol packet with another (matches EQProtocolPacket::combine)
|
||||||
|
func (p *ProtoPacket) Combine(rhs *ProtoPacket) bool {
|
||||||
|
const opCombined = 0x03 // OP_Combined
|
||||||
|
|
||||||
|
// Case 1: This packet is already combined - append to it
|
||||||
|
if p.Opcode == opCombined && p.Size()+rhs.Size()+3 < 256 {
|
||||||
|
newSize := len(p.Buffer) + int(rhs.Size()) + 1
|
||||||
|
newBuffer := make([]byte, newSize)
|
||||||
|
|
||||||
|
// Copy existing combined data
|
||||||
|
copy(newBuffer, p.Buffer)
|
||||||
|
offset := len(p.Buffer)
|
||||||
|
|
||||||
|
// Add size prefix for new packet
|
||||||
|
newBuffer[offset] = byte(rhs.Size())
|
||||||
|
offset++
|
||||||
|
|
||||||
|
// Serialize and append new packet
|
||||||
|
tmpBuf := make([]byte, rhs.Size())
|
||||||
|
rhs.Serialize(tmpBuf, 0)
|
||||||
|
copy(newBuffer[offset:], tmpBuf)
|
||||||
|
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: Neither packet is combined - create new combined packet
|
||||||
|
if p.Size()+rhs.Size()+4 < 256 {
|
||||||
|
totalSize := int(p.Size()) + int(rhs.Size()) + 2
|
||||||
|
newBuffer := make([]byte, totalSize)
|
||||||
|
offset := 0
|
||||||
|
|
||||||
|
// Add first packet with size prefix
|
||||||
|
newBuffer[offset] = byte(p.Size())
|
||||||
|
offset++
|
||||||
|
tmpBuf := make([]byte, p.Size())
|
||||||
|
p.Serialize(tmpBuf, 0)
|
||||||
|
copy(newBuffer[offset:], tmpBuf)
|
||||||
|
offset += int(p.Size())
|
||||||
|
|
||||||
|
// Add second packet with size prefix
|
||||||
|
newBuffer[offset] = byte(rhs.Size())
|
||||||
|
offset++
|
||||||
|
tmpBuf = make([]byte, rhs.Size())
|
||||||
|
rhs.Serialize(tmpBuf, 0)
|
||||||
|
copy(newBuffer[offset:], tmpBuf)
|
||||||
|
|
||||||
|
// Update buffer and mark as combined
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
p.Opcode = opCombined
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppCombine combines app-level packets (matches EQ2Packet::AppCombine)
|
||||||
|
func (p *ProtoPacket) AppCombine(rhs *ProtoPacket) bool {
|
||||||
|
const opAppCombined = 0x19 // OP_AppCombined
|
||||||
|
|
||||||
|
lhsSize := p.Size()
|
||||||
|
rhsSize := rhs.Size()
|
||||||
|
|
||||||
|
// Check max combined size
|
||||||
|
if lhsSize+rhsSize > MaxCombinedSize {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If already combined, add to it
|
||||||
|
if p.Opcode == opAppCombined {
|
||||||
|
tmpSize := rhsSize - 2 // Subtract opcode bytes
|
||||||
|
var newSize int
|
||||||
|
|
||||||
|
if tmpSize >= 255 {
|
||||||
|
newSize = len(p.Buffer) + int(tmpSize) + 3 // oversized header
|
||||||
|
} else {
|
||||||
|
newSize = len(p.Buffer) + int(tmpSize) + 1 // normal header
|
||||||
|
}
|
||||||
|
|
||||||
|
newBuffer := make([]byte, newSize)
|
||||||
|
copy(newBuffer, p.Buffer)
|
||||||
|
pos := len(p.Buffer)
|
||||||
|
|
||||||
|
// Add size header
|
||||||
|
if tmpSize >= 255 {
|
||||||
|
newBuffer[pos] = 255 // Oversized marker
|
||||||
|
pos++
|
||||||
|
binary.BigEndian.PutUint16(newBuffer[pos:], uint16(tmpSize))
|
||||||
|
pos += 2
|
||||||
|
} else {
|
||||||
|
newBuffer[pos] = byte(tmpSize)
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize rhs packet (skip first 2 bytes - opcode)
|
||||||
|
if len(rhs.Buffer) > 2 {
|
||||||
|
copy(newBuffer[pos:], rhs.Buffer[2:])
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new combined packet
|
||||||
|
lSize := lhsSize - 2
|
||||||
|
rSize := rhsSize - 2
|
||||||
|
totalSize := 0
|
||||||
|
|
||||||
|
if lSize >= 255 {
|
||||||
|
totalSize += 3 + int(lSize)
|
||||||
|
} else {
|
||||||
|
totalSize += 1 + int(lSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rSize >= 255 {
|
||||||
|
totalSize += 3 + int(rSize)
|
||||||
|
} else {
|
||||||
|
totalSize += 1 + int(rSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalSize > MaxCombinedSize {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
newBuffer := make([]byte, totalSize)
|
||||||
|
pos := 0
|
||||||
|
|
||||||
|
// Add first packet
|
||||||
|
if lSize >= 255 {
|
||||||
|
newBuffer[pos] = 255
|
||||||
|
pos++
|
||||||
|
binary.BigEndian.PutUint16(newBuffer[pos:], uint16(lSize))
|
||||||
|
pos += 2
|
||||||
|
} else {
|
||||||
|
newBuffer[pos] = byte(lSize)
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
if len(p.Buffer) > 2 {
|
||||||
|
copy(newBuffer[pos:], p.Buffer[2:])
|
||||||
|
pos += int(lSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add second packet
|
||||||
|
if rSize >= 255 {
|
||||||
|
newBuffer[pos] = 255
|
||||||
|
pos++
|
||||||
|
binary.BigEndian.PutUint16(newBuffer[pos:], uint16(rSize))
|
||||||
|
pos += 2
|
||||||
|
} else {
|
||||||
|
newBuffer[pos] = byte(rSize)
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
if len(rhs.Buffer) > 2 {
|
||||||
|
copy(newBuffer[pos:], rhs.Buffer[2:])
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Opcode = opAppCombined
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
p.packetPrepared = false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeApplicationPacket converts to app packet (matches EQProtocolPacket::MakeApplicationPacket)
|
||||||
|
func (p *ProtoPacket) MakeApplicationPacket(opcodeSize uint8) *AppPacket {
|
||||||
|
// Decompress if needed - handle both zlib and simple encoding
|
||||||
|
if p.eq2Compressed && len(p.Buffer) > 2 {
|
||||||
|
// Check compression type at position 2 (after sequence bytes)
|
||||||
|
compressionFlag := byte(0)
|
||||||
|
if len(p.Buffer) > 2 {
|
||||||
|
compressionFlag = p.Buffer[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
if compressionFlag == 0x5a {
|
||||||
|
// Zlib compression - decompress data after flag
|
||||||
|
if len(p.Buffer) > 3 {
|
||||||
|
if decompressed, err := Decompress(p.Buffer[3:]); err == nil {
|
||||||
|
// Rebuild buffer without compression
|
||||||
|
newBuffer := make([]byte, 2+len(decompressed))
|
||||||
|
copy(newBuffer[:2], p.Buffer[:2]) // Copy sequence
|
||||||
|
copy(newBuffer[2:], decompressed)
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
p.eq2Compressed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if compressionFlag == 0xa5 {
|
||||||
|
// Simple encoding - just remove the flag
|
||||||
|
if len(p.Buffer) > 3 {
|
||||||
|
newBuffer := make([]byte, len(p.Buffer)-1)
|
||||||
|
copy(newBuffer[:2], p.Buffer[:2]) // Copy sequence
|
||||||
|
copy(newBuffer[2:], p.Buffer[3:]) // Skip flag
|
||||||
|
p.Buffer = newBuffer
|
||||||
|
p.eq2Compressed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode chat if needed
|
||||||
|
if p.packetEncrypted && p.EncodeKey != 0 {
|
||||||
|
ChatDecode(p.Buffer, p.EncodeKey)
|
||||||
|
p.packetEncrypted = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewAppPacketFromRaw(p.Buffer, opcodeSize, p.manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a deep copy
|
||||||
|
func (p *ProtoPacket) Copy() *ProtoPacket {
|
||||||
|
newPacket := &ProtoPacket{
|
||||||
|
Packet: NewPacket(p.Opcode, p.Buffer),
|
||||||
|
eq2Compressed: p.eq2Compressed,
|
||||||
|
packetPrepared: p.packetPrepared,
|
||||||
|
packetEncrypted: p.packetEncrypted,
|
||||||
|
acked: p.acked,
|
||||||
|
LoginOp: p.LoginOp,
|
||||||
|
Sequence: p.Sequence,
|
||||||
|
SentTime: p.SentTime,
|
||||||
|
AttemptCount: p.AttemptCount,
|
||||||
|
manager: p.manager,
|
||||||
|
CompressThreshold: p.CompressThreshold,
|
||||||
|
EncodeKey: p.EncodeKey,
|
||||||
|
}
|
||||||
|
newPacket.Packet.CopyInfo(p.Packet)
|
||||||
|
return newPacket
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOpcodeName returns human-readable name for the opcode (matches C++ EQ2Packet::GetOpcodeName)
|
||||||
|
func (p *ProtoPacket) GetOpcodeName() string {
|
||||||
|
// Use manager to get opcode name if available
|
||||||
|
if p.manager != nil {
|
||||||
|
if name := p.manager.EmuToName(p.LoginOp); name != "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to protocol opcode names
|
||||||
|
switch p.Opcode {
|
||||||
|
case opcodes.OP_SessionRequest:
|
||||||
|
return "OP_SessionRequest"
|
||||||
|
case opcodes.OP_SessionResponse:
|
||||||
|
return "OP_SessionResponse"
|
||||||
|
case opcodes.OP_Combined:
|
||||||
|
return "OP_Combined"
|
||||||
|
case opcodes.OP_SessionDisconnect:
|
||||||
|
return "OP_SessionDisconnect"
|
||||||
|
case opcodes.OP_KeepAlive:
|
||||||
|
return "OP_KeepAlive"
|
||||||
|
case opcodes.OP_SessionStatRequest:
|
||||||
|
return "OP_SessionStatRequest"
|
||||||
|
case opcodes.OP_SessionStatResponse:
|
||||||
|
return "OP_SessionStatResponse"
|
||||||
|
case opcodes.OP_Packet:
|
||||||
|
return "OP_Packet"
|
||||||
|
case opcodes.OP_Fragment:
|
||||||
|
return "OP_Fragment"
|
||||||
|
case opcodes.OP_Ack:
|
||||||
|
return "OP_Ack"
|
||||||
|
case opcodes.OP_AppCombined:
|
||||||
|
return "OP_AppCombined"
|
||||||
|
case opcodes.OP_OutOfOrderAck:
|
||||||
|
return "OP_OutOfOrderAck"
|
||||||
|
case opcodes.OP_OutOfSession:
|
||||||
|
return "OP_OutOfSession"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Unknown(0x%04X)", p.Opcode)
|
||||||
|
}
|
||||||
|
}
|
34
packets/types.go
Normal file
34
packets/types.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package packets
|
||||||
|
|
||||||
|
// PacketSerializer interface for common packet operations
|
||||||
|
type PacketSerializer interface {
|
||||||
|
Serialize(dest []byte) uint32
|
||||||
|
Size() uint32
|
||||||
|
Copy() PacketSerializer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream states
|
||||||
|
type StreamState uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
StateDisconnected StreamState = iota
|
||||||
|
StateConnecting
|
||||||
|
StateEstablished
|
||||||
|
StateClosing
|
||||||
|
StateClosed
|
||||||
|
)
|
||||||
|
|
||||||
|
// Packet priority levels
|
||||||
|
const (
|
||||||
|
PriorityLow uint32 = 0
|
||||||
|
PriorityNormal uint32 = 5
|
||||||
|
PriorityHigh uint32 = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
// Max packet sizes
|
||||||
|
const (
|
||||||
|
MaxPacketSize = 0xFFFF
|
||||||
|
DefaultMTU = 1450
|
||||||
|
MaxCombinedSize = 512
|
||||||
|
MaxFragmentChunk = 0xFFFF
|
||||||
|
)
|
271
stream/factory.go
Normal file
271
stream/factory.go
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.sharkk.net/EQ2/Protocol/opcodes"
|
||||||
|
"git.sharkk.net/EQ2/Protocol/packets"
|
||||||
|
"github.com/panjf2000/gnet/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StreamFactory manages EQStream instances using gnet
|
||||||
|
type StreamFactory struct {
|
||||||
|
gnet.BuiltinEventEngine
|
||||||
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
streams map[gnet.Conn]*Stream
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
crcKey uint32
|
||||||
|
maxPacketSize uint16
|
||||||
|
encodeKey int
|
||||||
|
decodeKey int
|
||||||
|
opcodeSize uint8
|
||||||
|
clientVersion int16
|
||||||
|
|
||||||
|
// Database for opcodes
|
||||||
|
db *sql.DB
|
||||||
|
opcodeTable string
|
||||||
|
opcodeManager opcodes.Manager
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
onNewStream func(*Stream)
|
||||||
|
onStreamClosed func(*Stream)
|
||||||
|
onPacket func(*Stream, *packets.AppPacket)
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
totalStreams uint64
|
||||||
|
activeStreams uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// FactoryConfig holds factory configuration
|
||||||
|
type FactoryConfig struct {
|
||||||
|
CRCKey uint32
|
||||||
|
MaxPacketSize uint16
|
||||||
|
EncodeKey int
|
||||||
|
DecodeKey int
|
||||||
|
OpcodeSize uint8
|
||||||
|
ClientVersion int16
|
||||||
|
Database *sql.DB
|
||||||
|
OpcodeTable string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStreamFactory creates a new factory
|
||||||
|
func NewStreamFactory(cfg *FactoryConfig) *StreamFactory {
|
||||||
|
f := &StreamFactory{
|
||||||
|
streams: make(map[gnet.Conn]*Stream),
|
||||||
|
crcKey: cfg.CRCKey,
|
||||||
|
maxPacketSize: cfg.MaxPacketSize,
|
||||||
|
encodeKey: cfg.EncodeKey,
|
||||||
|
decodeKey: cfg.DecodeKey,
|
||||||
|
opcodeSize: cfg.OpcodeSize,
|
||||||
|
clientVersion: cfg.ClientVersion,
|
||||||
|
db: cfg.Database,
|
||||||
|
opcodeTable: cfg.OpcodeTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.maxPacketSize == 0 {
|
||||||
|
f.maxPacketSize = packets.DefaultMTU
|
||||||
|
}
|
||||||
|
if f.opcodeSize == 0 {
|
||||||
|
f.opcodeSize = packets.DefaultOpcodeSize
|
||||||
|
}
|
||||||
|
if f.opcodeTable == "" {
|
||||||
|
f.opcodeTable = "opcodes"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize opcode manager
|
||||||
|
if cfg.ClientVersion > 0 && cfg.Database != nil {
|
||||||
|
f.opcodeManager = opcodes.GetManager(cfg.ClientVersion, cfg.Database, f.opcodeTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnBoot called when server starts
|
||||||
|
func (f *StreamFactory) OnBoot(eng gnet.Engine) gnet.Action {
|
||||||
|
log.Printf("StreamFactory started")
|
||||||
|
return gnet.None
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnOpen called when new connection opens
|
||||||
|
func (f *StreamFactory) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
|
||||||
|
// Create stream configuration
|
||||||
|
streamCfg := &Config{
|
||||||
|
SessionID: uint32(time.Now().UnixNano()),
|
||||||
|
CRCKey: f.crcKey,
|
||||||
|
MaxPacketSize: f.maxPacketSize,
|
||||||
|
EncodeKey: f.encodeKey,
|
||||||
|
DecodeKey: f.decodeKey,
|
||||||
|
OpcodeManager: f.opcodeManager,
|
||||||
|
OpcodeSize: f.opcodeSize,
|
||||||
|
AckThreshold: 200 * time.Millisecond,
|
||||||
|
KeepaliveTime: 10 * time.Second,
|
||||||
|
TimeoutDuration: 30 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new stream
|
||||||
|
stream := NewStream(c, streamCfg)
|
||||||
|
|
||||||
|
// Set packet callback
|
||||||
|
stream.SetPacketCallback(func(app *packets.AppPacket) {
|
||||||
|
if f.onPacket != nil {
|
||||||
|
f.onPacket(stream, app)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Store stream
|
||||||
|
f.mu.Lock()
|
||||||
|
f.streams[c] = stream
|
||||||
|
f.activeStreams++
|
||||||
|
f.totalStreams++
|
||||||
|
f.mu.Unlock()
|
||||||
|
|
||||||
|
// Notify callback
|
||||||
|
if f.onNewStream != nil {
|
||||||
|
f.onNewStream(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetContext(stream)
|
||||||
|
log.Printf("New stream from %s", c.RemoteAddr())
|
||||||
|
|
||||||
|
return nil, gnet.None
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnClose called when connection closes
|
||||||
|
func (f *StreamFactory) OnClose(c gnet.Conn, err error) gnet.Action {
|
||||||
|
f.mu.Lock()
|
||||||
|
stream, exists := f.streams[c]
|
||||||
|
if exists {
|
||||||
|
delete(f.streams, c)
|
||||||
|
f.activeStreams--
|
||||||
|
}
|
||||||
|
f.mu.Unlock()
|
||||||
|
|
||||||
|
if stream != nil {
|
||||||
|
stream.Close()
|
||||||
|
|
||||||
|
// Notify callback
|
||||||
|
if f.onStreamClosed != nil {
|
||||||
|
f.onStreamClosed(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Stream closed: %s", c.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
return gnet.None
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnTraffic handles incoming data
|
||||||
|
func (f *StreamFactory) OnTraffic(c gnet.Conn) gnet.Action {
|
||||||
|
stream := c.Context().(*Stream)
|
||||||
|
if stream == nil {
|
||||||
|
return gnet.Close
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all available data
|
||||||
|
buf, err := c.Next(-1)
|
||||||
|
if err != nil {
|
||||||
|
return gnet.Close
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process packet
|
||||||
|
if err := stream.Process(buf); err != nil {
|
||||||
|
log.Printf("Stream process error: %v", err)
|
||||||
|
return gnet.Close
|
||||||
|
}
|
||||||
|
|
||||||
|
return gnet.None
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnTick called periodically to process stream queues
|
||||||
|
func (f *StreamFactory) OnTick() (time.Duration, gnet.Action) {
|
||||||
|
f.mu.RLock()
|
||||||
|
streams := make([]*Stream, 0, len(f.streams))
|
||||||
|
for _, stream := range f.streams {
|
||||||
|
streams = append(streams, stream)
|
||||||
|
}
|
||||||
|
f.mu.RUnlock()
|
||||||
|
|
||||||
|
// Process queues for all streams
|
||||||
|
for _, stream := range streams {
|
||||||
|
stream.processQueues()
|
||||||
|
}
|
||||||
|
|
||||||
|
return 100 * time.Millisecond, gnet.None
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStream returns stream for a connection
|
||||||
|
func (f *StreamFactory) GetStream(c gnet.Conn) *Stream {
|
||||||
|
f.mu.RLock()
|
||||||
|
defer f.mu.RUnlock()
|
||||||
|
return f.streams[c]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllStreams returns all active streams
|
||||||
|
func (f *StreamFactory) GetAllStreams() []*Stream {
|
||||||
|
f.mu.RLock()
|
||||||
|
defer f.mu.RUnlock()
|
||||||
|
|
||||||
|
result := make([]*Stream, 0, len(f.streams))
|
||||||
|
for _, stream := range f.streams {
|
||||||
|
result = append(result, stream)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNewStreamCallback sets callback for new streams
|
||||||
|
func (f *StreamFactory) SetNewStreamCallback(fn func(*Stream)) {
|
||||||
|
f.onNewStream = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStreamClosedCallback sets callback for closed streams
|
||||||
|
func (f *StreamFactory) SetStreamClosedCallback(fn func(*Stream)) {
|
||||||
|
f.onStreamClosed = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPacketCallback sets global packet callback
|
||||||
|
func (f *StreamFactory) SetPacketCallback(fn func(*Stream, *packets.AppPacket)) {
|
||||||
|
f.onPacket = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpcodeManager updates opcodes for a specific version
|
||||||
|
func (f *StreamFactory) UpdateOpcodeManager(version int16) {
|
||||||
|
if f.db != nil {
|
||||||
|
f.opcodeManager = opcodes.GetManager(version, f.db, f.opcodeTable)
|
||||||
|
log.Printf("Updated opcode manager to version %d", version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats returns factory statistics
|
||||||
|
func (f *StreamFactory) Stats() map[string]uint64 {
|
||||||
|
f.mu.RLock()
|
||||||
|
defer f.mu.RUnlock()
|
||||||
|
|
||||||
|
return map[string]uint64{
|
||||||
|
"total_streams": f.totalStreams,
|
||||||
|
"active_streams": f.activeStreams,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts the factory as a UDP server
|
||||||
|
func Run(addr string, factory *StreamFactory) error {
|
||||||
|
return gnet.Run(factory, addr,
|
||||||
|
gnet.WithMulticore(true),
|
||||||
|
gnet.WithReuseAddr(true),
|
||||||
|
gnet.WithReusePort(true),
|
||||||
|
gnet.WithTicker(true),
|
||||||
|
gnet.WithTCPKeepAlive(0), // Disable for UDP
|
||||||
|
gnet.WithSocketRecvBuffer(1024*1024),
|
||||||
|
gnet.WithSocketSendBuffer(1024*1024),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunTLS starts the factory with TLS (future enhancement)
|
||||||
|
func RunTLS(addr string, factory *StreamFactory, certFile, keyFile string) error {
|
||||||
|
// TLS configuration would go here if needed
|
||||||
|
return Run(addr, factory)
|
||||||
|
}
|
1170
stream/stream.go
Normal file
1170
stream/stream.go
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user