Skip to content

@Sewer56 Sewer56 released this Sep 18, 2018 · 4 commits to master since this release

Improvements

  • [Plugins] GameBanana Plugin now supports explicit statement of Item ID and Item Type allowing for redistribution of mods outside of GameBanana while retaining update support.

Other Changes

  • [Plugins] GameBanana and Github update plugins have now been enabled by default.
Assets 6

@Sewer56 Sewer56 released this Sep 15, 2018 · 9 commits to master since this release

Reloaded 2.0 | Scarlet Revolution



Table of Contents

Sorry for the links not working, Github doesn't support those in releases :/

Moving to Semantic Versioning

Admittedly since the very early days of Reloaded, my picking of version numbers was quite simply, bad. There really isn't much that I could have added back onto the last sentence.

With little experience of publishing larger software - I often found myself bumping the version of the project in irregular intervals; to the point where even version 1.0.0 was unfortunately not the first public-ready version, that was only really the case at around 1.0.3.

Even making things worse, not only did I often did not test NuGet package updates locally - due to a bug with PackageReference not updating local packages, I also thought that updating the versions of all my packages' with versions equal the mod loader every release was a good idea, terrible idea.

This can be seen this very instant - the latest and greatest stable version of libReloaded is err... a prerelease package: NuGet Versions

The New Format

Well, given the scale of this release - I decided that it is finally for the best to clean up this mess and start anew, only updating packages when they truly get updated and to make use of semantic versioning.

Basically to put it short, the format will still remain as X.Y.Z, e.g. 2.0.0 - but one thing will change. Rather than trying to make the mod loader signify progression; the individual components will be given a new meaning.

  • X (Major) version increment after incompatible API/library changes.
  • Y (Minor) version increment after new functionality in a backwards-compatible manner.
  • Z (Patch) version increment after backwards compatible bug fixes.

For the more complete explanation, feel free to read Semantic Versioning.

Notable Changes

Reloaded's New Plugin System

Yes
Oh pretty, divine colours.

Reloaded 2.0.0 includes a new, from the ground up plugin system designed to allow users to extend the functionality of both of Reloaded's Launcher and Loader.

As an example, with the plugin system a developer can perform many tasks:

  • Set the Reloaded-Loader parameters before an individual game is launched.
  • Execute code at various events such as Loader/Launcher launching, injecting DLLs.
  • Modify constants such the random messages shown below the Reloaded logo at the start of the loader.
  • Straight up replace/hook some Reloaded functions such as printing to console, printing banner.
  • Intercept the parsing of mod and game configurations onto the UI.

With the last one you can probably even integrate other mod loaders into Reloaded.

Aside from the rather charming example seen above, a more common or useful use of the plugin system can maybe be found directly below.

Mod update support for Github, GameBanana.

One of the additions into the newest version of Reloaded, that ships directly alongside the newly introduced plugin system is the newly gained ability to update individual mods from external sources on the internet.

Vroom Vroom!

One of the visible entries is not like the others.

Mod updates are automatically checked on launch of Reloaded Mod Loader and are done in fully asynchronous fashion - meaning that your launcher start up times are not impacted; enjoy!

The best of all; update is extensible via plugins. Want to add update support for another site? Write a simple plugin and you're done 👌.


Important Note:
For GameBanana mod update support, only mods downloaded through 1 click links using Reloaded 2.0.0 with plugin or newer will be supported. In addition, the GB 1 click link format will require to be changed to a new format incompatible with older Reloaded versions.

The link format will not change until a day after the release of 2.0.0 to allow other users to migrate.

Mod Configuration Changes

Support for Explicit DLL Names

Something that you may find more standard in other mod loaders, but not Reloaded, was the fact that till now - Reloaded assumed a standard set of DLL names, main32 for 32bit and main64 for 64bit.

And nothing was really wrong with that... except one thing... it makes life a bit more painful when you want to do DLL Exports as you'd have to do either of the following:

  • Get a list of all mods using Reloaded-IO and find a path to the other main32/main64.
  • Split mod with exports into two DLLs, one with different name and the actual exports.

That limit howevere was all but arbitrary; and I thought that it is perhaps time to lift that - and so; the new mod Config.json looks something more like this:

{
  "ModId": "",
  "ModName": "Modification Name Undefined",
  "ModDescription": "Modification Description Undefined",
  "ModVersion": "Undefined",
  "ModAuthor": "Undefined",
  "ModSite": "N/A",
  "ModSource": "N/A",
  "ConfigurationFile": "N/A",
  "DllFile32": "",
  "DllFile64": "",
  "Dependencies": []
}

Still fairly clean 😉, no more figuring out which main32.dll is which.

And now, this reduces the code of calling another Reloaded mod's dll export down to:

// This returns 0 if other dll is not loaded.
IntPtr dllHandle = Native.LoadLibraryW("otherReloadedDll"); 
IntPtr functionPointer = Native.GetProcAddress(dllHandle, "SomeFunction");

Done.

Autogeneration of Config.json Templates

When working with various mod loaders, one of the things you often ask yourself is "what the heck am I allowed to put in my config file!?". While Reloaded's wiki already is always ontop of the game, generally containing the latest templates in the tutorials; I still figured I could do something more.

As of Reloaded 2.0.0 - the launcher automatically exports various different configuration templates after it is installed, and before performing updates.

The templates are automatically exported to Reloaded-Mod-Loader\Reloaded-Config\Templates\Config and contain fresh, untouched config templates for items such as mods, games and plugins - complete with all of the fields.

Reloaded Assembler

It is no secret that Reloaded's X86/64 assembler is not the fastest thing alive; particularly due with the fact that individual mods cannot make use of it directly but have to communicate with it over the local computer.

The reason it has to communicate cross process over the local computer is unfortunately the sad truth that there does not exist a pure assembler which compiles to both 32 and 64bit machines (and can be ported to C#).

Because of this; during all this time, Reloaded has actually been using its own solution around the problem, the "Reloaded-Assembler". Reloaded-Assembler takes the fantastic FASM wrapper named FASM.NET and introduces it to the world (of your local computer) by adding full networking support to allow the remote compilation of assembler code.

With the use of some magic, it's even embedded in libReloaded and will self-extract and run if an instance is not already present.

Speeding up the Assembler.

Well, at one point I found that the setup time of my projects - TONER took longer than I initially. Eventually the startup time bottleneck has narrowed down to Reloaded's own function hook creation code which took over 100ms to complete, add 10+ hooks in a row, ouch!

While the hooking code for Reloaded is very advanced and powerful - I still found such performance figure unacceptable for my own liking, even if function hook creation is a one-time thing; so I took in pursuit to find the bottleneck... It didn't take long to identify the huge bottleneck of Reloaded Assembler - namely the networking component.

Therefore I have managed to implement two optimizations into the assembler to try work around the overhead of the networking component:

  • Increase the polling/check rate of the assembler.
  • Use unsynced events in the networking library for real-time message processing.
  • Explicitly flushing messages right after they are sent.
  • Skip the networked assembler altogether and use FASM.NET in X86.

Now to illustrate.

[Before] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 64ms
X86-64 64ms

Note: The average/realistic case would be around 32ms.

[After] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 0ms
X86-64 <4ms

Needless to say, in X86 the time taken to set up a function hook sliced, to less than 50ms by this change.

MemoryBufferManager Caching.

Since I have already fixed the main bottleneck of the hooking code; why shouldn't I just as well fix the secondary bottleneck?

And well, that bottleneck is MemoryBuffer, the implementation of Reloaded allocated memory that can be shared between different mods. This is primarily used for pointer storage in hook functions as well as permanent storage of data.

The bottleneck?
I simply forgot to cache the individual found buffers between different add operations; job done.

This has caused a further reduction of average X86 hook times from <50ms (after assembler patch) to 2ms.

All bottlenecks gone, at least in X86.

New ways to launch games.

One annoying aspect of Reloaded for some people may be the fact that due to Reloaded's nature of being a DLL injection based mod loader; the actual mod loader must initiate the game loading sequence.

As of Reloaded 2.0.0; some attempt is made to levy the situation. Two new features - one to create a shortcut for launching a game through Reloaded, and the other that can spoof/pretend to be a game launcher.

Both under the hood this uses with a new commandline switch for Reloaded-Launcher, --launch. This accepts a directory location containing a game profile and any extra additional arguments and passes it onto the loader directly.

Direct Shortcuts to Launch Games

Plain and simple. Press the button, get a shortcut on the desktop, doubleclick and the game runs through Reloaded.

Launcher Pretendo

You can read more about this one in one of Reloaded's Readme pages.

Basically, Reloaded now has its own launcher-spoofer executable that can replace any other game's launcher. The way it works; click the Generate Launcher button, paste over another game's launcher and just ensure that the individual executables the game's regular launcher woould typically run have their own game profiles in Reloaded. Done.

Oh, and you can also use it in place of a game executable to stop the "Steam Reattaching" business if you want, more on that in the readme pages.

Optimize X64 Loader Startup Times

GIF

Top right is before, bottom right is after.

The optimization comes in the form of changing how the check whether a game or process is X64 is performed. Before, the loader would run the game or process and ask the Windows API whether the process is running in Windows on Windows 64 (WOW64) mode.

Now, Reloaded's loader no longer performs this check, and instead immediately, as soon as the arguments are parsed and game profile read, instead opens a file in a stream and reads the architecture type from the PE header of the executable; no need to load the process anymore and then kill it if it's X64.

Reimplement Auto Attach

Auto attach

One of the features that was present in very, very early versions of Reloaded was the feature to wait for a process to start and automatically attach.

Well, for a reason I do not remember anymore, this feature was cut at some point... Why? I do not remember, however it is back.

libReloaded - Pointers to C# functions.

For a while, the functionality for creating pointers to C# functions has pretty much existed inside Reloaded's main library. After all, function hooks depend on it, don't they? ... Except that there was one caveat - it was all part of the hooking code and never exposed public.

Well, that functionality has been forked from the hook code and split into separate classes, ReverseFunctionWrapper and X64ReverseFunctionWrapper respectively.

Below is an example from Reloaded's Quick Tour on creating a pointer to a C# function.
The catch? None. Here's an example to a pointer of a C# "fastcall" function:

// Define a fastcall Reloaded function.
// Microsoft Fastcall passes first two parameters in registers ECX, EDX and returns value in EAX.
[ReloadedFunction(CallingConventions.Fastcall)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FastcallExample(int a, int b, int c);

/* Fields */
private static ReverseFunctionWrapper<FastcallExample> reverseFunctionWrapper;  // Pointer to C# Fastcall function.
private static FastcallExample                         functionWrapper;         // We will call our C# function through the pointer to prove.

/* Main/Init Method */
void FastcallCSharpFunctionPointerTest()
{
    // Create our pointer to our C# "fastcall" function.
    // reverseFunctionWrapper.Pointer now has the address of the C# function, that's fastcall.
    reverseFunctionWrapper = ReverseFunctionWrapper<FastcallExample>.CreateReverseWrapper(CSharpFastcallFunction);

    // To prove our C# "fastcall" function works, let's just call it like a native function.
    functionWrapper = FunctionWrapper.CreateWrapperFunction<FastcallExample>((long)reverseFunctionWrapper.Pointer);
    functionWrapper(1,2,3);
}


/* Function Implementation */

/// <summary>
/// When called through the address in reverseFunctionWrapper.Pointer,
/// this function is now a "fastcall" function.
/// </summary>
/// <param name="a">This number is passed into ECX!</param>
/// <param name="b">This number is passed into EDX!</param>
/// <param name="c">This number is on the stack.</param>
private static void CSharpFastcallFunction(int a, int b, int c)
{
    MessageBox.Show($"{a + b + c}");
}

All those wonderful docs.

What can I say? Documentation, Documentation, Documentation.

Now there's plenty more of it, last time around half of these pages did not exist.

Other Changes

libReloaded - Overlays

All backends

The code that has previously handled the frame pacing and framerate limiting has been entirely changed and rewritten from scratch. The previous, not as well thought out code from my earlier days of programming simply did not do frame timing correctly and put too much reliance on sleeping the thread.

The new framerate class consists of many wonderful bells and whistles:

  • Estimate the potential FPS if limiter disabled when the limiter is enabled.
  • Providing statistics such as the render time and sleep time until the next frame.
  • Timing accurate down to the highest frequency available for sleeping.

Remove Known Instances of Potentially Intrusive Open File Handles

Haha yes

Haha, yes, what is there to say? This is everyone's favourite dialog after all.
Well, some changes have been done behind the scenes; including less conventional image loading methods.

Rest assured, you can now delete banner images and a few others even when in use.
As for replacing... you were able to do that already 😊.

Pattern Scanner Performance Improvements

The internal logic of the pattern scanner has been changed from pass by value to pass by reference;

// Before
public static IntPtr FindPattern(byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }
// After
public static IntPtr FindPattern(ref byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }

This will greatly improve performance when passing in large byte arrays into the pattern scanner. You'll never know when someone will try to scan a large executable with it.

Of course for compatibility reasons; the old overload still exists.

Reloaded-GUI

Borderless Resizing

Reloaded's GUI got a new ability to resize the window, with or without the involvement of a visible window border (border is optional).

While this feature is not implemented anywhere as of yet, here is how it would look like.

A cancelled Reloaded theme/design for Heroes Power Plant.

Recursive Control Theming

Another feature that Reloaded's GUI has gained over the course of time is the recursive Windows Forms control theming of controls which feature child controls. Unfortunately, due to also having been implemented in the Heroes Power Plant reskin, and being currently unused - a visual representation of the changes has been lost.

However to put it simply, Reloaded's GUI can now have a panel in a panel in a panel in a panel and the controls/buttons/elements inside that panel would still be automatically themed.

Reloaded-Input

A bit of refactoring has been performed, cleaning up the existing code as it was a very, very long time since it was last touched. A bit of the code has been slightly changed for consistency and some monolithic classes were made less monolithic.

This shouldn't break any existing applications, much - but some class named will need adjustment; here is an example.

// Before
ControllerCommon.ControllerInputs inputs = controllerManager.GetInput(controllerPort);
// After
ControllerInputs inputs = controllerManager.GetInput(controllerPort);

Bug Fixes

Same-Game dependencies not updated in the GUI.


If I hit yes, one of these mods, which is in the same mod list would not be checked enabled in the mod list.
Whoops!

A bug has been reported recently where if a mod depends on another mod, and the user chooses to enable dependencies; the dependency would not be updated as enabled in the mod list menu. This has been fixed.

Steam API Hook

Reloaded Samples now includes a new sample mod that hooks the Steam API and lets you run a game without it restarting itself.

Whether it will work and not crash your game depends on a game by game basis; specifically how much of the API the individual game uses.

Assets 5
Sep 15, 2018
[Plugins] Fix plugin compile path.

@Sewer56 Sewer56 released this Sep 8, 2018 · 18 commits to master since this release

Reloaded 2.0 | Scarlet Revolution



Table of Contents

Sorry for the links not working, Github doesn't support those in releases :/

Moving to Semantic Versioning

Admittedly since the very early days of Reloaded, my picking of version numbers was quite simply, bad. There really isn't much that I could have added back onto the last sentence.

With little experience of publishing larger software - I often found myself bumping the version of the project in irregular intervals; to the point where even version 1.0.0 was unfortunately not the first public-ready version, that was only really the case at around 1.0.3.

Even making things worse, not only did I often did not test NuGet package updates locally - due to a bug with PackageReference not updating local packages, I also thought that updating the versions of all my packages' with versions equal the mod loader every release was a good idea, terrible idea.

This can be seen this very instant - the latest and greatest stable version of libReloaded is err... a prerelease package: NuGet Versions

The New Format

Well, given the scale of this release - I decided that it is finally for the best to clean up this mess and start anew, only updating packages when they truly get updated and to make use of semantic versioning.

Basically to put it short, the format will still remain as X.Y.Z, e.g. 2.0.0 - but one thing will change. Rather than trying to make the mod loader signify progression; the individual components will be given a new meaning.

  • X (Major) version increment after incompatible API/library changes.
  • Y (Minor) version increment after new functionality in a backwards-compatible manner.
  • Z (Patch) version increment after backwards compatible bug fixes.

For the more complete explanation, feel free to read Semantic Versioning.

Notable Changes

Reloaded's New Plugin System

Yes
Oh pretty, divine colours.

Reloaded 2.0.0 includes a new, from the ground up plugin system designed to allow users to extend the functionality of both of Reloaded's Launcher and Loader.

As an example, with the plugin system a developer can perform many tasks:

  • Set the Reloaded-Loader parameters before an individual game is launched.
  • Execute code at various events such as Loader/Launcher launching, injecting DLLs.
  • Modify constants such the random messages shown below the Reloaded logo at the start of the loader.
  • Straight up replace/hook some Reloaded functions such as printing to console, printing banner.
  • Intercept the parsing of mod and game configurations onto the UI.

With the last one you can probably even integrate other mod loaders into Reloaded.

Aside from the rather charming example seen above, a more common or useful use of the plugin system can maybe be found directly below.

Mod update support for Github, GameBanana.

One of the additions into the newest version of Reloaded, that ships directly alongside the newly introduced plugin system is the newly gained ability to update individual mods from external sources on the internet.

Vroom Vroom!

One of the visible entries is not like the others.

Mod updates are automatically checked on launch of Reloaded Mod Loader and are done in fully asynchronous fashion - meaning that your launcher start up times are not impacted; enjoy!

The best of all; update is extensible via plugins. Want to add update support for another site? Write a simple plugin and you're done 👌.


Important Note:
For GameBanana mod update support, only mods downloaded through 1 click links using Reloaded 2.0.0 with plugin or newer will be supported. In addition, the GB 1 click link format will require to be changed to a new format incompatible with older Reloaded versions.

The link format will not change until a day after the release of 2.0.0 to allow other users to migrate.

Mod Configuration Changes

Support for Explicit DLL Names

Something that you may find more standard in other mod loaders, but not Reloaded, was the fact that till now - Reloaded assumed a standard set of DLL names, main32 for 32bit and main64 for 64bit.

And nothing was really wrong with that... except one thing... it makes life a bit more painful when you want to do DLL Exports as you'd have to do either of the following:

  • Get a list of all mods using Reloaded-IO and find a path to the other main32/main64.
  • Split mod with exports into two DLLs, one with different name and the actual exports.

That limit howevere was all but arbitrary; and I thought that it is perhaps time to lift that - and so; the new mod Config.json looks something more like this:

{
  "ModId": "",
  "ModName": "Modification Name Undefined",
  "ModDescription": "Modification Description Undefined",
  "ModVersion": "Undefined",
  "ModAuthor": "Undefined",
  "ModSite": "N/A",
  "ModSource": "N/A",
  "ConfigurationFile": "N/A",
  "DllFile32": "",
  "DllFile64": "",
  "Dependencies": []
}

Still fairly clean 😉, no more figuring out which main32.dll is which.

And now, this reduces the code of calling another Reloaded mod's dll export down to:

// This returns 0 if other dll is not loaded.
IntPtr dllHandle = Native.LoadLibraryW("otherReloadedDll"); 
IntPtr functionPointer = Native.GetProcAddress(dllHandle, "SomeFunction");

Done.

Autogeneration of Config.json Templates

When working with various mod loaders, one of the things you often ask yourself is "what the heck am I allowed to put in my config file!?". While Reloaded's wiki already is always ontop of the game, generally containing the latest templates in the tutorials; I still figured I could do something more.

As of Reloaded 2.0.0 - the launcher automatically exports various different configuration templates after it is installed, and before performing updates.

The templates are automatically exported to Reloaded-Mod-Loader\Reloaded-Config\Templates\Config and contain fresh, untouched config templates for items such as mods, games and plugins - complete with all of the fields.

Reloaded Assembler

It is no secret that Reloaded's X86/64 assembler is not the fastest thing alive; particularly due with the fact that individual mods cannot make use of it directly but have to communicate with it over the local computer.

The reason it has to communicate cross process over the local computer is unfortunately the sad truth that there does not exist a pure assembler which compiles to both 32 and 64bit machines (and can be ported to C#).

Because of this; during all this time, Reloaded has actually been using its own solution around the problem, the "Reloaded-Assembler". Reloaded-Assembler takes the fantastic FASM wrapper named FASM.NET and introduces it to the world (of your local computer) by adding full networking support to allow the remote compilation of assembler code.

With the use of some magic, it's even embedded in libReloaded and will self-extract and run if an instance is not already present.

Speeding up the Assembler.

Well, at one point I found that the setup time of my projects - TONER took longer than I initially. Eventually the startup time bottleneck has narrowed down to Reloaded's own function hook creation code which took over 100ms to complete, add 10+ hooks in a row, ouch!

While the hooking code for Reloaded is very advanced and powerful - I still found such performance figure unacceptable for my own liking, even if function hook creation is a one-time thing; so I took in pursuit to find the bottleneck... It didn't take long to identify the huge bottleneck of Reloaded Assembler - namely the networking component.

Therefore I have managed to implement two optimizations into the assembler to try work around the overhead of the networking component:

  • Increase the polling/check rate of the assembler.
  • Skip the networked assembler altogether and use FASM.NET in X86.

Now to illustrate.

[Before] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 32ms
X86-64 32ms

[After] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 0ms
X86-64 4ms

Needless to say, in X86 the time taken to set up a function hook sliced, to less than 50ms by this change.

MemoryBufferManager Caching.

Since I have already fixed the main bottleneck of the hooking code; why shouldn't I just as well fix the secondary bottleneck?

And well, that bottleneck is MemoryBuffer, the implementation of Reloaded allocated memory that can be shared between different mods. This is primarily used for pointer storage in hook functions as well as permanent storage of data.

The bottleneck?
I simply forgot to cache the individual found buffers between different add operations; job done.

This has caused a further reduction of average X86 hook times from <50ms (after assembler patch) to 2ms.

All bottlenecks gone, at least in X86.

New ways to launch games.

One annoying aspect of Reloaded for some people may be the fact that due to Reloaded's nature of being a DLL injection based mod loader; the actual mod loader must initiate the game loading sequence.

As of Reloaded 2.0.0; some attempt is made to levy the situation. Two new features - one to create a shortcut for launching a game through Reloaded, and the other that can spoof/pretend to be a game launcher.

Both under the hood this uses with a new commandline switch for Reloaded-Launcher, --launch. This accepts a directory location containing a game profile and any extra additional arguments and passes it onto the loader directly.

Direct Shortcuts to Launch Games

Plain and simple. Press the button, get a shortcut on the desktop, doubleclick and the game runs through Reloaded.

Launcher Pretendo

You can read more about this one in one of Reloaded's Readme pages.

Basically, Reloaded now has its own launcher-spoofer executable that can replace any other game's launcher. The way it works; click the Generate Launcher button, paste over another game's launcher and just ensure that the individual executables the game's regular launcher woould typically run have their own game profiles in Reloaded. Done.

Oh, and you can also use it in place of a game executable to stop the "Steam Reattaching" business if you want, more on that in the readme pages.

Optimize X64 Loader Startup Times

GIF

Top right is before, bottom right is after.

The optimization comes in the form of changing how the check whether a game or process is X64 is performed. Before, the loader would run the game or process and ask the Windows API whether the process is running in Windows on Windows 64 (WOW64) mode.

Now, Reloaded's loader no longer performs this check, and instead immediately, as soon as the arguments are parsed and game profile read, instead opens a file in a stream and reads the architecture type from the PE header of the executable; no need to load the process anymore and then kill it if it's X64.

Reimplement Auto Attach

Auto attach

One of the features that was present in very, very early versions of Reloaded was the feature to wait for a process to start and automatically attach.

Well, for a reason I do not remember anymore, this feature was cut at some point... Why? I do not remember, however it is back.

libReloaded - Pointers to C# functions.

For a while, the functionality for creating pointers to C# functions has pretty much existed inside Reloaded's main library. After all, function hooks depend on it, don't they? ... Except that there was one caveat - it was all part of the hooking code and never exposed public.

Well, that functionality has been forked from the hook code and split into separate classes, ReverseFunctionWrapper and X64ReverseFunctionWrapper respectively.

Below is an example from Reloaded's Quick Tour on creating a pointer to a C# function.
The catch? None. Here's an example to a pointer of a C# "fastcall" function:

// Define a fastcall Reloaded function.
// Microsoft Fastcall passes first two parameters in registers ECX, EDX and returns value in EAX.
[ReloadedFunction(CallingConventions.Fastcall)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FastcallExample(int a, int b, int c);

/* Fields */
private static ReverseFunctionWrapper<FastcallExample> reverseFunctionWrapper;  // Pointer to C# Fastcall function.
private static FastcallExample                         functionWrapper;         // We will call our C# function through the pointer to prove.

/* Main/Init Method */
void FastcallCSharpFunctionPointerTest()
{
    // Create our pointer to our C# "fastcall" function.
    // reverseFunctionWrapper.Pointer now has the address of the C# function, that's fastcall.
    reverseFunctionWrapper = ReverseFunctionWrapper<FastcallExample>.CreateReverseWrapper(CSharpFastcallFunction);

    // To prove our C# "fastcall" function works, let's just call it like a native function.
    functionWrapper = FunctionWrapper.CreateWrapperFunction<FastcallExample>((long)reverseFunctionWrapper.Pointer);
    functionWrapper(1,2,3);
}


/* Function Implementation */

/// <summary>
/// When called through the address in reverseFunctionWrapper.Pointer,
/// this function is now a "fastcall" function.
/// </summary>
/// <param name="a">This number is passed into ECX!</param>
/// <param name="b">This number is passed into EDX!</param>
/// <param name="c">This number is on the stack.</param>
private static void CSharpFastcallFunction(int a, int b, int c)
{
    MessageBox.Show($"{a + b + c}");
}

All those wonderful docs.

What can I say? Documentation, Documentation, Documentation.

Now there's plenty more of it, last time around half of these pages did not exist.

Other Changes

libReloaded - Overlays

All backends

The code that has previously handled the frame pacing and framerate limiting has been entirely changed and rewritten from scratch. The previous, not as well thought out code from my earlier days of programming simply did not do frame timing correctly and put too much reliance on sleeping the thread.

The new framerate class consists of many wonderful bells and whistles:

  • Estimate the potential FPS if limiter disabled when the limiter is enabled.
  • Providing statistics such as the render time and sleep time until the next frame.
  • Timing accurate down to the highest frequency available for sleeping.

Remove Known Instances of Potentially Intrusive Open File Handles

Haha yes

Haha, yes, what is there to say? This is everyone's favourite dialog after all.
Well, some changes have been done behind the scenes; including less conventional image loading methods.

Rest assured, you can now delete banner images and a few others even when in use.
As for replacing... you were able to do that already 😊.

Pattern Scanner Performance Improvements

The internal logic of the pattern scanner has been changed from pass by value to pass by reference;

// Before
public static IntPtr FindPattern(byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }
// After
public static IntPtr FindPattern(ref byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }

This will greatly improve performance when passing in large byte arrays into the pattern scanner. You'll never know when someone will try to scan a large executable with it.

Of course for compatibility reasons; the old overload still exists.

Reloaded-GUI

Borderless Resizing

Reloaded's GUI got a new ability to resize the window, with or without the involvement of a visible window border (border is optional).

While this feature is not implemented anywhere as of yet, here is how it would look like.

A cancelled Reloaded theme/design for Heroes Power Plant.

Recursive Control Theming

Another feature that Reloaded's GUI has gained over the course of time is the recursive Windows Forms control theming of controls which feature child controls. Unfortunately, due to also having been implemented in the Heroes Power Plant reskin, and being currently unused - a visual representation of the changes has been lost.

However to put it simply, Reloaded's GUI can now have a panel in a panel in a panel in a panel and the controls/buttons/elements inside that panel would still be automatically themed.

Reloaded-Input

A bit of refactoring has been performed, cleaning up the existing code as it was a very, very long time since it was last touched. A bit of the code has been slightly changed for consistency and some monolithic classes were made less monolithic.

This shouldn't break any existing applications, much - but some class named will need adjustment; here is an example.

// Before
ControllerCommon.ControllerInputs inputs = controllerManager.GetInput(controllerPort);
// After
ControllerInputs inputs = controllerManager.GetInput(controllerPort);

Bug Fixes

Same-Game dependencies not updated in the GUI.


If I hit yes, one of these mods, which is in the same mod list would not be checked enabled in the mod list.
Whoops!

A bug has been reported recently where if a mod depends on another mod, and the user chooses to enable dependencies; the dependency would not be updated as enabled in the mod list menu. This has been fixed.

Steam API Hook

Reloaded Samples now includes a new sample mod that hooks the Steam API and lets you run a game without it restarting itself.

Whether it will work and not crash your game depends on a game by game basis; specifically how much of the API the individual game uses.

Assets 6
Pre-release

@Sewer56 Sewer56 released this Sep 8, 2018 · 19 commits to master since this release

Reloaded 2.0 | Scarlet Revolution



Table of Contents

Sorry for the links not working, Github doesn't support those in releases :/

Moving to Semantic Versioning

Admittedly since the very early days of Reloaded, my picking of version numbers was quite simply, bad. There really isn't much that I could have added back onto the last sentence.

With little experience of publishing larger software - I often found myself bumping the version of the project in irregular intervals; to the point where even version 1.0.0 was unfortunately not the first public-ready version, that was only really the case at around 1.0.3.

Even making things worse, not only did I often did not test NuGet package updates locally - due to a bug with PackageReference not updating local packages, I also thought that updating the versions of all my packages' with versions equal the mod loader every release was a good idea, terrible idea.

This can be seen this very instant - the latest and greatest stable version of libReloaded is err... a prerelease package: NuGet Versions

The New Format

Well, given the scale of this release - I decided that it is finally for the best to clean up this mess and start anew, only updating packages when they truly get updated and to make use of semantic versioning.

Basically to put it short, the format will still remain as X.Y.Z, e.g. 2.0.0 - but one thing will change. Rather than trying to make the mod loader signify progression; the individual components will be given a new meaning.

  • X (Major) version increment after incompatible API/library changes.
  • Y (Minor) version increment after new functionality in a backwards-compatible manner.
  • Z (Patch) version increment after backwards compatible bug fixes.

For the more complete explanation, feel free to read Semantic Versioning.

Notable Changes

Reloaded's New Plugin System

Yes
Oh pretty, divine colours.

Reloaded 2.0.0 includes a new, from the ground up plugin system designed to allow users to extend the functionality of both of Reloaded's Launcher and Loader.

As an example, with the plugin system a developer can perform many tasks:

  • Set the Reloaded-Loader parameters before an individual game is launched.
  • Execute code at various events such as Loader/Launcher launching, injecting DLLs.
  • Modify constants such the random messages shown below the Reloaded logo at the start of the loader.
  • Straight up replace/hook some Reloaded functions such as printing to console, printing banner.
  • Intercept the parsing of mod and game configurations onto the UI.

With the last one you can probably even integrate other mod loaders into Reloaded.

Aside from the rather charming example seen above, a more common or useful use of the plugin system can maybe be found directly below.

Mod update support for Github, GameBanana.

One of the additions into the newest version of Reloaded, that ships directly alongside the newly introduced plugin system is the newly gained ability to update individual mods from external sources on the internet.

Vroom Vroom!

One of the visible entries is not like the others.

Mod updates are automatically checked on launch of Reloaded Mod Loader and are done in fully asynchronous fashion - meaning that your launcher start up times are not impacted; enjoy!

The best of all; update is extensible via plugins. Want to add update support for another site? Write a simple plugin and you're done 👌.


Important Note:
For GameBanana mod update support, only mods downloaded through 1 click links using Reloaded 2.0.0 with plugin or newer will be supported. In addition, the GB 1 click link format will require to be changed to a new format incompatible with older Reloaded versions.

The link format will not change until a day after the release of 2.0.0 to allow other users to migrate.

Mod Configuration Changes

Support for Explicit DLL Names

Something that you may find more standard in other mod loaders, but not Reloaded, was the fact that till now - Reloaded assumed a standard set of DLL names, main32 for 32bit and main64 for 64bit.

And nothing was really wrong with that... except one thing... it makes life a bit more painful when you want to do DLL Exports as you'd have to do either of the following:

  • Get a list of all mods using Reloaded-IO and find a path to the other main32/main64.
  • Split mod with exports into two DLLs, one with different name and the actual exports.

That limit howevere was all but arbitrary; and I thought that it is perhaps time to lift that - and so; the new mod Config.json looks something more like this:

{
  "ModId": "",
  "ModName": "Modification Name Undefined",
  "ModDescription": "Modification Description Undefined",
  "ModVersion": "Undefined",
  "ModAuthor": "Undefined",
  "ModSite": "N/A",
  "ModSource": "N/A",
  "ConfigurationFile": "N/A",
  "DllFile32": "",
  "DllFile64": "",
  "Dependencies": []
}

Still fairly clean 😉, no more figuring out which main32.dll is which.

And now, this reduces the code of calling another Reloaded mod's dll export down to:

// This returns 0 if other dll is not loaded.
IntPtr dllHandle = Native.LoadLibraryW("otherReloadedDll"); 
IntPtr functionPointer = Native.GetProcAddress(dllHandle, "SomeFunction");

Done.

Autogeneration of Config.json Templates

When working with various mod loaders, one of the things you often ask yourself is "what the heck am I allowed to put in my config file!?". While Reloaded's wiki already is always ontop of the game, generally containing the latest templates in the tutorials; I still figured I could do something more.

As of Reloaded 2.0.0 - the launcher automatically exports various different configuration templates after it is installed, and before performing updates.

The templates are automatically exported to Reloaded-Mod-Loader\Reloaded-Config\Templates\Config and contain fresh, untouched config templates for items such as mods, games and plugins - complete with all of the fields.

Reloaded Assembler

It is no secret that Reloaded's X86/64 assembler is not the fastest thing alive; particularly due with the fact that individual mods cannot make use of it directly but have to communicate with it over the local computer.

The reason it has to communicate cross process over the local computer is unfortunately the sad truth that there does not exist a pure assembler which compiles to both 32 and 64bit machines (and can be ported to C#).

Because of this; during all this time, Reloaded has actually been using its own solution around the problem, the "Reloaded-Assembler". Reloaded-Assembler takes the fantastic FASM wrapper named FASM.NET and introduces it to the world (of your local computer) by adding full networking support to allow the remote compilation of assembler code.

With the use of some magic, it's even embedded in libReloaded and will self-extract and run if an instance is not already present.

Speeding up the Assembler.

Well, at one point I found that the setup time of my projects - TONER took longer than I initially. Eventually the startup time bottleneck has narrowed down to Reloaded's own function hook creation code which took over 100ms to complete, add 10+ hooks in a row, ouch!

While the hooking code for Reloaded is very advanced and powerful - I still found such performance figure unacceptable for my own liking, even if function hook creation is a one-time thing; so I took in pursuit to find the bottleneck... It didn't take long to identify the huge bottleneck of Reloaded Assembler - namely the networking component.

Therefore I have managed to implement two optimizations into the assembler to try work around the overhead of the networking component:

  • Increase the polling/check rate of the assembler.
  • Skip the networked assembler altogether and use FASM.NET in X86.

Now to illustrate.

[Before] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 32ms
X86-64 32ms

[After] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 0ms
X86-64 4ms

Needless to say, in X86 the time taken to set up a function hook sliced, to less than 50ms by this change.

MemoryBufferManager Caching.

Since I have already fixed the main bottleneck of the hooking code; why shouldn't I just as well fix the secondary bottleneck?

And well, that bottleneck is MemoryBuffer, the implementation of Reloaded allocated memory that can be shared between different mods. This is primarily used for pointer storage in hook functions as well as permanent storage of data.

The bottleneck?
I simply forgot to cache the individual found buffers between different add operations; job done.

This has caused a further reduction of average X86 hook times from <50ms (after assembler patch) to 2ms.

All bottlenecks gone, at least in X86.

New ways to launch games.

One annoying aspect of Reloaded for some people may be the fact that due to Reloaded's nature of being a DLL injection based mod loader; the actual mod loader must initiate the game loading sequence.

As of Reloaded 2.0.0; some attempt is made to levy the situation. Two new features - one to create a shortcut for launching a game through Reloaded, and the other that can spoof/pretend to be a game launcher.

Both under the hood this uses with a new commandline switch for Reloaded-Launcher, --launch. This accepts a directory location containing a game profile and any extra additional arguments and passes it onto the loader directly.

Direct Shortcuts to Launch Games

Plain and simple. Press the button, get a shortcut on the desktop, doubleclick and the game runs through Reloaded.

Launcher Pretendo

You can read more about this one in one of Reloaded's Readme pages.

Basically, Reloaded now has its own launcher-spoofer executable that can replace any other game's launcher. The way it works; click the Generate Launcher button, paste over another game's launcher and just ensure that the individual executables the game's regular launcher woould typically run have their own game profiles in Reloaded. Done.

Oh, and you can also use it in place of a game executable to stop the "Steam Reattaching" business if you want, more on that in the readme pages.

Optimize X64 Loader Startup Times

GIF

Top right is before, bottom right is after.

The optimization comes in the form of changing how the check whether a game or process is X64 is performed. Before, the loader would run the game or process and ask the Windows API whether the process is running in Windows on Windows 64 (WOW64) mode.

Now, Reloaded's loader no longer performs this check, and instead immediately, as soon as the arguments are parsed and game profile read, instead opens a file in a stream and reads the architecture type from the PE header of the executable; no need to load the process anymore and then kill it if it's X64.

Reimplement Auto Attach

Auto attach

One of the features that was present in very, very early versions of Reloaded was the feature to wait for a process to start and automatically attach.

Well, for a reason I do not remember anymore, this feature was cut at some point... Why? I do not remember, however it is back.

libReloaded - Pointers to C# functions.

For a while, the functionality for creating pointers to C# functions has pretty much existed inside Reloaded's main library. After all, function hooks depend on it, don't they? ... Except that there was one caveat - it was all part of the hooking code and never exposed public.

Well, that functionality has been forked from the hook code and split into separate classes, ReverseFunctionWrapper and X64ReverseFunctionWrapper respectively.

Below is an example from Reloaded's Quick Tour on creating a pointer to a C# function.
The catch? None. Here's an example to a pointer of a C# "fastcall" function:

// Define a fastcall Reloaded function.
// Microsoft Fastcall passes first two parameters in registers ECX, EDX and returns value in EAX.
[ReloadedFunction(CallingConventions.Fastcall)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FastcallExample(int a, int b, int c);

/* Fields */
private static ReverseFunctionWrapper<FastcallExample> reverseFunctionWrapper;  // Pointer to C# Fastcall function.
private static FastcallExample                         functionWrapper;         // We will call our C# function through the pointer to prove.

/* Main/Init Method */
void FastcallCSharpFunctionPointerTest()
{
    // Create our pointer to our C# "fastcall" function.
    // reverseFunctionWrapper.Pointer now has the address of the C# function, that's fastcall.
    reverseFunctionWrapper = ReverseFunctionWrapper<FastcallExample>.CreateReverseWrapper(CSharpFastcallFunction);

    // To prove our C# "fastcall" function works, let's just call it like a native function.
    functionWrapper = FunctionWrapper.CreateWrapperFunction<FastcallExample>((long)reverseFunctionWrapper.Pointer);
    functionWrapper(1,2,3);
}


/* Function Implementation */

/// <summary>
/// When called through the address in reverseFunctionWrapper.Pointer,
/// this function is now a "fastcall" function.
/// </summary>
/// <param name="a">This number is passed into ECX!</param>
/// <param name="b">This number is passed into EDX!</param>
/// <param name="c">This number is on the stack.</param>
private static void CSharpFastcallFunction(int a, int b, int c)
{
    MessageBox.Show($"{a + b + c}");
}

All those wonderful docs.

What can I say? Documentation, Documentation, Documentation.

Now there's plenty more of it, last time around half of these pages did not exist.

Other Changes

libReloaded - Overlays

All backends

The code that has previously handled the frame pacing and framerate limiting has been entirely changed and rewritten from scratch. The previous, not as well thought out code from my earlier days of programming simply did not do frame timing correctly and put too much reliance on sleeping the thread.

The new framerate class consists of many wonderful bells and whistles:

  • Estimate the potential FPS if limiter disabled when the limiter is enabled.
  • Providing statistics such as the render time and sleep time until the next frame.
  • Timing accurate down to the highest frequency available for sleeping.

Remove Known Instances of Potentially Intrusive Open File Handles

Haha yes

Haha, yes, what is there to say? This is everyone's favourite dialog after all.
Well, some changes have been done behind the scenes; including less conventional image loading methods.

Rest assured, you can now delete banner images and a few others even when in use.
As for replacing... you were able to do that already 😊.

Pattern Scanner Performance Improvements

The internal logic of the pattern scanner has been changed from pass by value to pass by reference;

// Before
public static IntPtr FindPattern(byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }
// After
public static IntPtr FindPattern(ref byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }

This will greatly improve performance when passing in large byte arrays into the pattern scanner. You'll never know when someone will try to scan a large executable with it.

Of course for compatibility reasons; the old overload still exists.

Reloaded-GUI

Borderless Resizing

Reloaded's GUI got a new ability to resize the window, with or without the involvement of a visible window border (border is optional).

While this feature is not implemented anywhere as of yet, here is how it would look like.

A cancelled Reloaded theme/design for Heroes Power Plant.

Recursive Control Theming

Another feature that Reloaded's GUI has gained over the course of time is the recursive Windows Forms control theming of controls which feature child controls. Unfortunately, due to also having been implemented in the Heroes Power Plant reskin, and being currently unused - a visual representation of the changes has been lost.

However to put it simply, Reloaded's GUI can now have a panel in a panel in a panel in a panel and the controls/buttons/elements inside that panel would still be automatically themed.

Reloaded-Input

A bit of refactoring has been performed, cleaning up the existing code as it was a very, very long time since it was last touched. A bit of the code has been slightly changed for consistency and some monolithic classes were made less monolithic.

This shouldn't break any existing applications, much - but some class named will need adjustment; here is an example.

// Before
ControllerCommon.ControllerInputs inputs = controllerManager.GetInput(controllerPort);
// After
ControllerInputs inputs = controllerManager.GetInput(controllerPort);

Bug Fixes

Same-Game dependencies not updated in the GUI.


If I hit yes, one of these mods, which is in the same mod list would not be checked enabled in the mod list.
Whoops!

A bug has been reported recently where if a mod depends on another mod, and the user chooses to enable dependencies; the dependency would not be updated as enabled in the mod list menu. This has been fixed.

Steam API Hook

Reloaded Samples now includes a new sample mod that hooks the Steam API and lets you run a game without it restarting itself.

Whether it will work and not crash your game depends on a game by game basis; specifically how much of the API the individual game uses.

Assets 6

@Sewer56 Sewer56 released this Sep 8, 2018 · 25 commits to master since this release

Reloaded 2.0 | Scarlet Revolution



Table of Contents

Sorry for the links not working, Github doesn't support those in releases :/

Moving to Semantic Versioning

Admittedly since the very early days of Reloaded, my picking of version numbers was quite simply, bad. There really isn't much that I could have added back onto the last sentence.

With little experience of publishing larger software - I often found myself bumping the version of the project in irregular intervals; to the point where even version 1.0.0 was unfortunately not the first public-ready version, that was only really the case at around 1.0.3.

Even making things worse, not only did I often did not test NuGet package updates locally - due to a bug with PackageReference not updating local packages, I also thought that updating the versions of all my packages' with versions equal the mod loader every release was a good idea, terrible idea.

This can be seen this very instant - the latest and greatest stable version of libReloaded is err... a prerelease package: NuGet Versions

The New Format

Well, given the scale of this release - I decided that it is finally for the best to clean up this mess and start anew, only updating packages when they truly get updated and to make use of semantic versioning.

Basically to put it short, the format will still remain as X.Y.Z, e.g. 2.0.0 - but one thing will change. Rather than trying to make the mod loader signify progression; the individual components will be given a new meaning.

  • X (Major) version increment after incompatible API/library changes.
  • Y (Minor) version increment after new functionality in a backwards-compatible manner.
  • Z (Patch) version increment after backwards compatible bug fixes.

For the more complete explanation, feel free to read Semantic Versioning.

Notable Changes

Reloaded's New Plugin System

Yes
Oh pretty, divine colours.

Reloaded 2.0.0 includes a new, from the ground up plugin system designed to allow users to extend the functionality of both of Reloaded's Launcher and Loader.

As an example, with the plugin system a developer can perform many tasks:

  • Set the Reloaded-Loader parameters before an individual game is launched.
  • Execute code at various events such as Loader/Launcher launching, injecting DLLs.
  • Modify constants such the random messages shown below the Reloaded logo at the start of the loader.
  • Straight up replace/hook some Reloaded functions such as printing to console, printing banner.
  • Intercept the parsing of mod and game configurations onto the UI.

With the last one you can probably even integrate other mod loaders into Reloaded.

Aside from the rather charming example seen above, a more common or useful use of the plugin system can maybe be found directly below.

Mod update support for Github, GameBanana.

One of the additions into the newest version of Reloaded, that ships directly alongside the newly introduced plugin system is the newly gained ability to update individual mods from external sources on the internet.

Vroom Vroom!

One of the visible entries is not like the others.

Mod updates are automatically checked on launch of Reloaded Mod Loader and are done in fully asynchronous fashion - meaning that your launcher start up times are not impacted; enjoy!

The best of all; update is extensible via plugins. Want to add update support for another site? Write a simple plugin and you're done 👌.


Important Note:
For GameBanana mod update support, only mods downloaded through 1 click links using Reloaded 2.0.0 with plugin or newer will be supported. In addition, the GB 1 click link format will require to be changed to a new format incompatible with older Reloaded versions.

The link format will not change until a day after the release of 2.0.0 to allow other users to migrate.

Mod Configuration Changes

Support for Explicit DLL Names

Something that you may find more standard in other mod loaders, but not Reloaded, was the fact that till now - Reloaded assumed a standard set of DLL names, main32 for 32bit and main64 for 64bit.

And nothing was really wrong with that... except one thing... it makes life a bit more painful when you want to do DLL Exports as you'd have to do either of the following:

  • Get a list of all mods using Reloaded-IO and find a path to the other main32/main64.
  • Split mod with exports into two DLLs, one with different name and the actual exports.

That limit howevere was all but arbitrary; and I thought that it is perhaps time to lift that - and so; the new mod Config.json looks something more like this:

{
  "ModId": "",
  "ModName": "Modification Name Undefined",
  "ModDescription": "Modification Description Undefined",
  "ModVersion": "Undefined",
  "ModAuthor": "Undefined",
  "ModSite": "N/A",
  "ModSource": "N/A",
  "ConfigurationFile": "N/A",
  "DllFile32": "",
  "DllFile64": "",
  "Dependencies": []
}

Still fairly clean 😉, no more figuring out which main32.dll is which.

And now, this reduces the code of calling another Reloaded mod's dll export down to:

// This returns 0 if other dll is not loaded.
IntPtr dllHandle = Native.LoadLibraryW("otherReloadedDll"); 
IntPtr functionPointer = Native.GetProcAddress(dllHandle, "SomeFunction");

Done.

Autogeneration of Config.json Templates

When working with various mod loaders, one of the things you often ask yourself is "what the heck am I allowed to put in my config file!?". While Reloaded's wiki already is always ontop of the game, generally containing the latest templates in the tutorials; I still figured I could do something more.

As of Reloaded 2.0.0 - the launcher automatically exports various different configuration templates after it is installed, and before performing updates.

The templates are automatically exported to Reloaded-Mod-Loader\Reloaded-Config\Templates\Config and contain fresh, untouched config templates for items such as mods, games and plugins - complete with all of the fields.

Reloaded Assembler

It is no secret that Reloaded's X86/64 assembler is not the fastest thing alive; particularly due with the fact that individual mods cannot make use of it directly but have to communicate with it over the local computer.

The reason it has to communicate cross process over the local computer is unfortunately the sad truth that there does not exist a pure assembler which compiles to both 32 and 64bit machines (and can be ported to C#).

Because of this; during all this time, Reloaded has actually been using its own solution around the problem, the "Reloaded-Assembler". Reloaded-Assembler takes the fantastic FASM wrapper named FASM.NET and introduces it to the world (of your local computer) by adding full networking support to allow the remote compilation of assembler code.

With the use of some magic, it's even embedded in libReloaded and will self-extract and run if an instance is not already present.

Speeding up the Assembler.

Well, at one point I found that the setup time of my projects - TONER took longer than I initially. Eventually the startup time bottleneck has narrowed down to Reloaded's own function hook creation code which took over 100ms to complete, add 10+ hooks in a row, ouch!

While the hooking code for Reloaded is very advanced and powerful - I still found such performance figure unacceptable for my own liking, even if function hook creation is a one-time thing; so I took in pursuit to find the bottleneck... It didn't take long to identify the huge bottleneck of Reloaded Assembler - namely the networking component.

Therefore I have managed to implement two optimizations into the assembler to try work around the overhead of the networking component:

  • Increase the polling/check rate of the assembler.
  • Skip the networked assembler altogether and use FASM.NET in X86.

Now to illustrate.

[Before] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 32ms
X86-64 32ms

[After] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 0ms
X86-64 4ms

Needless to say, in X86 the time taken to set up a function hook sliced, to less than 50ms by this change.

MemoryBufferManager Caching.

Since I have already fixed the main bottleneck of the hooking code; why shouldn't I just as well fix the secondary bottleneck?

And well, that bottleneck is MemoryBuffer, the implementation of Reloaded allocated memory that can be shared between different mods. This is primarily used for pointer storage in hook functions as well as permanent storage of data.

The bottleneck?
I simply forgot to cache the individual found buffers between different add operations; job done.

This has caused a further reduction of average X86 hook times from <50ms (after assembler patch) to 2ms.

All bottlenecks gone, at least in X86.

New ways to launch games.

One annoying aspect of Reloaded for some people may be the fact that due to Reloaded's nature of being a DLL injection based mod loader; the actual mod loader must initiate the game loading sequence.

As of Reloaded 2.0.0; some attempt is made to levy the situation. Two new features - one to create a shortcut for launching a game through Reloaded, and the other that can spoof/pretend to be a game launcher.

Both under the hood this uses with a new commandline switch for Reloaded-Launcher, --launch. This accepts a directory location containing a game profile and any extra additional arguments and passes it onto the loader directly.

Direct Shortcuts to Launch Games

Plain and simple. Press the button, get a shortcut on the desktop, doubleclick and the game runs through Reloaded.

Launcher Pretendo

You can read more about this one in one of Reloaded's Readme pages.

Basically, Reloaded now has its own launcher-spoofer executable that can replace any other game's launcher. The way it works; click the Generate Launcher button, paste over another game's launcher and just ensure that the individual executables the game's regular launcher woould typically run have their own game profiles in Reloaded. Done.

Oh, and you can also use it in place of a game executable to stop the "Steam Reattaching" business if you want, more on that in the readme pages.

Optimize X64 Loader Startup Times

GIF

Top right is before, bottom right is after.

The optimization comes in the form of changing how the check whether a game or process is X64 is performed. Before, the loader would run the game or process and ask the Windows API whether the process is running in Windows on Windows 64 (WOW64) mode.

Now, Reloaded's loader no longer performs this check, and instead immediately, as soon as the arguments are parsed and game profile read, instead opens a file in a stream and reads the architecture type from the PE header of the executable; no need to load the process anymore and then kill it if it's X64.

Reimplement Auto Attach

Auto attach

One of the features that was present in very, very early versions of Reloaded was the feature to wait for a process to start and automatically attach.

Well, for a reason I do not remember anymore, this feature was cut at some point... Why? I do not remember, however it is back.

libReloaded - Pointers to C# functions.

For a while, the functionality for creating pointers to C# functions has pretty much existed inside Reloaded's main library. After all, function hooks depend on it, don't they? ... Except that there was one caveat - it was all part of the hooking code and never exposed public.

Well, that functionality has been forked from the hook code and split into separate classes, ReverseFunctionWrapper and X64ReverseFunctionWrapper respectively.

Below is an example from Reloaded's Quick Tour on creating a pointer to a C# function.
The catch? None. Here's an example to a pointer of a C# "fastcall" function:

// Define a fastcall Reloaded function.
// Microsoft Fastcall passes first two parameters in registers ECX, EDX and returns value in EAX.
[ReloadedFunction(CallingConventions.Fastcall)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FastcallExample(int a, int b, int c);

/* Fields */
private static ReverseFunctionWrapper<FastcallExample> reverseFunctionWrapper;  // Pointer to C# Fastcall function.
private static FastcallExample                         functionWrapper;         // We will call our C# function through the pointer to prove.

/* Main/Init Method */
void FastcallCSharpFunctionPointerTest()
{
    // Create our pointer to our C# "fastcall" function.
    // reverseFunctionWrapper.Pointer now has the address of the C# function, that's fastcall.
    reverseFunctionWrapper = ReverseFunctionWrapper<FastcallExample>.CreateReverseWrapper(CSharpFastcallFunction);

    // To prove our C# "fastcall" function works, let's just call it like a native function.
    functionWrapper = FunctionWrapper.CreateWrapperFunction<FastcallExample>((long)reverseFunctionWrapper.Pointer);
    functionWrapper(1,2,3);
}


/* Function Implementation */

/// <summary>
/// When called through the address in reverseFunctionWrapper.Pointer,
/// this function is now a "fastcall" function.
/// </summary>
/// <param name="a">This number is passed into ECX!</param>
/// <param name="b">This number is passed into EDX!</param>
/// <param name="c">This number is on the stack.</param>
private static void CSharpFastcallFunction(int a, int b, int c)
{
    MessageBox.Show($"{a + b + c}");
}

All those wonderful docs.

What can I say? Documentation, Documentation, Documentation.

Now there's plenty more of it, last time around half of these pages did not exist.

Other Changes

libReloaded - Overlays

All backends

The code that has previously handled the frame pacing and framerate limiting has been entirely changed and rewritten from scratch. The previous, not as well thought out code from my earlier days of programming simply did not do frame timing correctly and put too much reliance on sleeping the thread.

The new framerate class consists of many wonderful bells and whistles:

  • Estimate the potential FPS if limiter disabled when the limiter is enabled.
  • Providing statistics such as the render time and sleep time until the next frame.
  • Timing accurate down to the highest frequency available for sleeping.

Remove Known Instances of Potentially Intrusive Open File Handles

Haha yes

Haha, yes, what is there to say? This is everyone's favourite dialog after all.
Well, some changes have been done behind the scenes; including less conventional image loading methods.

Rest assured, you can now delete banner images and a few others even when in use.
As for replacing... you were able to do that already 😊.

Pattern Scanner Performance Improvements

The internal logic of the pattern scanner has been changed from pass by value to pass by reference;

// Before
public static IntPtr FindPattern(byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }
// After
public static IntPtr FindPattern(ref byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }

This will greatly improve performance when passing in large byte arrays into the pattern scanner. You'll never know when someone will try to scan a large executable with it.

Of course for compatibility reasons; the old overload still exists.

Reloaded-GUI

Borderless Resizing

Reloaded's GUI got a new ability to resize the window, with or without the involvement of a visible window border (border is optional).

While this feature is not implemented anywhere as of yet, here is how it would look like.

A cancelled Reloaded theme/design for Heroes Power Plant.

Recursive Control Theming

Another feature that Reloaded's GUI has gained over the course of time is the recursive Windows Forms control theming of controls which feature child controls. Unfortunately, due to also having been implemented in the Heroes Power Plant reskin, and being currently unused - a visual representation of the changes has been lost.

However to put it simply, Reloaded's GUI can now have a panel in a panel in a panel in a panel and the controls/buttons/elements inside that panel would still be automatically themed.

Reloaded-Input

A bit of refactoring has been performed, cleaning up the existing code as it was a very, very long time since it was last touched. A bit of the code has been slightly changed for consistency and some monolithic classes were made less monolithic.

This shouldn't break any existing applications, much - but some class named will need adjustment; here is an example.

// Before
ControllerCommon.ControllerInputs inputs = controllerManager.GetInput(controllerPort);
// After
ControllerInputs inputs = controllerManager.GetInput(controllerPort);

Bug Fixes

Same-Game dependencies not updated in the GUI.


If I hit yes, one of these mods, which is in the same mod list would not be checked enabled in the mod list.
Whoops!

A bug has been reported recently where if a mod depends on another mod, and the user chooses to enable dependencies; the dependency would not be updated as enabled in the mod list menu. This has been fixed.

Assets 6

@Sewer56 Sewer56 released this Sep 8, 2018 · 30 commits to master since this release

Reloaded 2.0 | Revolution



Table of Contents

Sorry for the links not working, Github doesn't support those in releases :/

Moving to Semantic Versioning

Admittedly since the very early days of Reloaded, my picking of version numbers was quite simply, bad. There really isn't much that I could have added back onto the last sentence.

With little experience of publishing larger software - I often found myself bumping the version of the project in irregular intervals; to the point where even version 1.0.0 was unfortunately not the first public-ready version, that was only really the case at around 1.0.3.

Even making things worse, not only did I often did not test NuGet package updates locally - due to a bug with PackageReference not updating local packages, I also thought that updating the versions of all my packages' with versions equal the mod loader every release was a good idea, terrible idea.

This can be seen this very instant - the latest and greatest stable version of libReloaded is err... a prerelease package: NuGet Versions

The New Format

Well, given the scale of this release - I decided that it is finally for the best to clean up this mess and start anew, only updating packages when they truly get updated and to make use of semantic versioning.

Basically to put it short, the format will still remain as X.Y.Z, e.g. 2.0.0 - but one thing will change. Rather than trying to make the mod loader signify progression; the individual components will be given a new meaning.

  • X (Major) version increment after incompatible API/library changes.
  • Y (Minor) version increment after new functionality in a backwards-compatible manner.
  • Z (Patch) version increment after backwards compatible bug fixes.

For the more complete explanation, feel free to read Semantic Versioning.

Notable Changes

Reloaded's New Plugin System

Yes
Oh pretty, divine colours.

Reloaded 2.0.0 includes a new, from the ground up plugin system designed to allow users to extend the functionality of both of Reloaded's Launcher and Loader.

As an example, with the plugin system a developer can perform many tasks:

  • Set the Reloaded-Loader parameters before an individual game is launched.
  • Execute code at various events such as Loader/Launcher launching, injecting DLLs.
  • Modify constants such the random messages shown below the Reloaded logo at the start of the loader.
  • Straight up replace/hook some Reloaded functions such as printing to console, printing banner.
  • Intercept the parsing of mod and game configurations onto the UI.

With the last one you can probably even integrate other mod loaders into Reloaded.

Aside from the rather charming example seen above, a more common or useful use of the plugin system can maybe be found directly below.

Mod update support for Github, GameBanana.

One of the additions into the newest version of Reloaded, that ships directly alongside the newly introduced plugin system is the newly gained ability to update individual mods from external sources on the internet.

Vroom Vroom!

One of the visible entries is not like the others.

Mod updates are automatically checked on launch of Reloaded Mod Loader and are done in fully asynchronous fashion - meaning that your launcher start up times are not impacted; enjoy!

The best of all; update is extensible via plugins. Want to add update support for another site? Write a simple plugin and you're done 👌.


Important Note:
For GameBanana mod update support, only mods downloaded through 1 click links using Reloaded 2.0.0 with plugin or newer will be supported. In addition, the GB 1 click link format will require to be changed to a new format incompatible with older Reloaded versions.

The link format will not change until a day after the release of 2.0.0 to allow other users to migrate.

Mod Configuration Changes

Support for Explicit DLL Names

Something that you may find more standard in other mod loaders, but not Reloaded, was the fact that till now - Reloaded assumed a standard set of DLL names, main32 for 32bit and main64 for 64bit.

And nothing was really wrong with that... except one thing... it makes life a bit more painful when you want to do DLL Exports as you'd have to do either of the following:

  • Get a list of all mods using Reloaded-IO and find a path to the other main32/main64.
  • Split mod with exports into two DLLs, one with different name and the actual exports.

That limit howevere was all but arbitrary; and I thought that it is perhaps time to lift that - and so; the new mod Config.json looks something more like this:

{
  "ModId": "",
  "ModName": "Modification Name Undefined",
  "ModDescription": "Modification Description Undefined",
  "ModVersion": "Undefined",
  "ModAuthor": "Undefined",
  "ModSite": "N/A",
  "ModSource": "N/A",
  "ConfigurationFile": "N/A",
  "DllFile32": "",
  "DllFile64": "",
  "Dependencies": []
}

Still fairly clean 😉, no more figuring out which main32.dll is which.

And now, this reduces the code of calling another Reloaded mod's dll export down to:

// This returns 0 if other dll is not loaded.
IntPtr dllHandle = Native.LoadLibraryW("otherReloadedDll"); 
IntPtr functionPointer = Native.GetProcAddress(dllHandle, "SomeFunction");

Done.

Autogeneration of Config.json Templates

When working with various mod loaders, one of the things you often ask yourself is "what the heck am I allowed to put in my config file!?". While Reloaded's wiki already is always ontop of the game, generally containing the latest templates in the tutorials; I still figured I could do something more.

As of Reloaded 2.0.0 - the launcher automatically exports various different configuration templates after it is installed, and before performing updates.

The templates are automatically exported to Reloaded-Mod-Loader\Reloaded-Config\Templates\Config and contain fresh, untouched config templates for items such as mods, games and plugins - complete with all of the fields.

Reloaded Assembler

It is no secret that Reloaded's X86/64 assembler is not the fastest thing alive; particularly due with the fact that individual mods cannot make use of it directly but have to communicate with it over the local computer.

The reason it has to communicate cross process over the local computer is unfortunately the sad truth that there does not exist a pure assembler which compiles to both 32 and 64bit machines (and can be ported to C#).

Because of this; during all this time, Reloaded has actually been using its own solution around the problem, the "Reloaded-Assembler". Reloaded-Assembler takes the fantastic FASM wrapper named FASM.NET and introduces it to the world (of your local computer) by adding full networking support to allow the remote compilation of assembler code.

With the use of some magic, it's even embedded in libReloaded and will self-extract and run if an instance is not already present.

Speeding up the Assembler.

Well, at one point I found that the setup time of my projects - TONER took longer than I initially. Eventually the startup time bottleneck has narrowed down to Reloaded's own function hook creation code which took over 100ms to complete, add 10+ hooks in a row, ouch!

While the hooking code for Reloaded is very advanced and powerful - I still found such performance figure unacceptable for my own liking, even if function hook creation is a one-time thing; so I took in pursuit to find the bottleneck... It didn't take long to identify the huge bottleneck of Reloaded Assembler - namely the networking component.

Therefore I have managed to implement two optimizations into the assembler to try work around the overhead of the networking component:

  • Increase the polling/check rate of the assembler.
  • Skip the networked assembler altogether and use FASM.NET in X86.

Now to illustrate.

[Before] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 32ms
X86-64 32ms

[After] The worst case scenario of networking overhead:

Process Type Worst case scenario.
X86 0ms
X86-64 4ms

Needless to say, in X86 the time taken to set up a function hook sliced, to less than 50ms by this change.

MemoryBufferManager Caching.

Since I have already fixed the main bottleneck of the hooking code; why shouldn't I just as well fix the secondary bottleneck?

And well, that bottleneck is MemoryBuffer, the implementation of Reloaded allocated memory that can be shared between different mods. This is primarily used for pointer storage in hook functions as well as permanent storage of data.

The bottleneck?
I simply forgot to cache the individual found buffers between different add operations; job done.

This has caused a further reduction of average X86 hook times from <50ms (after assembler patch) to 2ms.

All bottlenecks gone, at least in X86.

New ways to launch games.

One annoying aspect of Reloaded for some people may be the fact that due to Reloaded's nature of being a DLL injection based mod loader; the actual mod loader must initiate the game loading sequence.

As of Reloaded 2.0.0; some attempt is made to levy the situation. Two new features - one to create a shortcut for launching a game through Reloaded, and the other that can spoof/pretend to be a game launcher.

Both under the hood this uses with a new commandline switch for Reloaded-Launcher, --launch. This accepts a directory location containing a game profile and any extra additional arguments and passes it onto the loader directly.

Direct Shortcuts to Launch Games

Plain and simple. Press the button, get a shortcut on the desktop, doubleclick and the game runs through Reloaded.

Launcher Pretendo

You can read more about this one in one of Reloaded's Readme pages.

Basically, Reloaded now has its own launcher-spoofer executable that can replace any other game's launcher. The way it works; click the Generate Launcher button, paste over another game's launcher and just ensure that the individual executables the game's regular launcher woould typically run have their own game profiles in Reloaded. Done.

Oh, and you can also use it in place of a game executable to stop the "Steam Reattaching" business if you want, more on that in the readme pages.

Optimize X64 Loader Startup Times

GIF

Top right is before, bottom right is after.

The optimization comes in the form of changing how the check whether a game or process is X64 is performed. Before, the loader would run the game or process and ask the Windows API whether the process is running in Windows on Windows 64 (WOW64) mode.

Now, Reloaded's loader no longer performs this check, and instead immediately, as soon as the arguments are parsed and game profile read, instead opens a file in a stream and reads the architecture type from the PE header of the executable; no need to load the process anymore and then kill it if it's X64.

libReloaded - Pointers to C# functions.

For a while, the functionality for creating pointers to C# functions has pretty much existed inside Reloaded's main library. After all, function hooks depend on it, don't they? ... Except that there was one caveat - it was all part of the hooking code and never exposed public.

Well, that functionality has been forked from the hook code and split into separate classes, ReverseFunctionWrapper and X64ReverseFunctionWrapper respectively.

Below is an example from Reloaded's Quick Tour on creating a pointer to a C# function.
The catch? None. Here's an example to a pointer of a C# "fastcall" function:

// Define a fastcall Reloaded function.
// Microsoft Fastcall passes first two parameters in registers ECX, EDX and returns value in EAX.
[ReloadedFunction(CallingConventions.Fastcall)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FastcallExample(int a, int b, int c);

/* Fields */
private static ReverseFunctionWrapper<FastcallExample> reverseFunctionWrapper;  // Pointer to C# Fastcall function.
private static FastcallExample                         functionWrapper;         // We will call our C# function through the pointer to prove.

/* Main/Init Method */
void FastcallCSharpFunctionPointerTest()
{
    // Create our pointer to our C# "fastcall" function.
    // reverseFunctionWrapper.Pointer now has the address of the C# function, that's fastcall.
    reverseFunctionWrapper = ReverseFunctionWrapper<FastcallExample>.CreateReverseWrapper(CSharpFastcallFunction);

    // To prove our C# "fastcall" function works, let's just call it like a native function.
    functionWrapper = FunctionWrapper.CreateWrapperFunction<FastcallExample>((long)reverseFunctionWrapper.Pointer);
    functionWrapper(1,2,3);
}


/* Function Implementation */

/// <summary>
/// When called through the address in reverseFunctionWrapper.Pointer,
/// this function is now a "fastcall" function.
/// </summary>
/// <param name="a">This number is passed into ECX!</param>
/// <param name="b">This number is passed into EDX!</param>
/// <param name="c">This number is on the stack.</param>
private static void CSharpFastcallFunction(int a, int b, int c)
{
    MessageBox.Show($"{a + b + c}");
}

All those wonderful docs.

What can I say? Documentation, Documentation, Documentation.

Now there's plenty more of it, last time around half of these pages did not exist.

Other Changes

libReloaded - Overlays

All backends

The code that has previously handled the frame pacing and framerate limiting has been entirely changed and rewritten from scratch. The previous, not as well thought out code from my earlier days of programming simply did not do frame timing correctly and put too much reliance on sleeping the thread.

The new framerate class consists of many wonderful bells and whistles:

  • Estimate the potential FPS if limiter disabled when the limiter is enabled.
  • Providing statistics such as the render time and sleep time until the next frame.
  • Timing accurate down to the highest frequency available for sleeping.

Remove Known Instances of Potentially Intrusive Open File Handles

Haha yes

Haha, yes, what is there to say? This is everyone's favourite dialog after all.
Well, some changes have been done behind the scenes; including less conventional image loading methods.

Rest assured, you can now delete banner images and a few others even when in use.
As for replacing... you were able to do that already 😊.

Pattern Scanner Performance Improvements

The internal logic of the pattern scanner has been changed from pass by value to pass by reference;

// Before
public static IntPtr FindPattern(byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }
// After
public static IntPtr FindPattern(ref byte[] memoryRegion, byte[] bytePattern, string stringMask) { /*...*/ }

This will greatly improve performance when passing in large byte arrays into the pattern scanner. You'll never know when someone will try to scan a large executable with it.

Of course for compatibility reasons; the old overload still exists.

Reloaded-GUI

Borderless Resizing

Reloaded's GUI got a new ability to resize the window, with or without the involvement of a visible window border (border is optional).

While this feature is not implemented anywhere as of yet, here is how it would look like.

A cancelled Reloaded theme/design for Heroes Power Plant.

Recursive Control Theming

Another feature that Reloaded's GUI has gained over the course of time is the recursive Windows Forms control theming of controls which feature child controls. Unfortunately, due to also having been implemented in the Heroes Power Plant reskin, and being currently unused - a visual representation of the changes has been lost.

However to put it simply, Reloaded's GUI can now have a panel in a panel in a panel in a panel and the controls/buttons/elements inside that panel would still be automatically themed.

Reloaded-Input

A bit of refactoring has been performed, cleaning up the existing code as it was a very, very long time since it was last touched. A bit of the code has been slightly changed for consistency and some monolithic classes were made less monolithic.

This shouldn't break any existing applications, much - but some class named will need adjustment; here is an example.

// Before
ControllerCommon.ControllerInputs inputs = controllerManager.GetInput(controllerPort);
// After
ControllerInputs inputs = controllerManager.GetInput(controllerPort);

Bug Fixes

Same-Game dependencies not updated in the GUI.


If I hit yes, one of these mods, which is in the same mod list would not be checked enabled in the mod list.
Whoops!

A bug has been reported recently where if a mod depends on another mod, and the user chooses to enable dependencies; the dependency would not be updated as enabled in the mod list menu. This has been fixed.

Assets 5

@Sewer56 Sewer56 released this Aug 13, 2018 · 69 commits to master since this release

Bug Fixes

[Launcher] Fix accidental error following internal format change whereby the config file location for mod configurations was incorrectly built.

Assets 6

@Sewer56 Sewer56 released this Aug 12, 2018 · 73 commits to master since this release

Commandline Args

Note: The following is a list of all cumulative changes since the last Stable released update;

Improvements

  • [Template] Implement full AppDomain level DLL separation. This should allow different mods to load different versions of the same libraries at once, which became an issue identified when the external dependency libraries got updated in 1.2.0. Devs: Please update your template files.

  • [Launcher, Loader, IO] Individual game profiles can now include commandline parameters to be passed onto applications, separated by white spaces.

  • [Loader] Make Reloaded-Loader preload Reloaded-Assembler: Reloaded-Assembler should no longer bother the mod developers working with code when removing/moving some library files ("this file is used by X").

  • [All] Update NuGet Dependencies: All 3rd party external NuGet packages have been updated and briefly tested for compatibility.

  • [Launcher] The launcher now remembers the last launched/selected game and will re-apply the last selection when opening the launcher the following time. The selection of the Manage Menu is also now synchronized with the Main Menu selection.

  • [Assembler] Reloaded-Assembler will now automatically shut itself down after ~10 seconds when all clients connected to it shutdown or disconnect (no more Assembler permanently active in background).

  • [X86 Hooks] You can now specify extra stack space to be reserved when calling external functions. This will allow developers to hook the peskiest of compiler optimized functions.

Bug Fixes

  • [Launcher - Themes] The launcher titlebar title now updates when themes are switched rather than only after exiting the menu.

Other

  • [NuGet] The NuGet packages should once again display their documentation in IntelliSense. There was a short period after the last update where they failed to do so. This was because IntelliSense appears to only check XMLs of the same filename as the DLL file and to avoid conflicts, I have started versioning the DLLs in name.

  • [NuGet] The NuGet packages no longer point to publically unlisted test packages also caused by the start of DLL versioning... whoops!

  • [Hooks] Expose original function wrapper address. For debugging purposes, developers will know what this means.

  • [All] Minor optimizations to the .csproj project entries for the libReloaded libraries to make them easier to package for NuGet in the future.

  • [File Redirector New] Minor code adjustments and documentation completion.

WIP

  • [Hooks] Untested Cheat-Engine style assembly hook. Literally untested.
Assets 6

@Sewer56 Sewer56 released this Aug 9, 2018 · 75 commits to master since this release

Improvements

  • [Template] Implement full AppDomain level DLL separation. This should allow different mods to load different versions of the same libraries at once, which became an issue identified when the external dependency libraries got updated in 1.2.0.

  • [X86 Hooks] You can now specify extra stack space to be reserved when calling external functions. This will allow developers to hook the peskiest of compiler optimized functions.

Other

  • [Hooks] Expose original function wrapper address. For debugging purposes, developers will know what this means.

WIP

  • [Hooks] Untested Cheat-Engine style assembly hook. Literally untested.
Assets 4
You can’t perform that action at this time.