Skip to content

Commit

Permalink
Refactor and add LCGOL support
Browse files Browse the repository at this point in the history
  • Loading branch information
TheIndra55 committed Jul 15, 2024
1 parent d3caf0b commit 5f46f12
Show file tree
Hide file tree
Showing 21 changed files with 723 additions and 539 deletions.
5 changes: 3 additions & 2 deletions premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ project "ModLoader"
language "C++"
cppdialect "C++17"

-- Source file
-- Source files
files "src/**"
includedirs { "src" }

-- Vendor modules
-- Vendor files
files { "vendor/minhook/src/**", "vendor/patterns/*.cpp" }
includedirs { "vendor/minhook/include", "vendor/patterns" }

Expand Down
33 changes: 33 additions & 0 deletions src/Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <Windows.h>
#include <MinHook.h>

#include "ModLoader.h"

static VOID(WINAPI* s_GetStartupInfoA)(LPSTARTUPINFOA);

static VOID WINAPI StartupInfoW(LPSTARTUPINFOA lpStartupInfo)
{
auto& loader = ModLoader::GetInstance();

if (!loader.IsInitialized())
{
loader.Initialize();
}

return s_GetStartupInfoA(lpStartupInfo);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
MH_Initialize();

// Insert an early hook on GetStartupInfoA which will be called when the executable is done unpacking
// Some of the executables are packed, so we can't immediately insert our hooks
MH_CreateHookApi(L"kernel32", "GetStartupInfoA", StartupInfoW, (void**)&s_GetStartupInfoA);
MH_EnableHook(MH_ALL_HOOKS);
}

return TRUE;
}
168 changes: 168 additions & 0 deletions src/ModLoader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "ModLoader.h"

#include <Windows.h>
#include <MinHook.h>
#include <Hooking.Patterns.h>

#include "cdc/FileSystem.h"
#include "cdc/MultiFileSystem.h"
#include "file/MultiFileSystem.h"
#include "file/HookFileSystem.h"
#include "util/Hooking.h"

static void* s_getFS = nullptr;
static void* s_target = nullptr;

static cdc::FileSystem** s_diskFS = nullptr;

// Gets the current file system
static cdc::FileSystem* GetFS() noexcept
{
return Hooking::CallReturn<cdc::FileSystem*>(s_getFS);
}

// Insert the hook file system and remove the current hook
template<typename FileSystem>
static void InsertAndUnhook() noexcept
{
if (std::is_same<FileSystem, MultiFileSystem>())
{
// Create new multi file system if it doesn't exist in current game
auto multiFileSystem = new MultiFileSystem();

// Override the default file system with ours
*(cdc::FileSystem**)((char*)s_getFS + 1) = multiFileSystem;
}

// Create the hook file system
auto fileSystem = new HookFileSystem(*s_diskFS);

// Add it to the system
auto multiFileSystem = (FileSystem*)GetFS();
multiFileSystem->Add(fileSystem, false, true);

// Now GTFO so we don't trigger any DRM which might be hanging around
MH_RemoveHook(s_target);
}

// Hooks
static void(*s_InitArchive)();
static bool(*s_InitPatchArchive)(const char*);
static void(__thiscall* s_InitDlcSystem)(void*);

// TR7 and TRA
static void InitArchive()
{
s_InitArchive();

InsertAndUnhook<MultiFileSystem>();
}

// TR8
static bool InitPatchArchive(const char* name)
{
auto ret = s_InitPatchArchive(name);

InsertAndUnhook<cdc::MultiFileSystem>();

return ret;
}

// LCGOL
static void __fastcall InitDlcSystem(void* _this)
{
s_InitDlcSystem(_this);

InsertAndUnhook<cdc::MultiFileSystem>();
}

ModLoader::~ModLoader() noexcept
{
MH_Uninitialize();
}

ModLoader& ModLoader::GetInstance() noexcept
{
static ModLoader instance;
return instance;
}

void ModLoader::Initialize() noexcept
{
m_initialized = true;

// Scan for all patterns
auto getFS = hook::pattern("E8 ? ? ? ? 50 8D 4C 24 08 6A 00 51").count_hint(1);

auto initArchive = hook::pattern("84 C0 75 0B 68 ? ? ? ? E8 ? ? ? ? 59 C3").count_hint(1);
auto initPatch = hook::pattern("56 57 E8 ? ? ? ? 8B 7C 24 0C 8B").count_hint(1);
auto initDlc = hook::pattern("8B 0E 6A 00 6A 00 52 E8 ? ? ? ? A1").count_hint(1);

if (getFS.empty() || !(initArchive.empty() || initPatch.empty() || initDlc.empty()))
{
ShowError();

return;
}

s_getFS = Hooking::GetAddress(getFS.get_first());

// Insert hooks
if (!initArchive.empty())
{
s_target = initArchive.get_first(-68);

MH_CreateHook(s_target, InitArchive, (void**)&s_InitArchive);
}

if (!initPatch.empty())
{
s_target = initPatch.get_first();

MH_CreateHook(s_target, InitPatchArchive, (void**)&s_InitPatchArchive);
}

if (!initDlc.empty())
{
s_target = initDlc.get_first(-88);

MH_CreateHook(s_target, InitDlcSystem, (void**)&s_InitDlcSystem);
}

// Find the disk file system
auto legend = hook::pattern("8B 15 ? ? ? ? 33 C9 89 4C 24 01").count_hint(1);
auto underworld = hook::pattern("8B 0D ? ? ? ? 89 35 ? ? ? ? 3B CE").count_hint(1);

if (legend.empty() && underworld.empty())
{
ShowError();

return;
}

if (!legend.empty())
{
s_diskFS = *legend.get_first<cdc::FileSystem**>(2);
}

if (!underworld.empty())
{
s_diskFS = *underworld.get_first<cdc::FileSystem**>(8);
}

MH_EnableHook(MH_ALL_HOOKS);
}

void ModLoader::ShowError() const noexcept
{
MessageBoxA(
NULL,
"This version is not compatible, please open an issue on GitHub if this game is listed as supported.",
"Gane not compatible",
MB_OK | MB_ICONERROR);
}

bool ModLoader::IsInitialized() const noexcept
{
return m_initialized;
}
18 changes: 18 additions & 0 deletions src/ModLoader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

class ModLoader
{
private:

bool m_initialized = false;

~ModLoader() noexcept;

void ShowError() const noexcept;

public:
static ModLoader& GetInstance() noexcept;

void Initialize() noexcept;
bool IsInitialized() const noexcept;
};
78 changes: 78 additions & 0 deletions src/cdc/FileSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

namespace cdc
{
class FileRequest
{
public:
enum Status
{
SETUP,
QUEUED,
PROCESSING,
DONE,
CANCELLED
};

enum Priority
{
HIGH,
NORMAL,
LOW
};

virtual void AddRef() = 0;
virtual void Release() = 0;
virtual void SetCompressedSize(unsigned int size) = 0;
virtual void SetUncompressed() = 0;
virtual void SetSize(unsigned int size) = 0;
virtual Status GetStatus() = 0;
virtual void Submit(Priority priority) = 0;
virtual void Cancel() = 0;
virtual float Completed() = 0;
};

class FileReceiver
{
public:
virtual int ReceiveData(const char* data, unsigned int dataSize, unsigned int requestOffset) = 0;
virtual void ReceiveStarted(FileRequest* request, unsigned int requestSize) = 0;
virtual void ReceiveCancelled(FileRequest* request) = 0;
virtual void ReceiveDone(FileRequest* request) = 0;
};

class File
{
public:
virtual FileRequest* RequestRead(FileReceiver* receiver, const char* fileName, unsigned int startOffset) = 0;
virtual unsigned int GetSize() = 0;
};

class FileSystem
{
public:
enum Status
{
IDLE,
BUSY
};

virtual FileRequest* RequestRead(FileReceiver* receiver, const char* fileName, unsigned int startOffset) = 0;
virtual File* OpenFile(const char* fileName) = 0;
virtual bool FileExists(const char* fileName) = 0;
virtual unsigned int GetFileSize(const char* fileName) = 0;
virtual void SetSpecialisationMask(unsigned int specMask) = 0;
virtual unsigned int GetSpecialisationMask() = 0;
virtual Status GetStatus() = 0;
virtual void Update() = 0;
virtual void Synchronize() = 0;

virtual void Suspend() = 0;
virtual bool Resume() = 0;
virtual bool IsSuspended() = 0;
virtual char* GetBufferPointer(FileRequest* request, unsigned int* bytesLocked) = 0;
virtual void ResetBufferPointer(cdc::FileRequest* request) = 0;

virtual ~FileSystem() { };
};
}
12 changes: 12 additions & 0 deletions src/cdc/MultiFileSystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "MultiFileSystem.h"

#include "util/Hooking.h"

#include <Hooking.Patterns.h>

void cdc::MultiFileSystem::Add(FileSystem* fileSystem, bool bReprioritize, bool bAddToFront)
{
auto func = hook::get_pattern<void>("80 7C 24 0C 00 8B C1 74 5A 53");

Hooking::ThisCall(func, this, fileSystem, bReprioritize, bAddToFront);
}
12 changes: 12 additions & 0 deletions src/cdc/MultiFileSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include "FileSystem.h"

namespace cdc
{
class MultiFileSystem
{
public:
void Add(FileSystem* fileSystem, bool bReprioritize, bool bAddToFront);
};
}
Loading

0 comments on commit 5f46f12

Please sign in to comment.