FiftyTifty Posted September 4, 2019 Share Posted September 4, 2019 Initially, I just wanted to patch the values for the GetHit imagespace modifier. Which I'm able to do, so there's no screen blurring when getting hit. Now, I want to skip the instructions that actually call that imagespace modifier. I found them in IDA, but NVSE won't let me patch them early enough in execution, so by the time they're changed, the engine has already done something with the instructions, so changing them this late in execution does nothing. Looked at iStewieAI's tweaks plugin, and I noticed that he uses several things. One, is that his early execution functions have the prefix __fastcall. Another, is that he uses a custom function called addDeferredInitHandler(). Lastly, he uses two other functions instead of SafeWrite(), which are WriteRelCall() and WriteRelJump(). But there's no documentation on how to use those. Here's the NVSEPlugin_Load() function: bool NVSEPlugin_Load(const NVSEInterface * nvse) { _MESSAGE("load"); g_pluginHandle = nvse->GetPluginHandle(); // save the NVSEinterface in cas we need it later SaveNVSE = (NVSEInterface *)nvse; // register to receive messages from NVSE NVSEMessagingInterface* msgIntfc = (NVSEMessagingInterface*)nvse->QueryInterface(kInterface_Messaging); msgIntfc->RegisterListener(g_pluginHandle, "NVSE", MessageHandler); g_msg = msgIntfc; g_script = (NVSEScriptInterface*)nvse->QueryInterface(kInterface_Script); //Begin addDeferredInitHandler(); PatchGetHitIMAD(); //End return true; } Here's my plugin's function: void __fastcall PatchGetHitIMAD() { //This function must be called at PreLoadGame() _MESSAGE("Starting"); addDeferredInitHandler(); //Address of near JNZ = 0046D7A4 SafeWrite8(0x46D7A4, 0xE9); SafeWrite8(0x46D7A5, 0xB6); SafeWrite8(0x46D7A6, 0x00); SafeWrite8(0x46D7A9, 0x90); } Original bytes: 0F 85 B5 00 00 00New bytes: E9 B6 00 00 90 What those new instructions do, is they change the JNZ (a two byte opcode) into JMP (one byte opcode) by replacing the first opcode, and changing the second byte into the offset. The third byte, the original offset, is turned into 00. And the last byte is changed into a NOP for good measure. While the instructions are patched in memory, after the engine's been started, they're no longer used so changing them does nothing to the game itself. Even with __fastcall and addDeferredInitHandler() being called in NVSEPlugin_Load(). The bytes changed, but the instructions are no longer referenced by the game engine. So how do I go about doing this? Link to comment Share on other sites More sharing options...
WarMachineDD7 Posted September 6, 2019 Share Posted September 6, 2019 (edited) Not much I can help with here, but maybe the Geck Extender github will help figuring out what those functions do: https://github.com/lStewieAl/Geck-Extender/blob/40182dde2675c0fbdb1079e4501b05141373460e/nvse/SafeWrite.cpp Edited September 6, 2019 by WarMachineDD7 Link to comment Share on other sites More sharing options...
FiftyTifty Posted September 6, 2019 Author Share Posted September 6, 2019 Oh my, I forgot to report back. So I patched the instructions of FalloutNV.exe directly, but that didn't make any difference whatsoever. So the instructions that actually apply the GetHit IMAD aren't readily available with IDA nor CheatEngine. I settled for just setting the duration of the imagespace modifier to 0, but I'd much rather have it never be called in the first place. That's a possible performance gain that we're missing out on. Link to comment Share on other sites More sharing options...
lStewieAl Posted September 6, 2019 Share Posted September 6, 2019 (edited) __fastcall is a calling convention in which the first two arguments to the function are passed in ECX and EDX registers. It has nothing to do with performance. The game uses the __thiscall convention in many places, in which the first argument is passed in ECX- in order to replace that call, you can create a class and have a member method as __thiscall, but itâs easier to just declare the function as fastcall and give a dummy argument for EDX. If youâre doing your patching in NVSEPlugin_Load, it is already being executed before any of the game is loaded. You likely wonât need a deferred initialisation. I use one because there are some things that I need to patch after the game has created all the singletons. Check that the code you are patching is definitely called (breakpoint it). WriteRelJump(x, y) and WriteRelCall(x, y) write in a long jmp or call instruction jumping/calling from address x to address y in memory. Edited September 6, 2019 by lStewieAl Link to comment Share on other sites More sharing options...
FiftyTifty Posted September 6, 2019 Author Share Posted September 6, 2019 __fastcall is a calling convention in which the first two arguments to the function are passed in ECX and EDX registers. It has nothing to do with performance.The game uses the __thiscall convention in many places, in which the first argument is passed in ECX- in order to replace that call, you can create a class and have a member method as __thiscall, but itâs easier to just declare the function as fastcall and give a dummy argument for EDX. If youâre doing your patching in NVSEPlugin_Load, it is already being executed before any of the game is loaded. You likely wonât need a deferred initialisation. I use one because there are some things that I need to patch after the game has created all the singletons. Check that the code you are patching is definitely called (breakpoint it). In performance, I meant that having the instructions which call the imagespace modifier skipped could bring about noticeable performance improvements in combat. And even after patching the executable directly, rather than waiting for any NVSE hooks, the instructions are completely ignored. Used IDA Pro 5.0 to find them. Loaded up FalloutNV.exe, found GetHit in the string list, found the instructions that use it, patched them, but no change in behaviour. Screenshot to demonstrate: https://i.imgur.com/NSNP04Y.png That's the only result I find for it. So the code that handles applying that imagespace modifier when the player takes damage must be elsewhere, and not as easy to locate. Good to know about the deferred initialization though. Link to comment Share on other sites More sharing options...
lStewieAl Posted September 6, 2019 Share Posted September 6, 2019 I doubt it will make any difference in performance, the game has far bigger problems. You could look for cross references (xrefs) to related gamesettings to help find the code you’re looking for. Link to comment Share on other sites More sharing options...
Recommended Posts