66#include " Hooking.Stubs.h"
77#include " GamePrimitives.h"
88#include " scrEngine.h"
9+ #include < nutsnbolts.h>
10+ #include < DrawCommands.h>
911
1012enum ScriptImDrawType : uint32_t
1113{
@@ -28,6 +30,9 @@ struct ScriptImRequest
2830
2931static constexpr int kMaxScriptImRequests = 1024 ;
3032static std::vector<ScriptImRequest> g_scriptImRequests{};
33+ static std::vector<ScriptImRequest> g_scriptImRenderBuffer{};
34+
35+ static std::atomic<bool > g_scriptImReady{false };
3136
3237static ScriptImRequest** g_scriptImBuffer;
3338static uint16_t * g_scriptImEntriesCount;
@@ -43,20 +48,28 @@ static void RenderScriptIm()
4348 // The game never uses this buffer itself, but it *may* be changed in the future updates.
4449 // This code isn't ready for such a scenario, so might potentially require tweaks.
4550 // Like if something allocate script im buffer before us, we would need to resize it
46- // and not just rewrite everything without custom stuff.
47-
48- if (g_scriptImRequests.empty ())
51+ // and not just rewrite everything without custom stuff.
52+
53+ // Wait until the main thread is done for this frame before pushing new requests
54+ if (g_scriptImReady.load (std::memory_order_acquire))
55+ {
56+ g_scriptImRenderBuffer.clear ();
57+ std::swap (g_scriptImRequests, g_scriptImRenderBuffer);
58+ g_scriptImReady.store (false , std::memory_order_relaxed);
59+ }
60+
61+ if (g_scriptImRenderBuffer.empty ())
4962 {
5063 return ;
5164 }
5265
53- *g_scriptImEntriesCount = g_scriptImRequests .size ();
66+ *g_scriptImEntriesCount = g_scriptImRenderBuffer .size ();
5467
5568 // If the buffer isn't allocated, let's do it.
5669 if (!*g_scriptImBuffer)
5770 {
5871 initScriptImBuffer ();
59- }
72+ }
6073
6174 // Failed to allocate? Bail out.
6275 if (!*g_scriptImBuffer)
@@ -66,11 +79,9 @@ static void RenderScriptIm()
6679 }
6780
6881 // Move stuff from our temp vector to the in-game buffer.
69- std::move (g_scriptImRequests .begin (), g_scriptImRequests .end (), *g_scriptImBuffer);
82+ std::copy (g_scriptImRenderBuffer .begin (), g_scriptImRenderBuffer .end (), *g_scriptImBuffer);
7083
7184 g_origRenderScriptIm ();
72-
73- g_scriptImRequests.clear ();
7485 *g_scriptImEntriesCount = 0 ;
7586}
7687
@@ -90,8 +101,8 @@ struct DrawOriginStore
90101
91102static bool (*isGamePaused)();
92103
93- static int * g_frameDrawIndex1 ;
94- static int * g_frameDrawIndex2 ;
104+ static int * g_renderBufferIndex ;
105+ static int * g_updateBufferIndex ;
95106static DrawOriginStore* g_drawOriginStore;
96107static uint32_t * g_scriptDrawOriginIndex;
97108
@@ -124,8 +135,8 @@ static HookFunction hookFunction([]()
124135 {
125136 auto location = hook::get_pattern<char >(" 48 69 D0 10 04 00 00 48 8D 05 ? ? ? ? 48 03" );
126137
127- g_frameDrawIndex1 = hook::get_address<int *>(location - 20 );
128- g_frameDrawIndex2 = hook::get_address<int *>(location - 7 );
138+ g_renderBufferIndex = hook::get_address<int *>(location - 20 );
139+ g_updateBufferIndex = hook::get_address<int *>(location - 7 );
129140 g_drawOriginStore = hook::get_address<DrawOriginStore*>(location + 10 );
130141
131142 hook::set_call (&isGamePaused, location - 27 );
@@ -153,13 +164,22 @@ static HookFunction hookFunction([]()
153164
154165 g_screenWidth = hook::get_address<int *>(location + 2 );
155166 g_screenHeight = hook::get_address<int *>(location + 8 );
156- }
167+ }
168+
169+ OnMainGameFrame.Connect ([]()
170+ {
171+ g_scriptImRequests.clear ();
172+ g_scriptImReady.store (false , std::memory_order_relaxed);
173+ });
174+
175+ OnPostFrontendRender.Connect ([]()
176+ {
177+ g_scriptImReady.store (true , std::memory_order_release);
178+ });
157179
158180 fx::ScriptEngine::RegisterNativeHandler (" SET_DRAW_ORIGIN" , [](fx::ScriptContext& context)
159181 {
160- auto drawIndex = *(isGamePaused () ? g_frameDrawIndex2 : g_frameDrawIndex1);
161-
162- auto & store = g_drawOriginStore[drawIndex];
182+ auto & store = g_drawOriginStore[*g_renderBufferIndex];
163183 const auto index = store.m_count ;
164184
165185 if (index >= 32 )
0 commit comments