From 072fb7b2ec3e1f6ba6433ba4c9cea1f93528acf1 Mon Sep 17 00:00:00 2001
From: Leonid Pospelov <leonidpospelov.dev@gmail.com>
Date: Fri, 3 Nov 2023 19:52:04 +0600
Subject: [PATCH] internal: fix Windows build (#1728)

---
 .../skyrim_platform/EventHandler.h            | 136 ++++++++++++------
 .../platform_se/skyrim_platform/EventUtils.h  |   2 +-
 2 files changed, 93 insertions(+), 45 deletions(-)

diff --git a/skyrim-platform/src/platform_se/skyrim_platform/EventHandler.h b/skyrim-platform/src/platform_se/skyrim_platform/EventHandler.h
index 4c431507bb..2e769222dd 100644
--- a/skyrim-platform/src/platform_se/skyrim_platform/EventHandler.h
+++ b/skyrim-platform/src/platform_se/skyrim_platform/EventHandler.h
@@ -452,64 +452,83 @@ class EventHandler final
     activeSinks.reserve(20);
 
     // script events
-    AppendSink<RE::TESActivateEvent>(std::vector({ "activate" }));
-    AppendSink<RE::TESActiveEffectApplyRemoveEvent>(
+    AppendSinkScriptEvent<RE::TESActivateEvent>(std::vector({ "activate" }));
+    AppendSinkScriptEvent<RE::TESActiveEffectApplyRemoveEvent>(
       std::vector({ "effectStart", "effectFinish" }));
-    AppendSink<RE::TESActorLocationChangeEvent>(
+    AppendSinkScriptEvent<RE::TESActorLocationChangeEvent>(
       std::vector({ "locationChanged" }));
-    AppendSink<RE::TESCellAttachDetachEvent>(
+    AppendSinkScriptEvent<RE::TESCellAttachDetachEvent>(
       std::vector({ "cellAttach", "cellDetach" }));
-    AppendSink<RE::TESCellFullyLoadedEvent>(
+    AppendSinkScriptEvent<RE::TESCellFullyLoadedEvent>(
       std::vector({ "cellFullyLoaded" }));
-    AppendSink<RE::TESCombatEvent>(std::vector({ "combatState" }));
-    AppendSink<RE::TESContainerChangedEvent>(
+    AppendSinkScriptEvent<RE::TESCombatEvent>(std::vector({ "combatState" }));
+    AppendSinkScriptEvent<RE::TESContainerChangedEvent>(
       std::vector({ "containerChanged" }));
-    AppendSink<RE::TESDeathEvent>(std::vector({ "deathEnd", "deathStart" }));
-    AppendSink<RE::TESDestructionStageChangedEvent>(
+    AppendSinkScriptEvent<RE::TESDeathEvent>(
+      std::vector({ "deathEnd", "deathStart" }));
+    AppendSinkScriptEvent<RE::TESDestructionStageChangedEvent>(
       std::vector({ "destructionStageChanged" }));
-    AppendSink<RE::TESEnterBleedoutEvent>(std::vector({ "enterBleedout" }));
-    AppendSink<RE::TESEquipEvent>(std::vector({ "equip", "unequip" }));
-    AppendSink<RE::TESFastTravelEndEvent>(std::vector({ "fastTravelEnd" }));
-    AppendSink<RE::TESFurnitureEvent>(
+    AppendSinkScriptEvent<RE::TESEnterBleedoutEvent>(
+      std::vector({ "enterBleedout" }));
+    AppendSinkScriptEvent<RE::TESEquipEvent>(
+      std::vector({ "equip", "unequip" }));
+    AppendSinkScriptEvent<RE::TESFastTravelEndEvent>(
+      std::vector({ "fastTravelEnd" }));
+    AppendSinkScriptEvent<RE::TESFurnitureEvent>(
       std::vector({ "furnitureExit", "furnitureEnter" }));
-    AppendSink<RE::TESGrabReleaseEvent>(std::vector({ "grabRelease" }));
-    AppendSink<RE::TESHitEvent>(std::vector({ "hit" }));
-    AppendSink<RE::TESInitScriptEvent>(std::vector({ "scriptInit" }));
-    AppendSink<RE::TESLoadGameEvent>(std::vector({ "loadGame" }));
-    AppendSink<RE::TESLockChangedEvent>(std::vector({ "lockChanged" }));
-    AppendSink<RE::TESMagicEffectApplyEvent>(
+    AppendSinkScriptEvent<RE::TESGrabReleaseEvent>(
+      std::vector({ "grabRelease" }));
+    AppendSinkScriptEvent<RE::TESHitEvent>(std::vector({ "hit" }));
+    AppendSinkScriptEvent<RE::TESInitScriptEvent>(
+      std::vector({ "scriptInit" }));
+    AppendSinkScriptEvent<RE::TESLoadGameEvent>(std::vector({ "loadGame" }));
+    AppendSinkScriptEvent<RE::TESLockChangedEvent>(
+      std::vector({ "lockChanged" }));
+    AppendSinkScriptEvent<RE::TESMagicEffectApplyEvent>(
       std::vector({ "magicEffectApply" }));
-    AppendSink<RE::TESMagicWardHitEvent>(std::vector({ "wardHit" }));
-    AppendSink<RE::TESMoveAttachDetachEvent>(
+    AppendSinkScriptEvent<RE::TESMagicWardHitEvent>(
+      std::vector({ "wardHit" }));
+    AppendSinkScriptEvent<RE::TESMoveAttachDetachEvent>(
       std::vector({ "moveAttachDetach" }));
-    AppendSink<RE::TESObjectLoadedEvent>(std::vector({ "objectLoaded" }));
-    AppendSink<RE::TESObjectREFRTranslationEvent>(
+    AppendSinkScriptEvent<RE::TESObjectLoadedEvent>(
+      std::vector({ "objectLoaded" }));
+    AppendSinkScriptEvent<RE::TESObjectREFRTranslationEvent>(
       std::vector({ "translationFailed", "translationAlmostCompleted",
                     "translationCompleted" }));
-    AppendSink<RE::TESOpenCloseEvent>(std::vector({ "open", "close" }));
-    AppendSink<RE::TESPackageEvent>(
+    AppendSinkScriptEvent<RE::TESOpenCloseEvent>(
+      std::vector({ "open", "close" }));
+    AppendSinkScriptEvent<RE::TESPackageEvent>(
       std::vector({ "packageStart", "packageChange", "packageEnd" }));
-    AppendSink<RE::TESPerkEntryRunEvent>(std::vector({ "perkEntryRun" }));
-    AppendSink<RE::TESPlayerBowShotEvent>(std::vector({ "playerBowShot" }));
-    AppendSink<RE::TESQuestInitEvent>(std::vector({ "questInit" }));
-    AppendSink<RE::TESQuestStageEvent>(std::vector({ "questStage" }));
-    AppendSink<RE::TESQuestStartStopEvent>(
+    AppendSinkScriptEvent<RE::TESPerkEntryRunEvent>(
+      std::vector({ "perkEntryRun" }));
+    AppendSinkScriptEvent<RE::TESPlayerBowShotEvent>(
+      std::vector({ "playerBowShot" }));
+    AppendSinkScriptEvent<RE::TESQuestInitEvent>(std::vector({ "questInit" }));
+    AppendSinkScriptEvent<RE::TESQuestStageEvent>(
+      std::vector({ "questStage" }));
+    AppendSinkScriptEvent<RE::TESQuestStartStopEvent>(
       std::vector({ "questStart", "questStop" }));
-    AppendSink<RE::TESResetEvent>(std::vector({ "reset" }));
-    AppendSink<RE::TESSceneActionEvent>(std::vector({ "sceneAction" }));
-    AppendSink<RE::TESSellEvent>(std::vector({ "sell" }));
-    AppendSink<RE::TESSleepStartEvent>(std::vector({ "sleepStart" }));
-    AppendSink<RE::TESSleepStopEvent>(std::vector({ "sleepStop" }));
-    AppendSink<RE::TESSpellCastEvent>(std::vector({ "spellCast" }));
-    AppendSink<RE::TESSwitchRaceCompleteEvent>(
+    AppendSinkScriptEvent<RE::TESResetEvent>(std::vector({ "reset" }));
+    AppendSinkScriptEvent<RE::TESSceneActionEvent>(
+      std::vector({ "sceneAction" }));
+    AppendSinkScriptEvent<RE::TESSellEvent>(std::vector({ "sell" }));
+    AppendSinkScriptEvent<RE::TESSleepStartEvent>(
+      std::vector({ "sleepStart" }));
+    AppendSinkScriptEvent<RE::TESSleepStopEvent>(std::vector({ "sleepStop" }));
+    AppendSinkScriptEvent<RE::TESSpellCastEvent>(std::vector({ "spellCast" }));
+    AppendSinkScriptEvent<RE::TESSwitchRaceCompleteEvent>(
       std::vector({ "switchRaceComplete" }));
-    AppendSink<RE::TESTrackedStatsEvent>(std::vector({ "trackedStats" }));
-    AppendSink<RE::TESTriggerEnterEvent>(std::vector({ "triggerEnter" }));
-    AppendSink<RE::TESTriggerEvent>(std::vector({ "trigger" }));
-    AppendSink<RE::TESTriggerLeaveEvent>(std::vector({ "triggerLeave" }));
-    AppendSink<RE::TESUniqueIDChangeEvent>(std::vector({ "uniqueIdChange" }));
-    AppendSink<RE::TESWaitStartEvent>(std::vector({ "waitStart" }));
-    AppendSink<RE::TESWaitStopEvent>(std::vector({ "waitStop" }));
+    AppendSinkScriptEvent<RE::TESTrackedStatsEvent>(
+      std::vector({ "trackedStats" }));
+    AppendSinkScriptEvent<RE::TESTriggerEnterEvent>(
+      std::vector({ "triggerEnter" }));
+    AppendSinkScriptEvent<RE::TESTriggerEvent>(std::vector({ "trigger" }));
+    AppendSinkScriptEvent<RE::TESTriggerLeaveEvent>(
+      std::vector({ "triggerLeave" }));
+    AppendSinkScriptEvent<RE::TESUniqueIDChangeEvent>(
+      std::vector({ "uniqueIdChange" }));
+    AppendSinkScriptEvent<RE::TESWaitStartEvent>(std::vector({ "waitStart" }));
+    AppendSinkScriptEvent<RE::TESWaitStopEvent>(std::vector({ "waitStop" }));
 
     // skse events
     // at the moment of writing, no way was found to standardize event source
@@ -655,6 +674,35 @@ class EventHandler final
     AppendSink<RE::SpellsLearned>(std::vector({ "spellsLearned" }));
   }
 
+  template <class E>
+  void AppendSinkScriptEvent(std::vector<const char*> eventNames)
+  {
+    // should consider checking if sink exists
+    // but since we store sink pointers
+    // the only option it to loop through all sinks
+    // and check for event names, TODO?
+
+    auto sink = new Sink(
+      eventNames,
+      // Activate
+      [](const ::Sink* sink) {
+        const auto handler = EventHandler::GetSingleton();
+        handler->ActivateSink<E>(sink, GetEventSourceScriptEvent<E>());
+      },
+      // Deactivate
+      [](const ::Sink* sink) {
+        const auto handler = EventHandler::GetSingleton();
+        handler->DeactivateSink<E>(sink, GetEventSourceScriptEvent<E>());
+      },
+      // IsActive
+      [](const ::Sink* sink) -> bool {
+        const auto handler = EventHandler::GetSingleton();
+        return handler->IsActiveSink(sink);
+      });
+
+    sinks.emplace(sink);
+  }
+
   /**
    * @brief Create new sink instance and add it to sink set.
    * Registration via script event source.
diff --git a/skyrim-platform/src/platform_se/skyrim_platform/EventUtils.h b/skyrim-platform/src/platform_se/skyrim_platform/EventUtils.h
index db10cf288c..7bee972353 100644
--- a/skyrim-platform/src/platform_se/skyrim_platform/EventUtils.h
+++ b/skyrim-platform/src/platform_se/skyrim_platform/EventUtils.h
@@ -1,7 +1,7 @@
 #pragma once
 
 template <class E>
-inline RE::BSTEventSource<E>* GetEventSource()
+inline RE::BSTEventSource<E>* GetEventSourceScriptEvent()
 {
   return RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource<E>();
 }