diff --git a/codxe.vcxproj b/codxe.vcxproj
index b0c7e4e..1010ddd 100644
--- a/codxe.vcxproj
+++ b/codxe.vcxproj
@@ -90,6 +90,7 @@
+
diff --git a/src/game/iw3/mp/components/cg.cpp b/src/game/iw3/mp/components/cg.cpp
index 41cd697..9a292a7 100644
--- a/src/game/iw3/mp/components/cg.cpp
+++ b/src/game/iw3/mp/components/cg.cpp
@@ -108,14 +108,6 @@ void Menus_OpenByName_Hook(UiContext *dc, const char *menuName)
Menus_OpenByName_Detour.GetOriginal()(dc, menuName);
}
-Detour CG_Init_Detour;
-
-void CG_Init_Hook(int localClientNum, int serverMessageNum, int serverCommandSequence, int clientNum)
-{
- CG_Init_Detour.GetOriginal()(localClientNum, serverMessageNum, serverCommandSequence, clientNum);
- cj_tas::On_CG_Init();
-}
-
cg::cg()
{
Menus_OpenByName_Detour = Detour(Menus_OpenByName, Menus_OpenByName_Hook);
@@ -143,9 +135,6 @@ cg::cg()
UI_SafeTranslateString_Detour = Detour(UI_SafeTranslateString, UI_SafeTranslateString_Hook);
UI_SafeTranslateString_Detour.Install();
- CG_Init_Detour = Detour(CG_Init, CG_Init_Hook);
- CG_Init_Detour.Install();
-
cg_scoreboardLabel_Score = Dvar_RegisterString("cg_scoreboardLabel_Score", "", DVAR_FLAG_NONE,
"Override label for 'Score' column on scoreboard");
@@ -166,7 +155,6 @@ cg::~cg()
UI_SafeTranslateString_Detour.Remove();
BG_CalculateWeaponPosition_IdleAngles_Detour.Remove();
BG_CalculateView_IdleAngles_Detour.Remove();
- CG_Init_Detour.Remove();
}
} // namespace mp
} // namespace iw3
diff --git a/src/game/iw3/mp/components/cj_tas.cpp b/src/game/iw3/mp/components/cj_tas.cpp
index f002125..e754597 100644
--- a/src/game/iw3/mp/components/cj_tas.cpp
+++ b/src/game/iw3/mp/components/cj_tas.cpp
@@ -1,4 +1,5 @@
#include "pch.h"
+#include "events.h"
#include "cj_tas.h"
#define ANGLE2SHORT(x) ((int)((x) * 65536 / 360) & 65535)
@@ -35,12 +36,6 @@ dvar_s *cj_tas_playback_ignore_weapon = nullptr;
unsigned int rpg_mp_index = 0;
-void cj_tas::On_CG_Init()
-{
- // Weapon indexes change every game
- rpg_mp_index = BG_FindWeaponIndexForName("rpg_mp");
-}
-
void Cmd_Startrecord_f()
{
if (is_recording)
@@ -372,6 +367,15 @@ void CL_CreateNewCommands_Hook(int localClientNum)
}
}
+const float colorWhiteRGBA[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+void CG_DrawTAS()
+{
+ static Font_s *bigDevFont = R_RegisterFont("fonts/bigDevFont");
+ const float x = 10.f * scrPlaceFullUnsafe.scaleVirtualToFull[0];
+ const float y = 30.f;
+ R_AddCmdDrawText("TAS", 5, bigDevFont, x, y, 1.0, 1.0, 0.0, colorWhiteRGBA, 0);
+}
+
cj_tas::cj_tas()
{
CL_CreateNewCommands_Detour = Detour(CL_CreateNewCommands, CL_CreateNewCommands_Hook);
@@ -399,6 +403,22 @@ cj_tas::cj_tas()
cj_tas_rpg_lookdown_yaw = Dvar_RegisterInt("cj_tas_rpg_lookdown_yaw", 0, -180, 180, 0, "RPG lookdown yaw angle");
cj_tas_rpg_lookdown_pitch =
Dvar_RegisterInt("cj_tas_rpg_lookdown_pitch", 70, -70, 70, 0, "RPG lookdown pitch angle");
+
+ Events::OnCG_DrawActive(
+ []()
+ {
+ if (cj_tas::TAS_Enabled())
+ {
+ CG_DrawTAS();
+ }
+ });
+
+ Events::OnCG_Init(
+ []()
+ {
+ // Weapon indexes change every game
+ rpg_mp_index = BG_FindWeaponIndexForName("rpg_mp");
+ });
}
cj_tas::~cj_tas()
diff --git a/src/game/iw3/mp/components/clipmap.cpp b/src/game/iw3/mp/components/clipmap.cpp
index 041f226..d6d1787 100644
--- a/src/game/iw3/mp/components/clipmap.cpp
+++ b/src/game/iw3/mp/components/clipmap.cpp
@@ -1,4 +1,5 @@
#include "pch.h"
+#include "events.h"
#include "clipmap.h"
namespace iw3
@@ -123,6 +124,8 @@ clipmap::clipmap()
CM_LoadMap_Detour = Detour(CM_LoadMap, CM_LoadMap_Hook);
CM_LoadMap_Detour.Install();
+
+ Events::OnCG_DrawActive(clipmap::HandleBrushCollisionChange);
}
clipmap::~clipmap()
diff --git a/src/game/iw3/mp/components/events.cpp b/src/game/iw3/mp/components/events.cpp
new file mode 100644
index 0000000..104bbbf
--- /dev/null
+++ b/src/game/iw3/mp/components/events.cpp
@@ -0,0 +1,65 @@
+#include "pch.h"
+#include "events.h"
+
+namespace iw3
+{
+namespace mp
+{
+
+std::vector> Events::cg_drawactive_callbacks;
+
+void Events::CG_DrawActive_Hook(int localClientNum)
+{
+ // Call original function first
+ CG_DrawActive_Detour.GetOriginal()(localClientNum);
+
+ for (auto it = cg_drawactive_callbacks.begin(); it != cg_drawactive_callbacks.end(); ++it)
+ {
+ (*it)();
+ }
+}
+
+void Events::OnCG_DrawActive(const std::function &callback)
+{
+ cg_drawactive_callbacks.emplace_back(callback);
+}
+
+Detour Events::CG_DrawActive_Detour;
+
+std::vector> Events::cg_init_callbacks;
+
+void Events::CG_Init_Hook(int localClientNum, int serverMessageNum, int serverCommandSequence, int clientNum)
+{
+ // Call original function first
+ CG_Init_Detour.GetOriginal()(localClientNum, serverMessageNum, serverCommandSequence, clientNum);
+
+ for (auto it = cg_init_callbacks.begin(); it != cg_init_callbacks.end(); ++it)
+ {
+ (*it)();
+ }
+}
+
+void Events::OnCG_Init(const std::function &callback)
+{
+ cg_init_callbacks.emplace_back(callback);
+}
+
+Detour Events::CG_Init_Detour;
+
+Events::Events()
+{
+ CG_DrawActive_Detour = Detour(CG_DrawActive, CG_DrawActive_Hook);
+ CG_DrawActive_Detour.Install();
+
+ CG_Init_Detour = Detour(CG_Init, CG_Init_Hook);
+ CG_Init_Detour.Install();
+}
+
+Events::~Events()
+{
+ CG_DrawActive_Detour.Remove();
+ CG_Init_Detour.Remove();
+}
+
+} // namespace mp
+} // namespace iw3
diff --git a/src/game/iw3/mp/components/events.h b/src/game/iw3/mp/components/events.h
new file mode 100644
index 0000000..9cafd90
--- /dev/null
+++ b/src/game/iw3/mp/components/events.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "pch.h"
+
+namespace iw3
+{
+namespace mp
+{
+
+class Events : public Module
+{
+ public:
+ Events();
+ ~Events();
+
+ const char *get_name() override
+ {
+ return "Events";
+ };
+
+ static void OnCG_DrawActive(const std::function &callback);
+ static void OnCG_Init(const std::function &callback);
+
+ private:
+ static std::vector> cg_drawactive_callbacks;
+ static Detour CG_DrawActive_Detour;
+ static void CG_DrawActive_Hook(int localClientNum);
+
+ static std::vector> cg_init_callbacks;
+ static Detour CG_Init_Detour;
+ static void CG_Init_Hook(int localClientNum, int serverMessageNum, int serverCommandSequence, int clientNum);
+};
+} // namespace mp
+} // namespace iw3
\ No newline at end of file
diff --git a/src/game/iw3/mp/main.cpp b/src/game/iw3/mp/main.cpp
index e0d05ba..e07aa5b 100644
--- a/src/game/iw3/mp/main.cpp
+++ b/src/game/iw3/mp/main.cpp
@@ -1,9 +1,9 @@
#include "pch.h"
-#include "main.h"
#include "components/cg.h"
#include "components/cj_tas.h"
#include "components/clipmap.h"
#include "components/cmds.h"
+#include "components/events.h"
#include "components/g_scr_main.h"
#include "components/gsc_client_fields.h"
#include "components/gsc_functions.h"
@@ -14,6 +14,7 @@
#include "components/scr_parser.h"
#include "components/sv_bots.h"
#include "common/config.h"
+#include "main.h"
// Structure to hold data for the active keyboard request
struct KeyboardRequest
@@ -279,14 +280,6 @@ void DrawFixedFPS()
R_AddCmdDrawText(buff, 16, font, x, y, 1.0, 1.0, 0.0, colorWhiteRGBA, 0);
}
-void CG_DrawTAS()
-{
- static Font_s *bigDevFont = R_RegisterFont("fonts/bigDevFont");
- const float x = 10.f * scrPlaceFullUnsafe.scaleVirtualToFull[0];
- const float y = 30.f;
- R_AddCmdDrawText("TAS", 5, bigDevFont, x, y, 1.0, 1.0, 0.0, colorWhiteRGBA, 0);
-}
-
dvar_s *cg_draw_player_info = nullptr;
void CG_DrawPlayerInfo()
@@ -311,34 +304,6 @@ void CG_DrawPlayerInfo()
R_AddCmdDrawText(buff, 256, consoleFont, x, y, 1.0, 1.0, 0.0, colorWhiteRGBA, 0);
}
-Detour CG_DrawActive_Detour;
-
-void CG_DrawActive_Hook(int localClientNum)
-{
- static dvar_s *pm_fixed_fps_enable = Dvar_FindMalleableVar("pm_fixed_fps_enable");
-
- CheckKeyboardCompletion();
-
- if (pm_fixed_fps_enable->current.enabled)
- {
- DrawFixedFPS();
- }
-
- if (cj_tas::TAS_Enabled())
- {
- CG_DrawTAS();
- }
-
- if (cg_draw_player_info->current.enabled)
- {
- CG_DrawPlayerInfo();
- }
-
- clipmap::HandleBrushCollisionChange();
-
- CG_DrawActive_Detour.GetOriginal()(localClientNum);
-}
-
Detour UI_Refresh_Detour;
void UI_Refresh_Hook(int localClientNum)
@@ -408,7 +373,9 @@ IW3_MP_Plugin::IW3_MP_Plugin()
DisableFastfileAuth();
+ // Special modules need to be registered first
RegisterModule(new Config());
+ RegisterModule(new Events());
RegisterModule(new cg());
RegisterModule(new cj_tas());
@@ -427,9 +394,6 @@ IW3_MP_Plugin::IW3_MP_Plugin()
UI_Refresh_Detour = Detour(UI_Refresh, UI_Refresh_Hook);
UI_Refresh_Detour.Install();
- CG_DrawActive_Detour = Detour(CG_DrawActive, CG_DrawActive_Hook);
- CG_DrawActive_Detour.Install();
-
CL_GamepadButtonEvent_Detour = Detour(CL_GamepadButtonEvent, CL_GamepadButtonEvent_Hook);
CL_GamepadButtonEvent_Detour.Install();
@@ -446,13 +410,30 @@ IW3_MP_Plugin::IW3_MP_Plugin()
cg_draw_player_info =
Dvar_RegisterBool("cg_draw_player_info", false, 0, "Draw player info (origin, viewangles, speed) on screen");
+
+ Events::OnCG_DrawActive(
+ []()
+ {
+ CheckKeyboardCompletion();
+
+ static dvar_s *pm_fixed_fps_enable = Dvar_FindMalleableVar("pm_fixed_fps_enable");
+
+ if (pm_fixed_fps_enable->current.enabled)
+ {
+ DrawFixedFPS();
+ }
+
+ if (cg_draw_player_info->current.enabled)
+ {
+ CG_DrawPlayerInfo();
+ }
+ });
}
IW3_MP_Plugin::~IW3_MP_Plugin()
{
DbgPrint("Shutting down MP\n");
- CG_DrawActive_Detour.Remove();
CL_GamepadButtonEvent_Detour.Remove();
Load_MapEntsPtr_Detour.Remove();
diff --git a/src/game/iw3/mp/symbols.h b/src/game/iw3/mp/symbols.h
index 0f91c70..e42e4aa 100644
--- a/src/game/iw3/mp/symbols.h
+++ b/src/game/iw3/mp/symbols.h
@@ -15,7 +15,9 @@ static auto Cbuf_AddText = reinterpret_cast(0x8223AAE8);
-static auto CG_DrawActive = reinterpret_cast(0x8231E6E0);
+typedef void (*CG_DrawActive_t)(int localClientNum);
+static CG_DrawActive_t CG_DrawActive = reinterpret_cast(0x8231E6E0);
+
static auto CG_GameMessage = reinterpret_cast(0x8230AAF0);
static auto CG_GetPredictedPlayerState = reinterpret_cast(0x82309120);
static auto CG_RegisterGraphics = reinterpret_cast(0x8230D858);
@@ -201,9 +203,8 @@ static auto CL_GetPredictedOriginForServerTime =
int *bobCycle, int *movementDir)>(0x822CAA38);
static auto CL_SetStance = reinterpret_cast(0x822D92A0);
-static auto CG_Init =
- reinterpret_cast(
- 0x8230DEA0);
+typedef void (*CG_Init_t)(int localClientNum, int serverMessageNum, int serverCommandSequence, int clientNum);
+static CG_Init_t CG_Init = reinterpret_cast(0x8230DEA0);
static auto Hunk_AllocateTempMemoryHighInternal = reinterpret_cast(0x821D7328);
static auto Scr_AddSourceBuffer =