Skip to content

Commit 4813ebd

Browse files
author
berkelium
committed
extra-natives: add SET_VISUAL_SETTING_FLOAT(const char*, float) native for overriding visual settings
1 parent 557bc4f commit 4813ebd

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#include <StdInc.h>
2+
#include <Hooking.h>
3+
4+
#include <ScriptEngine.h>
5+
6+
#include <Resource.h>
7+
#include <fxScripting.h>
8+
9+
#include <nutsnbolts.h>
10+
11+
#include <atArray.h>
12+
13+
#include <concurrent_queue.h>
14+
15+
static concurrency::concurrent_queue<std::function<void()>> g_mainThreadQueue;
16+
17+
struct VisualSettingsEntry
18+
{
19+
uint32_t entryHash;
20+
float value;
21+
22+
inline bool operator<(const VisualSettingsEntry& right)
23+
{
24+
return (entryHash < right.entryHash);
25+
}
26+
};
27+
28+
struct VisualSettingsData
29+
{
30+
bool initialized;
31+
atArray<VisualSettingsEntry> entries;
32+
};
33+
34+
static VisualSettingsData* g_visualSettings;
35+
36+
static hook::cdecl_stub<void(void*)> _loadVisualSettings([]()
37+
{
38+
return hook::get_call(hook::get_pattern("48 83 25 ? ? ? ? 00 48 8D ? ? ? ? ? E8 ? ? ? ? E8", 15));
39+
});
40+
41+
static std::unordered_map<uint32_t, float> g_visualSettingsOverrides;
42+
43+
static bool(*g_origLoadVisualSettingsDat)(void* vsData, const char* filename);
44+
45+
static bool LoadVisualSettingsDatStub(void* vsData, const char* filename)
46+
{
47+
bool success = g_origLoadVisualSettingsDat(vsData, filename);
48+
49+
if (success)
50+
{
51+
for (auto& entry : g_visualSettingsOverrides)
52+
{
53+
bool found = false;
54+
55+
// TODO: binary search?
56+
for (auto& pair : g_visualSettings->entries)
57+
{
58+
if (pair.entryHash == entry.first)
59+
{
60+
pair.value = entry.second;
61+
62+
found = true;
63+
break;
64+
}
65+
}
66+
67+
if (!found)
68+
{
69+
VisualSettingsEntry val;
70+
val.entryHash = entry.first;
71+
val.value = entry.second;
72+
73+
g_visualSettings->entries.Set(g_visualSettings->entries.GetCount(), val);
74+
}
75+
}
76+
77+
std::sort(g_visualSettings->entries.begin(), g_visualSettings->entries.end());
78+
}
79+
80+
return success;
81+
}
82+
83+
static InitFunction initFunction([]()
84+
{
85+
fx::ScriptEngine::RegisterNativeHandler("SET_VISUAL_SETTING_FLOAT", [](fx::ScriptContext& context)
86+
{
87+
const char* name = context.CheckArgument<const char*>(0);
88+
float value = context.GetArgument<float>(1);
89+
90+
fx::OMPtr<IScriptRuntime> runtime;
91+
92+
if (FX_SUCCEEDED(fx::GetCurrentScriptRuntime(&runtime)))
93+
{
94+
fx::Resource* resource = reinterpret_cast<fx::Resource*>(runtime->GetParentObject());
95+
96+
auto keyHash = HashString(name);
97+
g_visualSettingsOverrides[keyHash] = value;
98+
99+
_loadVisualSettings(g_visualSettings);
100+
101+
resource->OnStop.Connect([keyHash]()
102+
{
103+
g_mainThreadQueue.push([keyHash]()
104+
{
105+
g_visualSettingsOverrides.erase(keyHash);
106+
107+
_loadVisualSettings(g_visualSettings);
108+
});
109+
});
110+
}
111+
});
112+
113+
OnMainGameFrame.Connect([=]()
114+
{
115+
std::function<void()> func;
116+
117+
while (g_mainThreadQueue.try_pop(func))
118+
{
119+
func();
120+
}
121+
});
122+
});
123+
124+
static HookFunction hookFunction([]()
125+
{
126+
g_visualSettings = hook::get_address<VisualSettingsData*>(hook::get_pattern("48 83 25 ? ? ? ? 00 48 8D ? ? ? ? ? E8 ? ? ? ? E8", 11));
127+
128+
{
129+
auto location = (char*)hook::get_call(hook::get_pattern("48 83 25 ? ? ? ? 00 48 8D ? ? ? ? ? E8 ? ? ? ? E8", 15));
130+
131+
hook::set_call(&g_origLoadVisualSettingsDat, location + 0x12);
132+
hook::call(location + 0x12, LoadVisualSettingsDatStub);
133+
}
134+
});

0 commit comments

Comments
 (0)