1+ #include " pch.h"
2+ #include " ForceFutureCheckpoint.h"
3+ #include " IMessagesGUI.h"
4+ #include " RuntimeExceptionHandler.h"
5+ #include " SettingsStateAndEvents.h"
6+ #include " IMCCStateHook.h"
7+ #include " GameTickEventHook.h"
8+ #include " IMakeOrGetCheat.h"
9+
10+ class ForceFutureCheckpoint ::ForceFutureCheckpointImpl
11+ {
12+ private:
13+ GameState mGame ;
14+ // injected services
15+ std::weak_ptr<IMessagesGUI> messagesGUIWeak;
16+ std::shared_ptr<RuntimeExceptionHandler> runtimeExceptions;
17+ std::weak_ptr<GameTickEventHook> gameTickEventHookWeak;
18+ std::weak_ptr<SettingsStateAndEvents> settingsWeak;
19+ std::weak_ptr<IMCCStateHook> mccStateHookWeak;
20+
21+ // event callbacks
22+ ScopedCallback <ToggleEvent> forceFutureCheckpointToggleCallback;
23+ void onForceFutureCheckpointToggle (bool & newValue)
24+ {
25+ try
26+ {
27+ lockOrThrow (gameTickEventHookWeak, gameTickEventHook);
28+
29+ if (newValue)
30+ {
31+ gameTickEventCallback = std::make_unique<ScopedCallback<eventpp::CallbackList<void (int )>>>(gameTickEventHook->getGameTickEvent (), [this ](int i) {onGameTickEventCallback (i); });
32+ }
33+ else
34+ {
35+ gameTickEventCallback.reset ();
36+ }
37+
38+ }
39+ catch (HCMRuntimeException ex)
40+ {
41+ ex.prepend (" Force Future Checkpoint service encountered an error: " );
42+ runtimeExceptions->handleMessage (ex);
43+ }
44+ }
45+
46+ // runs every tick while armed, if current tick is the user-selected tick then disarm the service and force a checkpoint.
47+ std::unique_ptr<ScopedCallback<eventpp::CallbackList<void (int )>>> gameTickEventCallback;
48+ void onGameTickEventCallback (int tickCount)
49+ {
50+ try
51+ {
52+ lockOrThrow (settingsWeak, settings)
53+ if (tickCount == settings->forceFutureCheckpointTick ->GetValue ())
54+ { // current tick is the tick to fire the checkpoint!
55+
56+ // begin by disabling the toggle setting (which will disable this tick event callback)
57+ settings->forceFutureCheckpointToggle ->GetValueDisplay () = false ;
58+ settings->forceFutureCheckpointToggle ->UpdateValueWithInput ();
59+
60+ // force the checkpoint (fire the event; if it fails, not our problem)
61+ settings->forceCheckpointEvent ->operator ()();
62+ }
63+ }
64+ catch (HCMRuntimeException ex)
65+ {
66+ ex.prepend (" Force Future Checkpoint service encountered an error: " );
67+ runtimeExceptions->handleMessage (ex);
68+ }
69+ }
70+
71+
72+ // fill the which-tick-to-force-checkpoint-on with a value 5 seconds from the current game tick.
73+ ScopedCallback <ActionEvent> forceFutureCheckpointFillCallback;
74+ void onForceFutureCheckpointFill ()
75+ {
76+ PLOG_VERBOSE << " onForceFutureCheckpointFill" ;
77+ try
78+ {
79+ lockOrThrow (mccStateHookWeak, mccStateHook);
80+ if (mccStateHook->isGameCurrentlyPlaying (mGame ) == false ) return ;
81+
82+
83+ lockOrThrow (gameTickEventHookWeak, gameTickEventHook);
84+ int currentTick = gameTickEventHook->getCurrentGameTick ();
85+
86+ int ticksPerSecond = (mGame .operator GameState::Value () == GameState::Value::Halo1) ? 30 : 60 ;
87+ constexpr int secondsInTheFuture = 5 ;
88+
89+ int futureTick = currentTick + (ticksPerSecond * secondsInTheFuture);
90+
91+ lockOrThrow (settingsWeak, settings);
92+ settings->forceFutureCheckpointTick ->GetValueDisplay () = futureTick;
93+ settings->forceFutureCheckpointTick ->UpdateValueWithInput ();
94+ }
95+ catch (HCMRuntimeException ex)
96+ {
97+ ex.prepend (" Force Future Checkpoint service encountered an error: " );
98+ runtimeExceptions->handleMessage (ex);
99+ }
100+
101+ }
102+
103+
104+
105+
106+ public:
107+ ForceFutureCheckpointImpl (GameState game, IDIContainer& dicon)
108+ : mGame (game),
109+ forceFutureCheckpointToggleCallback (dicon.Resolve<SettingsStateAndEvents>().lock()->forceFutureCheckpointToggle->valueChangedEvent, [this](bool & n) { onForceFutureCheckpointToggle (n); }),
110+ forceFutureCheckpointFillCallback (dicon.Resolve<SettingsStateAndEvents>().lock()->forceFutureCheckpointFillEvent, [this]() { onForceFutureCheckpointFill (); }),
111+ mccStateHookWeak (dicon.Resolve<IMCCStateHook>()),
112+ messagesGUIWeak(dicon.Resolve<IMessagesGUI>()),
113+ runtimeExceptions(dicon.Resolve<RuntimeExceptionHandler>()),
114+ settingsWeak(dicon.Resolve<SettingsStateAndEvents>()),
115+ gameTickEventHookWeak(resolveDependentCheat(GameTickEventHook))
116+ {
117+
118+ }
119+
120+ };
121+
122+
123+
124+
125+ ForceFutureCheckpoint::ForceFutureCheckpoint (GameState gameImpl, IDIContainer& dicon)
126+ : pimpl(std::make_unique<ForceFutureCheckpointImpl>(gameImpl, dicon))
127+ {
128+ }
129+
130+ ForceFutureCheckpoint::~ForceFutureCheckpoint () = default ;
0 commit comments