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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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