diff --git a/CMakeLists.txt b/CMakeLists.txt index 0da82a25..6d971cf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(isle CXX) option(ISLE_BUILD_APP "Build ISLE.EXE application" ON) +option(ISLE_BUILD_PATCH "Build patching into ISLE.EXE and LEGO1.DLL (requires ISLE_BUILD_APP)" OFF) option(ISLE_USE_SMARTHEAP "Build with SmartHeap" ${MSVC}) option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" ON) @@ -219,6 +220,22 @@ target_link_libraries(lego1 PRIVATE ddraw dsound dxguid dinput winmm) set_property(TARGET lego1 PROPERTY OUTPUT_NAME LEGO1) set_property(TARGET lego1 PROPERTY SUFFIX ".DLL") +# Forward ISLE_BUILD_PATCH +if (ISLE_BUILD_PATCH) + target_sources(lego1 PRIVATE LEGO1/decomp.cpp) + + target_compile_definitions(lego1 PRIVATE ISLE_BUILD_PATCH) + + # Copy LEGO1.DLL to LEGO1_PATCH.DLL after LEGO1.DLL is built + # This is a crappy hack, but when building the patcher, we want + # ISLE.EXE to import the original LEGO1.DLL, then load LEGO1_PATCH.DLL + # (our DLL) manually + add_custom_command( + TARGET lego1 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/LEGO1_PATCH.DLL + ) +endif() + if (ISLE_BUILD_APP) add_executable(isle WIN32 ISLE/res/isle.rc @@ -245,6 +262,11 @@ if (ISLE_BUILD_APP) # Make sure filenames are ALL CAPS set_property(TARGET isle PROPERTY OUTPUT_NAME ISLE) set_property(TARGET isle PROPERTY SUFFIX ".EXE") + + # Forward ISLE_BUILD_PATCH + if (ISLE_BUILD_PATCH) + target_compile_definitions(isle PRIVATE ISLE_BUILD_PATCH) + endif() endif() if (MSVC) @@ -272,4 +294,4 @@ if (MSVC) set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "/incremental:no") set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "/incremental:no /debug") set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "/incremental:no") -endif() \ No newline at end of file +endif() diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index c20f1652..bc426e49 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -155,6 +155,21 @@ BOOL StartDirectSound(void); // OFFSET: ISLE 0x401610 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { +#ifdef ISLE_BUILD_PATCH + // Load LEGO1_PATCH.DLL + { + HMODULE hModule = LoadLibraryA("LEGO1_PATCH.DLL"); + if (hModule) { + typedef void (*PatchFunc)(void*); + PatchFunc patchFunc = (PatchFunc)GetProcAddress(hModule, "Patch"); + if (patchFunc) { + void *root = (char*)VideoManager - 0x10015720; + patchFunc(root); + } + } + } +#endif + // Look for another instance, if we find one, bring it to the foreground instead if (!FindExistingInstance()) { return 0; diff --git a/LEGO1/decomp.cpp b/LEGO1/decomp.cpp new file mode 100644 index 00000000..dee2a0a2 --- /dev/null +++ b/LEGO1/decomp.cpp @@ -0,0 +1,9 @@ +#include "decomp.h" + +#include "Windows.h" + +// Export "Patch" function (non-mangled name) +extern "C" __declspec(dllexport) void Patch(void *root) +{ + MessageBoxA(NULL, "HELLO", "HELLO", 0); +} diff --git a/LEGO1/decomp.h b/LEGO1/decomp.h index cd179ae6..f47a2343 100644 --- a/LEGO1/decomp.h +++ b/LEGO1/decomp.h @@ -12,4 +12,21 @@ typedef unsigned char undefined; typedef unsigned short undefined2; typedef unsigned int undefined4; +#ifdef ISLE_BUILD_PATCH + +class PatchHook +{ +public: + PatchHook(void *p_ourFunc, void *p_origFunc); +}; + +#define PATCH_HOOK(ourFunc, origFunc) \ + static PatchHook _patchHook_##__COUNTER__ ((void *)ourFunc, (void *)origFunc) + +#else + +#define PATCH_HOOK(ourFunc, origFunc) + +#endif + #endif // DECOMP_H diff --git a/LEGO1/mxtransitionmanager.cpp b/LEGO1/mxtransitionmanager.cpp index f66f4bae..c985aaec 100644 --- a/LEGO1/mxtransitionmanager.cpp +++ b/LEGO1/mxtransitionmanager.cpp @@ -192,6 +192,11 @@ MxResult MxTransitionManager::StartTransition(TransitionType p_animationType, Mx return FAILURE; } +void Test() +{ + MxResult (MxTransitionManager:: * pfTarget)(MxTransitionManager::TransitionType, MxS32, MxBool, MxBool) = MxTransitionManager::StartTransition; +} + // OFFSET: LEGO1 0x1004c170 void MxTransitionManager::Transition_Wipe() {