#pragma once #include template struct BSTEventSink; // Very nasty work around to avoid template code duplication namespace details { void InternalRegisterSink(void* apEventDispatcher, void* apSink) noexcept; void InternalUnRegisterSink(void* apEventDispatcher, void* apSink) noexcept; void InternalPushEvent(void* apEventDispatcher, void* apEvent) noexcept; } // namespace details template struct EventDispatcher { void RegisterSink(BSTEventSink* apSink) noexcept { details::InternalRegisterSink(reinterpret_cast(this), reinterpret_cast(apSink)); } void UnRegisterSink(BSTEventSink* apSink) noexcept { details::InternalUnRegisterSink(reinterpret_cast(this), reinterpret_cast(apSink)); } void PushEvent(const T* apEvent) noexcept { details::InternalPushEvent(reinterpret_cast(this), reinterpret_cast(apEvent)); } uint8_t pad0[0x58]; }; struct UnknownEvent { }; struct BGSEventProcessedEvent { }; struct TESActivateEvent { TESObjectREFR* object; }; struct TESActiveEffectApplyRemove { TESObjectREFR* hCaster; TESObjectREFR* hTarget; uint16_t usActiveEffectUniqueID; bool bIsApplied; }; struct TESActorLocationChangeEvent { }; struct TESBookReadEvent { }; struct TESCellAttachDetachEvent { }; struct TESCellFullyLoadedEvent { }; struct TESCombatEvent { }; struct TESContainerChangedEvent { uint32_t oldContainerID; uint32_t newContainerID; uint8_t pad8[0xC]; }; struct TESDeathEvent { TESObjectREFR* pActorDying; TESObjectREFR* pActorKiller; bool isDead; }; struct TESDestructionStageChangedEvent { }; struct TESEnterBleedoutEvent { }; struct TESEquipEvent { }; struct TESFormDeleteEvent { }; struct TESFurnitureEvent { }; struct TESGrabReleaseEvent { }; struct TESHitEvent { TESObjectREFR* hit; TESObjectREFR* hitter; }; struct TESLoadGameEvent { }; struct TESLockChangedEvent { }; struct TESMagicEffectApplyEvent { TESObjectREFR* hTarget; TESObjectREFR* hCaster; uint32_t uiMagicEffectFormID; }; struct TESMagicWardHitEvent { }; struct TESMoveAttachDetachEvent { }; struct TESObjectLoadedEvent { }; struct TESObjectREFRTranslationEvent { }; struct TESOpenCloseEvent { }; struct TESPackageEvent { }; struct TESInitScriptEvent { }; struct TESPerkEntryRunEvent { }; struct TESQuestInitEvent { uint32_t formId; }; struct TESQuestStageEvent { void* callback; uint32_t formId; uint16_t stageId; bool bUnk; }; struct TESQuestStartStopEvent { uint32_t formId; }; struct TESQuestStageItemDoneEvent { uint32_t formId; uint16_t stageId; bool unk; }; struct TESResetEvent { }; struct TESResolveNPCTemplatesEvent { }; struct TESSceneEvent { }; struct TESSceneActionEvent { }; struct TESScenePhaseEvent { }; struct TESSellEvent { }; struct TESSleepStartEvent { }; struct TESSleepStopEvent { }; struct TESSpellCastEvent { }; struct TESPlayerBowShotEvent { }; struct TESTopicInfoEvent { TESObjectREFR* hSpeakerRef; void* pCallback; uint32_t uiTopicInfoFormID; int32_t eType; uint16_t usStage; }; struct TESTrackedStatsEvent { }; struct TESTrapHitEvent { }; struct TESTriggerEvent { TESObjectREFR* pTrigger; TESObjectREFR* pActionRef; }; struct TESTriggerEnterEvent { TESObjectREFR* pTrigger; TESObjectREFR* pActionRef; }; struct TESTriggerLeaveEvent { TESObjectREFR* pTrigger; TESObjectREFR* pActionRef; }; struct TESUniqueIDChangeEvent { }; struct TESSwitchRaceCompleteEvent { }; struct TESFastTravelEndEvent { }; struct EventDispatcherManager { static EventDispatcherManager* Get() noexcept; EventDispatcher eventProcessedEvent; EventDispatcher activateEvent; EventDispatcher activeEffectApplyRemove; EventDispatcher actorLocationChangeEvent; EventDispatcher bookReadEvent; EventDispatcher cellAttachDetachEvent; EventDispatcher cellFullyLoadedEvent; EventDispatcher unknownDispatcher8; // apply decals event EventDispatcher combatEvent; EventDispatcher containerChangedEvent; EventDispatcher deathEvent; EventDispatcher destructionStageChangedEventDispatcher; EventDispatcher enterBleedoutEvent; EventDispatcher equipEvent; EventDispatcher formDeleteEvent; EventDispatcher furnitureEvent; EventDispatcher grabReleaseEvent; EventDispatcher hitEvent; // validated EventDispatcher initScriptEvent; EventDispatcher loadGameEvent; EventDispatcher lockChangedEvent; EventDispatcher magicEffectApplyEvent; EventDispatcher magicWardHitEvent; EventDispatcher moveAttachDetachEvent; EventDispatcher objectLoadedEvent; EventDispatcher objectREFRTranslationEvent; EventDispatcher openCloseEvent; EventDispatcher packageEvent; EventDispatcher perkEntryRunEvent; EventDispatcher questInitEvent; // 9F8 EventDispatcher questStageEvent; EventDispatcher questStageItemDoneEvent; // AA8, validated StageItemFinishedCallback::TriggerItemDoneEvent EventDispatcher questStartStopEvent; // TESResolveNPCTemplatesEvent EventDispatcher resetEvent; // validated 0xB58 EventDispatcher resolveNPCTemplatesEvent; EventDispatcher sceneEvent; EventDispatcher sceneActionEvent; EventDispatcher scenePhaseEvent; EventDispatcher sellEvent; EventDispatcher unknownDispatcher39; EventDispatcher sleepStopEvent; EventDispatcher spellCastEvent; EventDispatcher unknownDispatcher42; EventDispatcher topicInfoEvent; EventDispatcher trackedStatsEvent; EventDispatcher trapHitEvent; EventDispatcher triggerEvent; EventDispatcher triggerEnterEvent; EventDispatcher triggerLeaveEvent; EventDispatcher uniqueIDChangeEvent; EventDispatcher unknownDispatcher50; // waitevent EventDispatcher unknownDispatcher51; // TESWaitStopEvent EventDispatcher switchRaceCompleteEvent; EventDispatcher fastTravelEndEvent; }; // constexpr auto x = offsetof(EventDispatcherManager, unkx); static_assert(sizeof(EventDispatcherManager) == 4752); static_assert(offsetof(EventDispatcherManager, activateEvent) == 88); static_assert(offsetof(EventDispatcherManager, deathEvent) == 880); static_assert(offsetof(EventDispatcherManager, lockChangedEvent) == 1760); static_assert(offsetof(EventDispatcherManager, furnitureEvent) == 1320); static_assert(offsetof(EventDispatcherManager, resetEvent) == 2904); static_assert(offsetof(EventDispatcherManager, trackedStatsEvent) == 3872); static_assert(offsetof(EventDispatcherManager, triggerEvent) == 4048); static_assert(offsetof(EventDispatcherManager, switchRaceCompleteEvent) == 4576); static_assert(offsetof(EventDispatcherManager, fastTravelEndEvent) == 4664); static_assert(offsetof(EventDispatcherManager, questInitEvent) == 0x9F8); static_assert(offsetof(EventDispatcherManager, questStageEvent) == 0xA50); static_assert(offsetof(EventDispatcherManager, questStartStopEvent) == 0xB00);