├── .gitignore ├── BUILD.md ├── COPYING ├── COPYING.LESSER ├── Examples ├── HelloWorld │ ├── .gitignore │ ├── HelloWorld.sln │ ├── HelloWorld │ │ ├── HelloWorld.vcxproj │ │ ├── HelloWorld.vcxproj.filters │ │ ├── HelloWorld.vcxproj.user │ │ ├── S4ModApi.h │ │ ├── S4ModApi.lib │ │ ├── dllmain.cpp │ │ └── splash.bmp │ └── README.md ├── LuaExample │ ├── .gitignore │ ├── LuaExample.sln │ ├── LuaExample │ │ ├── LuaExample.vcxproj │ │ ├── LuaExample.vcxproj.filters │ │ ├── LuaExample.vcxproj.user │ │ ├── Resource.rc │ │ ├── S4ModApi.h │ │ ├── S4ModApi.lib │ │ ├── dllmain.cpp │ │ ├── resource.h │ │ ├── rwm-down.bmp │ │ ├── rwm-hover.bmp │ │ ├── rwm.bmp │ │ ├── sm-down.bmp │ │ ├── sm-hover.bmp │ │ └── sm.bmp │ ├── README.md │ └── luaexample.png └── SelectionLimitExample │ ├── .gitignore │ ├── README.md │ ├── SelectionLimitExample.sln │ ├── SelectionLimitExample │ ├── S4ModApi.h │ ├── S4ModApi.lib │ ├── SelectionLimitExample.vcxproj │ ├── SelectionLimitExample.vcxproj.filters │ ├── SelectionLimitExample.vcxproj.user │ └── dllmain.cpp │ └── units-selected.png ├── README.md ├── S4ModApi.sln ├── S4ModApi ├── .gitignore ├── CBltHook.cpp ├── CBltHook.h ├── CCustomUi.cpp ├── CCustomUi.h ├── CDialog.cpp ├── CDialog.h ├── CEntityHook.cpp ├── CEntityHook.h ├── CFrameHook.cpp ├── CFrameHook.h ├── CGuiBltHook.cpp ├── CGuiBltHook.h ├── CGuiClearHook.cpp ├── CGuiClearHook.h ├── CGuiElementBltHook.cpp ├── CGuiElementBltHook.h ├── CHook.cpp ├── CHook.h ├── CLuaOpenHook.cpp ├── CLuaOpenHook.h ├── CMapInitHook.cpp ├── CMapInitHook.h ├── CMessageBox.cpp ├── CMessageBox.h ├── CMod.cpp ├── CMod.h ├── CMouseHook.cpp ├── CMouseHook.h ├── CS4Build.cpp ├── CS4Casting.cpp ├── CS4CustomUi.cpp ├── CS4Debug.cpp ├── CS4Entity.cpp ├── CS4Error.cpp ├── CS4GarrisonWarriors.cpp ├── CS4GoodDistribution.cpp ├── CS4Landscape.cpp ├── CS4Listeners.cpp ├── CS4MenuEvents.cpp ├── CS4Misc.cpp ├── CS4Recruit.cpp ├── CS4Screen.cpp ├── CS4Scripting.cpp ├── CS4Selection.cpp ├── CS4SendWarriors.cpp ├── CS4Singleton.cpp ├── CS4Trading.cpp ├── CS4Unknown.cpp ├── CSelectionMod.cpp ├── CSelectionMod.h ├── CSettlerSendHook.cpp ├── CSettlerSendHook.h ├── CSettlers4Api.h ├── CTickHook.cpp ├── CTickHook.h ├── CUpdate.cpp ├── CUpdate.h ├── Console.cpp ├── Console.h ├── DebugInfo.cpp ├── DebugProgram.cpp ├── DebugRender.cpp ├── DebugRender.h ├── Log.cpp ├── Log.h ├── S4CreateInterface.cpp ├── S4ModApi.h ├── S4ModApi.rc ├── S4ModApi.vcxproj ├── S4ModApi.vcxproj.filters ├── S4ModApi.vcxproj.user ├── dllmain.cpp ├── globals.cpp ├── globals.h ├── lib │ ├── .gitignore │ ├── Debug │ │ ├── Lua321.lib │ │ └── Precompiled.lib │ ├── Debug142 │ │ ├── Lua321.lib │ │ └── Precompiled.lib │ ├── Release │ │ ├── Lua321.lib │ │ └── Precompiled.lib │ ├── hlib.cpp │ ├── hlib.h │ ├── lauxlib.h │ ├── lua.h │ ├── luadebug.h │ └── lualib.h ├── md5.cpp ├── md5.h ├── module.cpp ├── module.h ├── patterns.cpp ├── patterns.h ├── resource.h ├── s4.cpp ├── s4.h ├── safemem.cpp └── safemem.h ├── UpdateExamples.bat └── VERSION.md /.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore for C++ 2 | # Compiled Object files 3 | *.slo 4 | *.lo 5 | *.o 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # Visual Studio Files 17 | /Debug 18 | /Release 19 | /Debug142 20 | *.suo 21 | *.csproj.user 22 | *.vbproj.user 23 | ipch 24 | *sdf 25 | .vs 26 | *.aps 27 | 28 | /PackageRelease.bat 29 | /*.zip 30 | *.xcf 31 | deploy.bat 32 | -------------------------------------------------------------------------------- /BUILD.md: -------------------------------------------------------------------------------- 1 | # S4ModApi Build Instructions 2 | 3 | To build the S4ModApi project, you will need Visual Studio 2019 and the build tools v141_xp and v142 installed. 4 | 5 | It is also sufficient to only have build tools v142 installed if you only want to create debug builds. The release is build using the v141_xp build tools. 6 | 7 | 8 | 9 | ## IDE Setup 10 | 11 | 1. Choose and download a Version of Visual Studio from [here](https://visualstudio.microsoft.com/de/downloads/). If you need help installing it, follow [these instructions](https://docs.microsoft.com/en-us/visualstudio/install/install-visual-studio?view=vs-2019). 12 | 2. Choose the following workloads during installation: 13 | * **Desktop development with C++** 14 | * **C++ Windows XP support for VS 2017** 15 | 16 | This will install the latest MSVC Buildtools for x64/x86 v142 and v141_xp. 17 | 18 | 19 | 20 | ## Build Configurations 21 | 22 | The project can be build using one of the following configurations. 23 | 24 | | Configuration | Description | 25 | | ------------- | ------------------------------------------------------------ | 26 | | Release | Create a release build using the v141_xp build tools. Logging and console is disabled. | 27 | | Debug | Create a debug build using the v141_xp build tools. Logging and console is enabled. | 28 | | Debug142 | Create a debug build using the v142 build tools. Logging and console is enabled. | 29 | 30 | Note: If you only have the build tools v142 installed, make sure to change the configuration to Debug142. 31 | 32 | To build all configurations in one step do the following. 33 | 34 | 1. Open the **S4ModApi.sln** in Visual Studio 2019. 35 | 2. In the top menu select **Build** and click **Batch build**. 36 | 3. Make sure all configurations are selected and click **Build**. 37 | 38 | 39 | 40 | ## Deployment 41 | 42 | You can create a deploy script in the Release, Debug, Debug142 output directories. It will be automatically called when a build finished. You can use it to copy the S4ModApi.dll to your game installation. 43 | 44 | Example of a deploy.bat: 45 | 46 | ```shell 47 | copy %0\..\S4ModApi.dll "G:\Programme\The Settlers History Collection\The Settlers IV\" 48 | exit 0 49 | ``` 50 | 51 | 52 | 53 | ## Packaging 54 | 55 | Run the PackageRelease.bat script to create a zip file containing the following files. 56 | 57 | | File | Description | 58 | | ------------ | ------------------------------------------------------------ | 59 | | LICENSE.md | MIT license file for the binary distribution. | 60 | | S4ModApi.dll | The S4ModApi library that players must install. | 61 | | S4ModApi.h | The header that mod developers must install. | 62 | | S4ModApi.lib | An import library that modders can use to link against S4ModApi.dll. | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Examples/HelloWorld/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore for C++ 2 | # Compiled Object files 3 | *.slo 4 | *.lo 5 | *.o 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # Visual Studio Files 17 | Debug 18 | Release 19 | *.suo 20 | *.csproj.user 21 | *.vbproj.user 22 | ipch 23 | *sdf 24 | .vs 25 | *.aps 26 | -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorld", "HelloWorld\HelloWorld.vcxproj", "{38C5D2B2-2026-42A6-8C31-7BCC5FD25A08}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x86 = Release|x86 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {38C5D2B2-2026-42A6-8C31-7BCC5FD25A08}.Release|x86.ActiveCfg = Release|Win32 14 | {38C5D2B2-2026-42A6-8C31-7BCC5FD25A08}.Release|x86.Build.0 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {AA9D3F68-8F50-4240-8656-FD39F4A0CB74} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld/HelloWorld.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | 16.0 11 | Win32Proj 12 | {38c5d2b2-2026-42a6-8c31-7bcc5fd25a08} 13 | HelloWorld 14 | 10.0 15 | HelloWorld 16 | 17 | 18 | 19 | DynamicLibrary 20 | false 21 | v142 22 | true 23 | Unicode 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | false 36 | .asi 37 | 38 | 39 | 40 | Level3 41 | true 42 | true 43 | true 44 | WIN32;NDEBUG;HelloWorld_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 45 | true 46 | 47 | 48 | Windows 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | if exist "$(OutDir)deploy.bat" (call "$(OutDir)deploy.bat" ) 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld/HelloWorld.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Quelldateien 20 | 21 | 22 | 23 | 24 | Headerdateien 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld/HelloWorld.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld/S4ModApi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/HelloWorld/HelloWorld/S4ModApi.lib -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | 4 | #include "S4ModApi.h" 5 | #pragma comment(lib, "S4ModApi") 6 | 7 | static S4API s4; // the interface to the Settlers 4 Mod API 8 | static LPCVOID splashHandle; // the handle to the splash image 9 | 10 | static void CleanUp() { 11 | if (NULL != splashHandle) { 12 | s4->DestroyCustomUiElement(splashHandle); 13 | splashHandle = NULL; 14 | } 15 | if (NULL != s4) { 16 | s4->Release(); 17 | s4 = NULL; 18 | } 19 | }; 20 | 21 | BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { 22 | switch (ul_reason_for_call) { 23 | case DLL_PROCESS_ATTACH: { 24 | s4 = S4ApiCreate(); // get an interface to the mod api 25 | if (NULL == s4) break; 26 | 27 | WCHAR imgFn[MAX_PATH]; // the filename of the splash image 28 | INT filenameLen = GetModuleFileNameW(hModule, imgFn, _countof(imgFn)) 29 | - 4; // subtract 4 to remove the .asi file ending 30 | if (filenameLen <= 0) break; 31 | 32 | // append \splash.bmp to the filename of the module 33 | wcscpy_s(&imgFn[filenameLen], _countof(imgFn) - filenameLen, L"\\splash.bmp"); 34 | 35 | S4CustomUiElement cuie = { 0 }; 36 | cuie.size = sizeof(cuie); 37 | cuie.szImg = imgFn; 38 | cuie.x = 50; 39 | cuie.y = 50; 40 | cuie.screen = S4_SCREEN_MAINMENU; 41 | cuie.actionHandler = [](LPCVOID lpUiElement, S4_CUSTOM_UI_ENUM newstate) { 42 | if (newstate & S4_CUSTOM_UI_SELECTED) { 43 | CleanUp(); 44 | } 45 | return (HRESULT)0; 46 | }; 47 | 48 | splashHandle = s4->CreateCustomUiElement(&cuie); 49 | break; 50 | } 51 | case DLL_THREAD_ATTACH: 52 | case DLL_THREAD_DETACH: 53 | break; 54 | case DLL_PROCESS_DETACH: 55 | CleanUp(); 56 | break; 57 | } 58 | return TRUE; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /Examples/HelloWorld/HelloWorld/splash.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/HelloWorld/HelloWorld/splash.bmp -------------------------------------------------------------------------------- /Examples/HelloWorld/README.md: -------------------------------------------------------------------------------- 1 | This is a example project for the S4ModApi. The goal of the Hello World Plugin is to display a hello world popup in the main menu of the game. Have a look at the [article](https://github.com/nyfrk/S4ModApi/wiki/HelloWorldPlugin) that goes step by step through this example. 2 | 3 | 4 | 5 | # License 6 | 7 | The HelloWorld example is licensed under the MIT license. -------------------------------------------------------------------------------- /Examples/LuaExample/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore for C++ 2 | # Compiled Object files 3 | *.slo 4 | *.lo 5 | *.o 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # Visual Studio Files 17 | Debug 18 | Release 19 | *.suo 20 | *.csproj.user 21 | *.vbproj.user 22 | ipch 23 | *sdf 24 | .vs 25 | *.aps 26 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LuaExample", "LuaExample\LuaExample.vcxproj", "{A33B9263-8378-4E4D-ACC8-68EE8173D199}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Release|x86 = Release|x86 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {A33B9263-8378-4E4D-ACC8-68EE8173D199}.Debug|x86.ActiveCfg = Debug|Win32 15 | {A33B9263-8378-4E4D-ACC8-68EE8173D199}.Debug|x86.Build.0 = Debug|Win32 16 | {A33B9263-8378-4E4D-ACC8-68EE8173D199}.Release|x86.ActiveCfg = Release|Win32 17 | {A33B9263-8378-4E4D-ACC8-68EE8173D199}.Release|x86.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {3B1BC253-72A6-4B3E-BCBD-D409F8386153} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/LuaExample.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 16.0 15 | Win32Proj 16 | {a33b9263-8378-4e4d-acc8-68ee8173d199} 17 | LuaExample 18 | 10.0 19 | 20 | 21 | 22 | DynamicLibrary 23 | true 24 | v142 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v142 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | .asi 47 | 48 | 49 | false 50 | .asi 51 | 52 | 53 | 54 | Level3 55 | true 56 | WIN32;_DEBUG;LUAEXAMPLE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 57 | true 58 | 59 | 60 | Windows 61 | true 62 | false 63 | 64 | 65 | if exist "$(OutDir)deploy.bat" (call "$(OutDir)deploy.bat" ) 66 | 67 | 68 | 69 | 70 | Level3 71 | true 72 | true 73 | true 74 | WIN32;NDEBUG;LUAEXAMPLE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 75 | true 76 | 77 | 78 | Windows 79 | true 80 | true 81 | true 82 | false 83 | 84 | 85 | if exist "$(OutDir)deploy.bat" (call "$(OutDir)deploy.bat" ) 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/LuaExample.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Quelldateien 20 | 21 | 22 | 23 | 24 | Headerdateien 25 | 26 | 27 | 28 | 29 | Ressourcendateien 30 | 31 | 32 | 33 | 34 | Ressourcendateien 35 | 36 | 37 | Ressourcendateien 38 | 39 | 40 | Ressourcendateien 41 | 42 | 43 | Ressourcendateien 44 | 45 | 46 | Ressourcendateien 47 | 48 | 49 | Ressourcendateien 50 | 51 | 52 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/LuaExample.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/Resource.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "winres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // Deutsch (Deutschland) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) 19 | LANGUAGE LANG_GERMAN, SUBLANG_GERMAN 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Bitmap 51 | // 52 | 53 | IDB_RWM BITMAP "rwm.bmp" 54 | 55 | IDB_RWM_DOWN BITMAP "rwm-down.bmp" 56 | 57 | IDB_RWM_HOVER BITMAP "rwm-hover.bmp" 58 | 59 | IDB_SM BITMAP "sm.bmp" 60 | 61 | IDB_SM_DOWN BITMAP "sm-down.bmp" 62 | 63 | IDB_SM_HOVER BITMAP "sm-hover.bmp" 64 | 65 | #endif // Deutsch (Deutschland) resources 66 | ///////////////////////////////////////////////////////////////////////////// 67 | 68 | 69 | 70 | #ifndef APSTUDIO_INVOKED 71 | ///////////////////////////////////////////////////////////////////////////// 72 | // 73 | // Generated from the TEXTINCLUDE 3 resource. 74 | // 75 | 76 | 77 | ///////////////////////////////////////////////////////////////////////////// 78 | #endif // not APSTUDIO_INVOKED 79 | 80 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/S4ModApi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/S4ModApi.lib -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Von Microsoft Visual C++ generierte Includedatei. 3 | // Verwendet durch Resource.rc 4 | // 5 | #define IDB_RWM 108 6 | #define IDB_RWM_DOWN 109 7 | #define IDB_RWM_HOVER 110 8 | #define IDB_SM 111 9 | #define IDB_SM_DOWN 112 10 | #define IDB_BITMAP6 113 11 | #define IDB_SM_HOVER 113 12 | 13 | // Next default values for new objects 14 | // 15 | #ifdef APSTUDIO_INVOKED 16 | #ifndef APSTUDIO_READONLY_SYMBOLS 17 | #define _APS_NEXT_RESOURCE_VALUE 114 18 | #define _APS_NEXT_COMMAND_VALUE 40001 19 | #define _APS_NEXT_CONTROL_VALUE 1001 20 | #define _APS_NEXT_SYMED_VALUE 101 21 | #endif 22 | #endif 23 | -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/rwm-down.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/rwm-down.bmp -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/rwm-hover.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/rwm-hover.bmp -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/rwm.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/rwm.bmp -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/sm-down.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/sm-down.bmp -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/sm-hover.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/sm-hover.bmp -------------------------------------------------------------------------------- /Examples/LuaExample/LuaExample/sm.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/LuaExample/sm.bmp -------------------------------------------------------------------------------- /Examples/LuaExample/README.md: -------------------------------------------------------------------------------- 1 | This is a example project for the S4ModApi. The goal of the Lua Example Plugin is to demonstrate how a plugin can interact with the games lua virtual machine by adding and calling lua functions. The plugin will add two blue buttons to the game. 2 | 3 | ![luaexample](C:\Users\WIN10\source\repos\github\S4ModApi\Examples\LuaExample\luaexample.png) 4 | 5 | When clicking the **Reveal World Map** button the lua example plugin will call the [ISettlers4Api::RevealWorldMap](https://github.com/nyfrk/S4ModApi/wiki/RevealWorldMap) method. This method will call the [Tutorial.RWM](https://s4.muffinmar.io/scripts/?id=Tutorial_RWM#Tutorial_RWM) lua function to reveal the map. Furthermore the plugin displays a text message in the notification box using [ISettlers4Api::ShowTextMessage](https://github.com/nyfrk/S4ModApi/wiki/ShowTextMessage). 6 | 7 | When clicking the **Call Ext.ShowMessage** button the lua example plugin will call the Ext.ShowMessage lua function. The plugin will add this lua function to the games lua virtual machine by using a Lua Open Hook that is provided by the S4ModApi. The Ext.ShowMessage function uses the S4ModApi to display a message using [ISettlers4Api::ShowTextMessage](https://github.com/nyfrk/S4ModApi/wiki/ShowTextMessage) method. This demonstrates how you can add custom lua functions to the games lua virtual machine and how you can call lua functions from a plugin. 8 | 9 | # License 10 | 11 | The Lua Example Plugin is licensed under the MIT license. -------------------------------------------------------------------------------- /Examples/LuaExample/luaexample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/LuaExample/luaexample.png -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore for C++ 2 | # Compiled Object files 3 | *.slo 4 | *.lo 5 | *.o 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # Visual Studio Files 17 | Debug 18 | Release 19 | *.suo 20 | *.csproj.user 21 | *.vbproj.user 22 | ipch 23 | *sdf 24 | .vs 25 | *.aps 26 | -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/README.md: -------------------------------------------------------------------------------- 1 | This is a example project for the S4ModApi. The goal of the Selection Limit Example Plugin is to showcase the removal of the unit selection limit. 2 | 3 | See https://github.com/nyfrk/S4ModApi/wiki/SetMaxSelection. 4 | 5 | ![units-selected](units-selected.png) 6 | 7 | 8 | 9 | # License 10 | 11 | The Selection Limit Example Plugin is licensed under the MIT license. -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/SelectionLimitExample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SelectionLimitExample", "SelectionLimitExample\SelectionLimitExample.vcxproj", "{38C5D2B2-2026-42A6-8C31-7BCC5FD25A08}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x86 = Release|x86 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {38C5D2B2-2026-42A6-8C31-7BCC5FD25A08}.Release|x86.ActiveCfg = Release|Win32 14 | {38C5D2B2-2026-42A6-8C31-7BCC5FD25A08}.Release|x86.Build.0 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {AA9D3F68-8F50-4240-8656-FD39F4A0CB74} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/SelectionLimitExample/S4ModApi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/SelectionLimitExample/SelectionLimitExample/S4ModApi.lib -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/SelectionLimitExample/SelectionLimitExample.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | 10 | 16.0 11 | Win32Proj 12 | {38c5d2b2-2026-42a6-8c31-7bcc5fd25a08} 13 | SelectionLimitExample 14 | 10.0 15 | SelectionLimitExample 16 | 17 | 18 | 19 | DynamicLibrary 20 | false 21 | v142 22 | true 23 | Unicode 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | false 36 | .asi 37 | 38 | 39 | 40 | Level3 41 | true 42 | true 43 | true 44 | WIN32;NDEBUG;SelectionLimitExample_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 45 | true 46 | 47 | 48 | Windows 49 | true 50 | true 51 | true 52 | false 53 | 54 | 55 | if exist "$(OutDir)deploy.bat" (call "$(OutDir)deploy.bat" ) 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/SelectionLimitExample/SelectionLimitExample.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Quelldateien 20 | 21 | 22 | 23 | 24 | Headerdateien 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/SelectionLimitExample/SelectionLimitExample.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/SelectionLimitExample/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | 4 | #include "S4ModApi.h" 5 | #pragma comment(lib, "S4ModApi") 6 | 7 | static S4API s4; // the interface to the Settlers 4 Mod API 8 | 9 | BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { 10 | switch (ul_reason_for_call) { 11 | case DLL_PROCESS_ATTACH: { 12 | s4 = S4ApiCreate(); // get an interface to the mod api 13 | if (NULL != s4) { 14 | s4->SetMaxSelection(1000); 15 | } 16 | break; 17 | } 18 | case DLL_THREAD_ATTACH: 19 | case DLL_THREAD_DETACH: 20 | break; 21 | case DLL_PROCESS_DETACH: 22 | // cleanup 23 | if (NULL != s4) { 24 | s4->SetMaxSelection(100); 25 | s4->Release(); 26 | s4 = NULL; 27 | } 28 | break; 29 | } 30 | return TRUE; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Examples/SelectionLimitExample/units-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/Examples/SelectionLimitExample/units-selected.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # S4ModApi [![GitHub release (latest by date)](https://img.shields.io/github/v/release/nyfrk/S4ModApi)](https://github.com/nyfrk/S4ModApi/releases/latest) 2 | A modding library for Bluebyte's The Settlers 4. The goal of this project is to provide a API to mod developers such that they do not have to resort to reverse engineer the game themselves. 3 | 4 | 5 | 6 | ## Features 7 | 8 | * Create custom UI elements that the player can interact with 9 | * Create player events programmatically 10 | * Run code on specific events 11 | * Dispatch access to common hooks fairly to mods thus reducing conflicts between them 12 | * Simplify ASI mod creation by providing common functions for modding 13 | * Manages a backward compatible ABI for the API 14 | * Single header file 15 | * Open Source 16 | 17 | 18 | 19 | ## Installation for Players 20 | 21 | [Download a release](https://github.com/nyfrk/S4ModApi/releases) and unpack the S4ModApi.dll next to your S4_Main.exe. 22 | 23 | 24 | 25 | ## Remarks for Modders 26 | 27 | Note: The ABI is stable and backward compatible only if you link against the latest release. **Do not distribute your mod linking to a prerelease** (labeled with RC) since the ABI is not stable and not backward compatible. Your mod will break with upcoming releases. Read the [versioning guide](VERSION.md) for more information regarding ABI stability. 28 | 29 | See the [hello world sample mod](https://github.com/nyfrk/S4ModApi/wiki/HelloWorldPlugin) on how to configure your project with the S4ModApi. 30 | 31 | [The **reference** of the API is available in the Wiki](https://github.com/nyfrk/S4ModApi/wiki) 32 | 33 | Please consider contributing features that that we currently do not offer back to this project. You can make sure that your mod stays compatible with upcoming and past releases of The Settlers 4, if you link to the S4ModApi.dll instead of directly linking to the S4_Main.exe. Moreover does it reduce the risk of conflicts between plugins and other mods. 34 | 35 | 36 | 37 | ## Contribute 38 | 39 | We are open for pull requests! 40 | 41 | Follow the [build instructions](BUILD.md) if you want to build the S4ModApi.dll and it's import library. 42 | 43 | Some source files are only provided as precompiled obj files. This is due to license issues. 44 | 45 | 46 | 47 | ## Acknowledgments 48 | 49 | Special thanks to the following contributors. Without their work this project would not be as far as it is today. 50 | 51 | - [**MuffinMario**](https://github.com/MuffinMario) for the creation of [s4.muffinmar.io](https://s4.muffinmar.io/scripts/) and the reversal / documentation of the Lua interface including all function names, their parameters and many enumerations. 52 | - [**Viciten**](https://github.com/Viciten) for the support of [alpha blended bitmaps](https://github.com/nyfrk/S4ModApi/commit/134d532b83d201f43f18b699d877021f512411d3). 53 | - [**oberstrike**](https://github.com/oberstrike) for the contribution of [features and bugfixes](https://github.com/oberstrike/S4ModApi) 54 | - [**WizzardMaker**](https://github.com/WizzardMaker) for the contributions of [features and bugfixes](https://github.com/WizzardMaker/S4ModApi). 55 | 56 | 57 | 58 | ## License 59 | 60 | The S4ModApi project is licensed under the GNU Lesser General Public License version 3 (LGPLv3). See [COPYING.LESSER](COPYING.LESSER) file for details. 61 | 62 | -------------------------------------------------------------------------------- /S4ModApi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29503.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "S4ModApi", "S4ModApi\S4ModApi.vcxproj", "{80F4B5D7-9AB1-4DA7-B3A9-C13241352964}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Debug142|x86 = Debug142|x86 12 | Release|x86 = Release|x86 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {80F4B5D7-9AB1-4DA7-B3A9-C13241352964}.Debug|x86.ActiveCfg = Debug|Win32 16 | {80F4B5D7-9AB1-4DA7-B3A9-C13241352964}.Debug|x86.Build.0 = Debug|Win32 17 | {80F4B5D7-9AB1-4DA7-B3A9-C13241352964}.Debug142|x86.ActiveCfg = Debug142|Win32 18 | {80F4B5D7-9AB1-4DA7-B3A9-C13241352964}.Debug142|x86.Build.0 = Debug142|Win32 19 | {80F4B5D7-9AB1-4DA7-B3A9-C13241352964}.Release|x86.ActiveCfg = Release|Win32 20 | {80F4B5D7-9AB1-4DA7-B3A9-C13241352964}.Release|x86.Build.0 = Release|Win32 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | GlobalSection(ExtensibilityGlobals) = postSolution 26 | SolutionGuid = {779B4EE4-8F36-40ED-9D04-EEE5F670A740} 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /S4ModApi/.gitignore: -------------------------------------------------------------------------------- 1 | /Debug 2 | /Release 3 | /Debug142 4 | /CFrameHook.cpp 5 | /CMouseHook.cpp 6 | /CS4SendWarriors.cpp -------------------------------------------------------------------------------- /S4ModApi/CBltHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CBltHook : public CHook { 27 | public: 28 | static CBltHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CBltHook(); 37 | static BOOL __stdcall CBltHook::OnBlt(DWORD caller, DWORD ecx, DWORD edx, DWORD _0, DWORD _1, DWORD _2, DWORD _3, DWORD _4, DWORD _5, DWORD _6); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CCustomUi.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "windows.h" 25 | #include 26 | #include 27 | #include 28 | #include "S4ModApi.h" 29 | #include "CDialog.h" 30 | 31 | class CCustomUi; 32 | 33 | class CCustomUi : public CDialog { 34 | public: 35 | CCustomUi(LPCS4CUSTOMUIELEMENT); 36 | S4_CUSTOM_UI_ENUM GetState(); 37 | void SetHandler(LPS4UICALLBACK); 38 | ~CCustomUi(); 39 | 40 | protected: 41 | virtual BOOL OnDraw(HDC hdc, const POINT* cursor, const RECT* clientRect) override; 42 | virtual BOOL OnMouse(DWORD dwMouseButton, INT iX, INT iY, DWORD dwMsgId, HWND hwnd) override; 43 | virtual BOOL OnShow() override; // do not call Hide() from here (will deadlock) 44 | virtual BOOL OnHide() override; // do not call Show() from here (will deadlock) 45 | 46 | private: 47 | CCustomUi(const CCustomUi&) = delete; 48 | CCustomUi& operator=(CCustomUi const&) = delete; 49 | 50 | S4_GUI_ENUM m_screenFilter; 51 | RECT m_rect, m_hoverRect, m_selectedRect, m_selectedHoverRect; 52 | HBITMAP m_hImg, m_hImgHover, m_hImgSelected, m_hImgSelectedHover; 53 | std::mutex m_bitmap_mtx; 54 | bool m_visible; 55 | 56 | S4_CUSTOM_UI_ENUM m_state; 57 | volatile LPS4UICALLBACK m_handler; 58 | volatile LPS4UIFILTERCALLBACK m_filterFunc; 59 | }; 60 | -------------------------------------------------------------------------------- /S4ModApi/CDialog.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "windows.h" 25 | #include 26 | #include 27 | #include "S4ModApi.h" 28 | 29 | #define DIALOG_RENDER_PRIORITY 100001 30 | 31 | class CDialog { 32 | public: 33 | const enum FeaturesEnum : unsigned { FeatureNone = 0, FeatureOnMouse = 1, FeatureOnDraw = 2, FeatureAll = 3 } DialogFeatures; 34 | 35 | CDialog(INT x, INT y, INT w, INT h, DWORD flags, FeaturesEnum = FeatureAll); 36 | CDialog(DWORD flags = 0, FeaturesEnum = FeatureAll); 37 | BOOL Show(); 38 | BOOL Hide(); 39 | BOOL IsShown() const; 40 | BOOL HasFeature(const FeaturesEnum &f) const; 41 | const RECT& GetRect() const; 42 | 43 | virtual ~CDialog(); 44 | 45 | protected: 46 | virtual BOOL OnDraw(HDC hdc, const POINT *cursor, const RECT* clientRect); 47 | virtual BOOL OnMouse(DWORD dwMouseButton, INT iX, INT iY, DWORD dwMsgId, HWND hwnd); 48 | virtual BOOL OnShow(); // do not call Hide() from here (will deadlock) 49 | virtual BOOL OnHide(); // do not call Show() from here (will deadlock) 50 | VOID UpdatePositionWithOffsetsFlags(const RECT& source, const RECT* clientRect); 51 | 52 | RECT m_position; 53 | DWORD m_flags; 54 | static S4API s4api; 55 | 56 | private: 57 | CDialog(const CDialog&) = delete; 58 | CDialog& operator=(CDialog const&) = delete; 59 | 60 | volatile bool m_isShown; 61 | 62 | static void Cleanup(); 63 | 64 | static void MaintainS4Api(); 65 | void ModifyFeatureCounts(signed add); 66 | 67 | static std::mutex state_mutex; 68 | static std::condition_variable condIdle; 69 | static std::vector pending_dialogs; 70 | static volatile enum State : unsigned { StateIdle, StateBusy, StateBusyCleanupRequired } state; 71 | static std::vector dialogs; // how many messageboxes are visible 72 | static S4HOOK hFramehook, hMousehook; 73 | static unsigned countFramehook, countMousehook; 74 | 75 | static HRESULT S4HCALL OnFrameProc(LPDIRECTDRAWSURFACE7 lpSurface, INT32 iPillarboxWidth, LPVOID lpReserved); 76 | static HRESULT S4HCALL OnMouseProc(DWORD dwMouseButton, INT iX, INT iY, DWORD dwMsgId, HWND hwnd, LPCS4UIELEMENT lpUiElement); 77 | }; 78 | -------------------------------------------------------------------------------- /S4ModApi/CEntityHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // JmpPatch 24 | #include "patterns.h" 25 | 26 | #include "CEntityHook.h" 27 | 28 | static hlib::CallPatch OnEntityHook; 29 | 30 | BOOL __stdcall CEntityHook::OnEntity() { 31 | return 0; 32 | } 33 | 34 | //static void __declspec(naked) __onEntity() { 35 | // // todo: add entity hook 36 | // __asm { 37 | // ret 38 | // } 39 | //} 40 | 41 | CEntityHook& CEntityHook::GetInstance() { 42 | static CEntityHook inst; 43 | return inst; 44 | } 45 | 46 | bool CEntityHook::Init() { 47 | TRACE; 48 | /*DWORD addr = g_Patterns.xxx; 49 | if (!addr) return false; 50 | 51 | OnEntityHook = hlib::CallPatch(addr, (DWORD)__onEntity);*/ 52 | 53 | return true; 54 | } 55 | 56 | void CEntityHook::Patch() { 57 | TRACE; 58 | OnEntityHook.patch(); 59 | } 60 | 61 | void CEntityHook::Unpatch() { 62 | TRACE; 63 | OnEntityHook.unpatch(); 64 | } 65 | 66 | CEntityHook::CEntityHook() { TRACE; } 67 | 68 | 69 | -------------------------------------------------------------------------------- /S4ModApi/CEntityHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CEntityHook : public CHook { 27 | public: 28 | static CEntityHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CEntityHook(); 37 | static BOOL __stdcall CEntityHook::OnEntity(); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CFrameHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // JmpPatch 24 | #include "s4.h" 25 | #include "patterns.h" 26 | 27 | #include "CSettlers4Api.h" 28 | #include "CFrameHook.h" 29 | #include "Console.h" 30 | 31 | static hlib::JmpPatch OnFrameHook; 32 | static DWORD* pBase = nullptr; 33 | 34 | DWORD __stdcall CFrameHook::OnFrame() { 35 | TRACE; 36 | // cache the IsCurrentlyOnScreen results in this array 37 | BYTE s4_gui_state[S4_GUI_ENUM_MAXVALUE] = { 0 }; // 0 == unknown, 1 == visible, 2 == hidden 38 | if (pBase) { 39 | INT32 pillarboxWidth = 0; 40 | if (S4::GetInstance().PillarboxWidth) pillarboxWidth = *S4::GetInstance().PillarboxWidth; 41 | LPDIRECTDRAWSURFACE7 dst = (LPDIRECTDRAWSURFACE7)(*(DWORD*)(*(DWORD*)(*(DWORD*)(*pBase) + (g_isGE ? 0x3C : 0x5C)) + 0x4)); 42 | mutex.lock(); 43 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 44 | mutex.unlock(); 45 | for (auto& observer : observers) { 46 | auto& param = observer.param; 47 | if (param && param < S4_GUI_ENUM_MAXVALUE) { 48 | switch (s4_gui_state[param]) { 49 | case 0: { 50 | auto res = CSettlers4Api::GetInstance().IsCurrentlyOnScreen((S4_GUI_ENUM)param); 51 | s4_gui_state[param] = res ? 1 : 2; 52 | if (res) break; else continue; 53 | } 54 | case 1: break; 55 | default: continue; 56 | } 57 | } 58 | ((LPS4FRAMECALLBACK)observer.callback)(dst, pillarboxWidth, 0); 59 | } 60 | } 61 | return (DWORD)(OnFrameHook.getAddress() + 5); 62 | } 63 | 64 | static void __declspec(naked) __onFrame() { 65 | __asm { 66 | push ecx 67 | push edx 68 | call CFrameHook::OnFrame 69 | pop edx 70 | pop ecx 71 | pop edi 72 | pop esi 73 | cmp g_isGE, 0 74 | jz lbl_HE 75 | pop ebp // gold edition 76 | jmp lbl_end 77 | lbl_HE : 78 | pop ebx // history edition 79 | lbl_end : 80 | push eax 81 | mov al, 01 82 | ret 83 | } 84 | } 85 | 86 | CFrameHook& CFrameHook::GetInstance() { 87 | static CFrameHook inst; 88 | return inst; 89 | } 90 | 91 | bool CFrameHook::Init() { 92 | TRACE; 93 | if (!g_Patterns.OnFrameHook || !g_Patterns.Backbuffer) return false; 94 | 95 | OnFrameHook = hlib::JmpPatch(g_Patterns.OnFrameHook + 12, (DWORD)__onFrame); 96 | pBase = (DWORD*)(g_Patterns.Backbuffer + (g_isGE ? 34 : 22)); 97 | 98 | return true; 99 | } 100 | 101 | void CFrameHook::Patch() { 102 | TRACE; 103 | OnFrameHook.patch(); 104 | } 105 | 106 | void CFrameHook::Unpatch() { 107 | TRACE; 108 | OnFrameHook.unpatch(); 109 | } 110 | 111 | CFrameHook::CFrameHook() { TRACE; } 112 | -------------------------------------------------------------------------------- /S4ModApi/CFrameHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CFrameHook : public CHook { 27 | public: 28 | static CFrameHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CFrameHook(); 37 | static DWORD __stdcall OnFrame(); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CGuiBltHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // JmpPatch 24 | #include "patterns.h" 25 | 26 | #include "CGuiBltHook.h" 27 | 28 | static hlib::CallPatch OnComposeBltHook, OnSettlerIdHook; 29 | 30 | BOOL __stdcall CGuiBltHook::OnBlt(DWORD id, LPVOID dstSurface, LPRECT dstRect, LPVOID srcSurface, LPRECT srcRect, DWORD ddbltFlags, LPVOID ddbltfx) { 31 | //TRACE; // we do not log this as it will be a mayor performance hit 32 | mutex.lock(); 33 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 34 | mutex.unlock(); 35 | BOOL discard = false; 36 | S4GuiBltParams params; 37 | 38 | params.id = id / 4; // id goes from 0x130 (incl) to 0x167 (excl) 39 | params.dstSurface = dstSurface; 40 | params.dstRect = dstRect; 41 | params.srcSurface = srcSurface; 42 | params.srcRect = srcRect; 43 | params.ddbltFlags = ddbltFlags; 44 | params.ddbltfx = ddbltfx; 45 | 46 | for (auto& observer : observers) { 47 | discard |= ((LPS4GUIBLTCALLBACK)observer.callback)(¶ms, discard); 48 | } 49 | 50 | return discard; 51 | } 52 | 53 | static void __declspec(naked) __onBlt() { 54 | __asm { 55 | sub esp, 16 56 | movdqu[esp], xmm0 57 | sub esp, 16 58 | movdqu[esp], xmm1 59 | sub esp, 16 60 | movdqu[esp], xmm2 61 | sub esp, 16 62 | movdqu[esp], xmm3 63 | sub esp, 16 64 | movdqu[esp], xmm4 65 | sub esp, 16 66 | movdqu[esp], xmm5 67 | sub esp, 16 68 | movdqu[esp], xmm6 69 | sub esp, 16 70 | movdqu[esp], xmm7 71 | sub esp, 128 72 | fsave[esp] 73 | 74 | push ecx 75 | push[esp + 256 + 4 + 20] 76 | push[esp + 256 + 4 + 20] 77 | push[esp + 256 + 4 + 20] 78 | push[esp + 256 + 4 + 20] 79 | push[esp + 256 + 4 + 20] 80 | push ecx 81 | push edi 82 | call CGuiBltHook::OnBlt 83 | pop ecx 84 | 85 | frstor[esp] 86 | add esp, 128 87 | movdqu xmm7, [esp] 88 | add esp, 16 89 | movdqu xmm6, [esp] 90 | add esp, 16 91 | movdqu xmm5, [esp] 92 | add esp, 16 93 | movdqu xmm4, [esp] 94 | add esp, 16 95 | movdqu xmm3, [esp] 96 | add esp, 16 97 | movdqu xmm2, [esp] 98 | add esp, 16 99 | movdqu xmm1, [esp] 100 | add esp, 16 101 | movdqu xmm0, [esp] 102 | add esp, 16 103 | 104 | test al, al 105 | pushf 106 | xor eax, eax 107 | popf 108 | jnz lbl_skip_original 109 | push[esp + 20] 110 | push[esp + 20] 111 | push[esp + 20] 112 | push[esp + 20] 113 | push[esp + 20] 114 | call [esi + 0x18] 115 | 116 | lbl_skip_original: 117 | 118 | pop esi // ret addr 119 | add esp, 20 // clean the stack 120 | 121 | push esi 122 | test eax, eax 123 | ret 124 | } 125 | } 126 | 127 | CGuiBltHook& CGuiBltHook::GetInstance() { 128 | static CGuiBltHook inst; 129 | return inst; 130 | } 131 | 132 | bool CGuiBltHook::Init() { 133 | TRACE; 134 | /* 135 | S4_Main.exe+2647C6 - 8B 45 FC - mov eax,[ebp-04] 136 | S4_Main.exe+2647C9 - 8B 15 08875401 - mov edx,[S4_Main.exe+1058708] { (04860720) } 137 | S4_Main.exe+2647CF - 8D 80 D8456E01 - lea eax,[eax+S4_Main.exe+11F45D8] 138 | S4_Main.exe+2647D5 - 8B 4A 5C - mov ecx,[edx+5C] 139 | S4_Main.exe+2647D8 - 50 - push eax 140 | S4_Main.exe+2647D9 - 8B 45 FC - mov eax,[ebp-04] 141 | S4_Main.exe+2647DC - FF 34 17 - push [edi+edx] 142 | S4_Main.exe+2647DF - 8B 31 - mov esi,[ecx] 143 | S4_Main.exe+2647E1 - 8D 80 B8466E01 - lea eax,[eax+S4_Main.exe+11F46B8] 144 | S4_Main.exe+2647E7 - 50 - push eax 145 | S4_Main.exe+2647E8 - FF 56 18 - call dword ptr [esi+18] <--- we hook here, 5 arguments + ecx 146 | S4_Main.exe+2647EB - 85 C0 - test eax,eax 147 | 148 | */ 149 | 150 | 151 | DWORD addr = S4_Main != 0 ? S4_Main + 0x2647E8 : 0; 152 | if (!addr) return false; 153 | 154 | OnComposeBltHook = hlib::CallPatch(addr, (DWORD)__onBlt); 155 | 156 | return true; 157 | } 158 | 159 | void CGuiBltHook::Patch() { 160 | TRACE; 161 | OnComposeBltHook.patch(); 162 | } 163 | 164 | void CGuiBltHook::Unpatch() { 165 | TRACE; 166 | OnComposeBltHook.unpatch(); 167 | } 168 | 169 | CGuiBltHook::CGuiBltHook() { TRACE; } 170 | -------------------------------------------------------------------------------- /S4ModApi/CGuiBltHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CGuiBltHook : public CHook { 27 | public: 28 | static CGuiBltHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CGuiBltHook(); 37 | static BOOL __stdcall OnBlt(DWORD id, LPVOID dstSurface, LPRECT dstRect, LPVOID srcSurface, LPRECT srcRect, DWORD ddbltFlags, LPVOID ddbltfx); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CGuiClearHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // JmpPatch 24 | #include "patterns.h" 25 | #include "safemem.h" 26 | 27 | #include "CGuiClearHook.h" 28 | 29 | static hlib::JmpPatch OnClearHook; 30 | DWORD Orig; // you store the original function address here. Populate it before you install the call patch. 31 | DWORD backJmp; 32 | 33 | struct GUIContainer { 34 | WORD type; 35 | WORD x; 36 | WORD y; 37 | WORD width; 38 | WORD height; 39 | WORD mainTexture; 40 | WORD transparency; 41 | WORD containerPointer; 42 | //sizeof == 36 43 | }; 44 | 45 | #pragma optimize("", off) 46 | void __stdcall CGuiClearHook::OnClear(DWORD *surfaceContainer) { 47 | //TRACE; // we do not log this as it will be a mayor performance hit 48 | mutex.lock(); 49 | auto observers = GetInstance().observers; // obtain a copy of all the observers since the callbacks may modify the vector 50 | mutex.unlock(); 51 | BOOL discard = false; 52 | S4GuiClearParams params; 53 | GUIContainer *c = (GUIContainer*)surfaceContainer; 54 | params.surfaceWidth = c->width; 55 | params.surfaceHeight = c->height; 56 | params.x = c->x; 57 | params.y = c->y; 58 | params.surfaceId = c->type; 59 | 60 | // iterate observers 61 | for (auto& observer : observers) { 62 | discard |= ((LPS4GUICLEARCALLBACK)observer.callback)(¶ms, discard); 63 | } 64 | 65 | return; 66 | } 67 | #pragma optimize("", on) 68 | 69 | static void __declspec(naked) __onHook() { 70 | __asm { 71 | call Orig 72 | 73 | 74 | push esi 75 | call CGuiClearHook::OnClear // we call your stdcall hook procedure, this is allowed to change eax, ecx and edx as well as the xmm / fpu registers 76 | 77 | 78 | jmp backJmp 79 | } 80 | } 81 | 82 | CGuiClearHook& CGuiClearHook::GetInstance() { 83 | static CGuiClearHook inst; 84 | return inst; 85 | } 86 | 87 | bool CGuiClearHook::Init() { 88 | TRACE; 89 | 90 | const DWORD addr = S4_Main != 0 ? S4_Main + 0x0027227F : 0; 91 | if (!addr) return false; 92 | Orig = S4_Main + 0x25F000; 93 | backJmp = S4_Main + 0x00272284; 94 | OnClearHook = hlib::JmpPatch(addr, (DWORD)__onHook); 95 | 96 | return true; 97 | } 98 | 99 | void CGuiClearHook::Patch() { 100 | TRACE; 101 | OnClearHook.patch(); 102 | } 103 | 104 | void CGuiClearHook::Unpatch() { 105 | TRACE; 106 | OnClearHook.unpatch(); 107 | } 108 | 109 | CGuiClearHook::CGuiClearHook() { TRACE; } 110 | -------------------------------------------------------------------------------- /S4ModApi/CGuiClearHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CGuiClearHook : public CHook { 27 | public: 28 | static CGuiClearHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CGuiClearHook(); 37 | static void __stdcall OnClear(DWORD *container); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CGuiElementBltHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CGuiElementBltHook : public CHook { 27 | public: 28 | static CGuiElementBltHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CGuiElementBltHook(); 37 | static BOOL __stdcall OnElementBlt(DWORD _0, DWORD _1, DWORD, DWORD _2, DWORD _3, DWORD _4); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CHook.h" 23 | #include "Console.h" 24 | #include 25 | #include "module.h" 26 | 27 | void CHook::InitAll() { 28 | TRACE; 29 | const std::lock_guard lock(mutex); 30 | for (auto& inst : instances) inst->Setup(); 31 | } 32 | 33 | HRESULT CHook::RemoveListener(S4HOOK hook) { 34 | TRACE; 35 | if (hook != 0) { 36 | const std::lock_guard lock(mutex); 37 | for (auto& inst : instances) { 38 | auto& observers = inst->observers; 39 | for (auto it = observers.rbegin(); it != observers.rend(); ++it) { 40 | if (it->id == hook) { 41 | DecreaseModuleRefcount(it->mod); 42 | observers.erase((++it).base()); 43 | if (hook < lowestFreeId) lowestFreeId = hook; 44 | if (observers.empty()) { 45 | inst->Uninstall(); 46 | } 47 | LOG("remove listener " << dec << hook << " with S_OK"); 48 | return S_OK; 49 | } 50 | } 51 | } 52 | } 53 | 54 | LOG("error: remove listener " << dec << hook << " returns with E_HANDLE"); 55 | return E_HANDLE; 56 | } 57 | 58 | S4HOOK CHook::FindFreeObserverId() { 59 | TRACE; 60 | std::vector usedS4HookIDsVec; // bit (!) vector that tracks used IDs 61 | // build bit vector 62 | for (auto& inst : instances) { 63 | for (auto& observer : inst->observers) { 64 | if (observer.id >= usedS4HookIDsVec.size()) 65 | usedS4HookIDsVec.resize(observer.id); 66 | usedS4HookIDsVec[observer.id - 1] = true; 67 | } 68 | } 69 | 70 | // find first bit that is 0 71 | auto sz = usedS4HookIDsVec.size(); 72 | for (UINT32 i = 0; i < sz; i++) { 73 | if (!usedS4HookIDsVec[i]) 74 | return i + 1; 75 | } 76 | return sz + 1; 77 | } 78 | 79 | S4HOOK CHook::AddListener(LPCVOID lpCallback, DWORD dwParam, INT iPriority) { 80 | TRACE; 81 | if (lpCallback == NULL) { 82 | LOG("error: lpCallback is NULL"); 83 | return 0; 84 | } 85 | auto mod = IncreaseModuleRefcount(lpCallback); 86 | if (!mod) { 87 | LOG("error: cannot lock code of callback in memory"); 88 | return 0; // already unloaded? 89 | } 90 | const std::lock_guard lock(mutex); 91 | Install(); 92 | auto hookId = FindFreeObserverId(); 93 | ObserverEntry entry(lpCallback, hookId, dwParam, iPriority, mod); 94 | // insert listener according to priority (keeps vector sorted by priority) 95 | observers.insert( 96 | std::upper_bound( 97 | observers.begin(), 98 | observers.end(), 99 | entry, 100 | [](const ObserverEntry& a, const ObserverEntry& b) { return a.priority < b.priority; }), 101 | entry); 102 | LOG("inserted callback " << HEXNUM(lpCallback) << dec << " with param " << dec << dwParam << " in module " << HEXNUM(mod) << ". S4HOOK == " << dec << hookId); 103 | return hookId; 104 | } 105 | 106 | CHook::CHook() { 107 | TRACE; 108 | const std::lock_guard lock(mutex); 109 | instances.push_back(this); 110 | } 111 | 112 | CHook::~CHook() { 113 | TRACE; 114 | const std::lock_guard lock(mutex); 115 | auto it = std::find(instances.rbegin(), instances.rend(), this); 116 | if (it != instances.rend()) { 117 | instances.erase((++it).base()); 118 | } 119 | } 120 | 121 | void CHook::Setup() { 122 | TRACE; 123 | if (m_bIsInitialized) return; 124 | m_bIsInitialized = Init(); 125 | if (!m_bIsInitialized) return; 126 | 127 | if (m_bWantInstalled) Install(); 128 | } 129 | 130 | void CHook::Install() { 131 | TRACE; 132 | if (m_bIsInstalled) return; 133 | m_bWantInstalled = true; 134 | if (!m_bIsInitialized) { // not initialized 135 | Setup(); // try initialize 136 | if (!m_bIsInitialized) return; // still not initialized 137 | } 138 | m_bIsInstalled = true; 139 | 140 | Patch(); 141 | } 142 | 143 | void CHook::Uninstall() { 144 | TRACE; 145 | if (!m_bIsInstalled) return; 146 | m_bWantInstalled = false; 147 | m_bIsInstalled = false; 148 | 149 | Unpatch(); 150 | } 151 | 152 | std::vector CHook::instances; 153 | 154 | std::recursive_mutex CHook::mutex; 155 | S4HOOK CHook::lowestFreeId = 1; 156 | 157 | CHook::ObserverEntry::ObserverEntry(LPCVOID callback, S4HOOK id, DWORD param, INT priority, HMODULE mod) : 158 | callback(callback),id(id),param(param), priority(priority), mod(mod) { 159 | TRACE; 160 | } 161 | -------------------------------------------------------------------------------- /S4ModApi/CHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | #include "S4ModApi.h" 24 | #include 25 | #include 26 | #include "Log.h" 27 | 28 | class CHook { 29 | public: 30 | void Setup(); // processes the addresses from the pattern scanner 31 | void Install(); // installs the hook 32 | void Uninstall(); // uninstalls the hook 33 | 34 | S4HOOK AddListener(LPCVOID,DWORD=0,INT=0); // register an observer 35 | static HRESULT RemoveListener(S4HOOK); // remove an observer 36 | static void InitAll(); // initialize all instantiated hooks 37 | 38 | protected: 39 | virtual bool Init() = 0; // computes target addresses based on the patterns 40 | virtual void Patch() = 0; // installs the patches/detours 41 | virtual void Unpatch() = 0; // uninstalls the patches/detours 42 | 43 | CHook(); 44 | ~CHook(); 45 | CHook(const CHook&) = delete; 46 | CHook& operator=(CHook const&) = delete; 47 | 48 | /** struct used for mapping S4HOOK to callback function **/ 49 | struct ObserverEntry { 50 | LPCVOID callback; 51 | S4HOOK id; 52 | DWORD param; 53 | INT priority; 54 | HMODULE mod; 55 | 56 | ObserverEntry() = delete; 57 | ObserverEntry(LPCVOID callback, S4HOOK id, DWORD param, INT priority, HMODULE mod); 58 | }; 59 | std::vector observers; 60 | static std::recursive_mutex mutex; 61 | 62 | private: 63 | /** all instances of the hooks **/ 64 | static std::vector instances; 65 | 66 | static S4HOOK lowestFreeId; 67 | 68 | static S4HOOK FindFreeObserverId(); // get a free id for an observer 69 | 70 | unsigned char m_bIsInstalled : 1; 71 | unsigned char m_bIsInitialized : 1; 72 | unsigned char m_bWantInstalled : 1; 73 | }; 74 | -------------------------------------------------------------------------------- /S4ModApi/CLuaOpenHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // JmpPatch 24 | #include "patterns.h" 25 | #include "safemem.h" 26 | 27 | #include "CLuaOpenHook.h" 28 | 29 | static hlib::JmpPatch OnLuaOpenHook; 30 | static DWORD backjmp, origjmp; 31 | 32 | DWORD __stdcall CLuaOpenHook::OnLuaOpen() { 33 | TRACE; 34 | mutex.lock(); 35 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 36 | mutex.unlock(); 37 | for (auto& observer : observers) { 38 | ((LPS4LUAOPENCALLBACK)observer.callback)(); 39 | } 40 | return 0; 41 | } 42 | 43 | static void __declspec(naked) __onLuaOpenHE() { 44 | __asm { 45 | call origjmp 46 | call CLuaOpenHook::OnLuaOpen 47 | jmp backjmp 48 | } 49 | } 50 | 51 | CLuaOpenHook& CLuaOpenHook::GetInstance() { 52 | static CLuaOpenHook inst; 53 | return inst; 54 | } 55 | 56 | bool CLuaOpenHook::Init() { 57 | TRACE; 58 | if (!g_Patterns.OnLuaOpenHook) return false; 59 | 60 | DWORD addr = g_Patterns.OnLuaOpenHook; 61 | if (!addr) return false; 62 | addr += 30; 63 | DWORD off = READ_AT((LPCVOID)addr, 1); 64 | if (!off) return false; 65 | origjmp = addr + off + 5; 66 | backjmp = addr + 5; 67 | OnLuaOpenHook = hlib::JmpPatch(addr, (DWORD)(__onLuaOpenHE)); 68 | 69 | return true; 70 | } 71 | 72 | void CLuaOpenHook::Patch() { 73 | TRACE; 74 | OnLuaOpenHook.patch(); 75 | } 76 | 77 | void CLuaOpenHook::Unpatch() { 78 | TRACE; 79 | OnLuaOpenHook.unpatch(); 80 | } 81 | 82 | CLuaOpenHook::CLuaOpenHook() { TRACE; } 83 | -------------------------------------------------------------------------------- /S4ModApi/CLuaOpenHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CLuaOpenHook : public CHook { 27 | public: 28 | static CLuaOpenHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CLuaOpenHook(); 37 | static DWORD __stdcall OnLuaOpen(); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CMapInitHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // JmpPatch 24 | #include "patterns.h" 25 | 26 | #include "CMapInitHook.h" 27 | 28 | static hlib::JmpPatch OnMapInitHook; 29 | static DWORD backjmp; 30 | 31 | DWORD __stdcall CMapInitHook::OnMapInit() { 32 | TRACE; 33 | mutex.lock(); 34 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 35 | mutex.unlock(); 36 | for (auto& observer : observers) { 37 | ((LPS4MAPINITCALLBACK)observer.callback)(0, 0); 38 | } 39 | return 0; 40 | } 41 | 42 | static void __declspec(naked) __onMapInitHE() { 43 | __asm { 44 | push ecx 45 | push edx 46 | 47 | call CMapInitHook::OnMapInit 48 | 49 | // the stuff we replaced 50 | lea ecx, [esi + 0x5c] 51 | 52 | mov eax, backjmp 53 | jmp eax 54 | } 55 | } 56 | 57 | static void __declspec(naked) __onMapInitGE() { 58 | __asm { 59 | // the stuff we replaced 60 | not ecx 61 | dec ecx 62 | mov edi, ecx 63 | 64 | call CMapInitHook::OnMapInit 65 | 66 | mov eax, backjmp 67 | jmp backjmp 68 | } 69 | } 70 | 71 | CMapInitHook& CMapInitHook::GetInstance() { 72 | static CMapInitHook inst; 73 | return inst; 74 | } 75 | 76 | bool CMapInitHook::Init() { 77 | TRACE; 78 | if (!g_Patterns.OnMapInitHook) return false; 79 | 80 | DWORD addr = g_Patterns.OnMapInitHook; 81 | OnMapInitHook = hlib::JmpPatch(addr, (DWORD)(g_isGE ? __onMapInitGE : __onMapInitHE)); 82 | backjmp = addr + 5; 83 | 84 | return true; 85 | } 86 | 87 | void CMapInitHook::Patch() { 88 | TRACE; 89 | OnMapInitHook.patch(); 90 | } 91 | 92 | void CMapInitHook::Unpatch() { 93 | TRACE; 94 | OnMapInitHook.unpatch(); 95 | } 96 | 97 | CMapInitHook::CMapInitHook() { TRACE; } 98 | -------------------------------------------------------------------------------- /S4ModApi/CMapInitHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CMapInitHook : public CHook { 27 | public: 28 | static CMapInitHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CMapInitHook(); 37 | static DWORD __stdcall OnMapInit(); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CMessageBox.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "windows.h" 25 | #include 26 | #include 27 | #include 28 | #include "S4ModApi.h" 29 | #include "CDialog.h" 30 | 31 | class CMessageBox; 32 | 33 | typedef HRESULT(FAR S4HCALL* LPMESSAGEBOXHANDLER)(CMessageBox* messagebox, INT reason); 34 | 35 | class CMessageBox : public CDialog { 36 | public: 37 | enum HideReasonEnum : DWORD { 38 | CMessageBox_HideReason_Default, // default state, window is hidden per default 39 | CMessageBox_HideReason_NotHidden, // the window is not hidden (is visible) 40 | CMessageBox_HideReason_Method, // hide() method was called by user 41 | CMessageBox_HideReason_OkButton, // ok button was used 42 | CMessageBox_HideReason_CloseButton, // close button was used 43 | }; 44 | 45 | CMessageBox(LPCWSTR title, LPCWSTR message, INT x, INT y, INT w, INT h, DWORD flags = 0); 46 | 47 | HideReasonEnum GetHideReason(); 48 | void SetHandler(LPMESSAGEBOXHANDLER); 49 | 50 | protected: 51 | virtual BOOL OnDraw(HDC hdc, const POINT *cursor, const RECT* client) override; 52 | virtual BOOL OnMouse(DWORD dwMouseButton, INT iX, INT iY, DWORD dwMsgId, HWND hwnd) override; 53 | virtual BOOL OnShow() override; // do not call Hide() from here (will deadlock) 54 | virtual BOOL OnHide() override; // do not call Show() from here (will deadlock) 55 | 56 | private: 57 | CMessageBox(const CMessageBox&) = delete; 58 | CMessageBox& operator=(CMessageBox const&) = delete; 59 | 60 | std::wstring m_title, m_message; 61 | RECT m_closeButton, m_okButton, m_windowRect; 62 | HideReasonEnum m_hideReason; 63 | volatile LPMESSAGEBOXHANDLER m_handler; 64 | }; 65 | -------------------------------------------------------------------------------- /S4ModApi/CMod.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CMod.h" 23 | #include "Console.h" 24 | #include 25 | #include "module.h" 26 | 27 | void CMod::InitAll() { 28 | TRACE; 29 | const std::lock_guard lock(mutex); 30 | for (auto& inst : instances) inst->Setup(); 31 | } 32 | 33 | CMod::CMod() { 34 | TRACE; 35 | const std::lock_guard lock(mutex); 36 | instances.push_back(this); 37 | } 38 | 39 | CMod::~CMod() { 40 | TRACE; 41 | const std::lock_guard lock(mutex); 42 | auto it = std::find(instances.rbegin(), instances.rend(), this); 43 | if (it != instances.rend()) { 44 | instances.erase((++it).base()); 45 | } 46 | } 47 | 48 | void CMod::Setup() { 49 | TRACE; 50 | const std::lock_guard lock(mutex); 51 | if (m_bIsInitialized) return; 52 | m_bIsInitialized = Init(); 53 | if (!m_bIsInitialized) return; 54 | 55 | if (m_bWantInstalled) Install(); 56 | } 57 | 58 | void CMod::Install() { 59 | TRACE; 60 | const std::lock_guard lock(mutex); 61 | if (m_bIsInstalled) return; 62 | m_bWantInstalled = true; 63 | if (!m_bIsInitialized) { // not initialized 64 | Setup(); // try initialize 65 | if (!m_bIsInitialized) return; // still not initialized 66 | } 67 | m_bIsInstalled = true; 68 | 69 | Patch(); 70 | } 71 | 72 | void CMod::Uninstall() { 73 | TRACE; 74 | const std::lock_guard lock(mutex); 75 | if (!m_bIsInstalled) return; 76 | m_bWantInstalled = false; 77 | m_bIsInstalled = false; 78 | 79 | Unpatch(); 80 | } 81 | 82 | bool CMod::IsInstalled() { 83 | return m_bIsInstalled; 84 | } 85 | 86 | bool CMod::IsEnabled() { 87 | return m_bWantInstalled || m_bIsInstalled; 88 | } 89 | 90 | std::vector CMod::instances; 91 | std::recursive_mutex CMod::mutex; 92 | 93 | -------------------------------------------------------------------------------- /S4ModApi/CMod.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | #include "S4ModApi.h" 24 | #include 25 | #include 26 | #include "Log.h" 27 | 28 | /// 29 | /// Mods are modifications to the game that require patterns or other initialization 30 | /// to be already performed. Mods may be activated but not installed. When initialization 31 | /// is completed all activated mods will be installed. 32 | /// 33 | /// CMod serves as a base class for mods. 34 | /// 35 | class CMod { 36 | public: 37 | void Setup(); // processes the addresses from the pattern scanner 38 | void Install(); // installs the mod 39 | void Uninstall(); // uninstalls the mod 40 | 41 | bool IsInstalled(); // mod is enabled and installed 42 | bool IsEnabled(); // mod is enabled but not yet installed 43 | 44 | static void InitAll(); // initialize all activated mods 45 | 46 | protected: 47 | virtual bool Init() = 0; // computes target addresses based on the patterns 48 | virtual void Patch() = 0; // installs the patches/detours 49 | virtual void Unpatch() = 0; // uninstalls the patches/detours 50 | 51 | CMod(); 52 | ~CMod(); 53 | CMod(const CMod&) = delete; 54 | CMod& operator=(CMod const&) = delete; 55 | 56 | static std::recursive_mutex mutex; 57 | 58 | private: 59 | /** all instances of the mods that have been constructed **/ 60 | static std::vector instances; 61 | 62 | unsigned char m_bIsInstalled : 1; 63 | unsigned char m_bIsInitialized : 1; 64 | unsigned char m_bWantInstalled : 1; 65 | }; 66 | -------------------------------------------------------------------------------- /S4ModApi/CMouseHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // CallPatch 24 | #include // GET_X_LPARAM, GET_Y_LPARAM 25 | #include "s4.h" 26 | #include "patterns.h" 27 | #include "CMouseHook.h" 28 | #include "CSettlers4Api.h" 29 | 30 | static hlib::CallPatch OnMouseButtonHook, OnMouseWheelHookHE; 31 | 32 | bool __stdcall CMouseHook::OnMouse(HWND hwnd, DWORD msg, DWORD wparam, DWORD lparam) { 33 | TRACE; 34 | S4UiElement uiElement; 35 | LPCS4UIELEMENT lpUiElement = 36 | CSettlers4Api::GetInstance().GetHoveringUiElement(&uiElement) == 0 ? &uiElement : NULL; 37 | mutex.lock(); 38 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 39 | mutex.unlock(); 40 | for (auto& observer : observers) { 41 | if (0 != ((LPS4MOUSECALLBACK)observer.callback)(wparam, (INT16)(GET_X_LPARAM(lparam)), (INT16)(GET_Y_LPARAM(lparam)), msg, hwnd, lpUiElement)) 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | static void __declspec(naked) __onMouseHE() { 48 | __asm { 49 | push eax 50 | push ecx 51 | push edx 52 | 53 | //push edi 54 | 55 | push[ebp - 0x04] // lparam 56 | push[ebp - 0x08] // wparam 57 | push[ebp - 0x0C] // msg 58 | push[ebp + 0x08] // hwnd 59 | call CMouseHook::OnMouse 60 | 61 | pop edx 62 | pop ecx 63 | test al, al 64 | pop eax 65 | jnz cancelEvent 66 | 67 | test eax, 0x08000000 68 | //mov ecx, [ebp - 4] // the opcodes we replaced 69 | //xor ecx, ebp 70 | 71 | ret 72 | 73 | cancelEvent : 74 | //cancel the event 75 | pop eax // remove the return address from stack 76 | pop edi 77 | pop esi 78 | pop ebx 79 | xor eax, eax 80 | mov esp, ebp 81 | pop ebp 82 | ret 16 83 | } 84 | } 85 | 86 | static void __declspec(naked) __onMouseGE() { 87 | __asm { 88 | push eax 89 | push edx 90 | 91 | push[esp + 0x2C] // lparam 92 | push[esp + 0x1C + 4] // wparam 93 | push[esp + 0x0C + 8] // msg 94 | push[esp + 0x28 + 12] // hwnd 95 | call CMouseHook::OnMouse 96 | 97 | pop edx 98 | test al, al 99 | pop eax 100 | jnz cancelEvent 101 | 102 | test eax, 0x08000000 // the opcode we replaced 103 | 104 | ret 105 | 106 | cancelEvent : 107 | pop eax // pop return address 108 | xor eax, eax 109 | pop edi 110 | pop esi 111 | pop ebp 112 | pop ebx 113 | pop ecx 114 | pop ecx 115 | ret 16 116 | } 117 | } 118 | 119 | CMouseHook& CMouseHook::GetInstance() { 120 | static CMouseHook inst; 121 | return inst; 122 | } 123 | 124 | bool CMouseHook::Init() { 125 | TRACE; 126 | if (!g_Patterns.OnMouseButtonHook) return false; 127 | 128 | DWORD addr = g_Patterns.OnMouseButtonHook + (g_isGE ? 19 : 20); 129 | DWORD addr2 = g_Patterns.OnMouseButtonHook + 68; 130 | OnMouseButtonHook = hlib::CallPatch(addr, (DWORD)(g_isGE ? __onMouseGE : __onMouseHE)); 131 | OnMouseWheelHookHE = hlib::CallPatch(addr2, (DWORD)__onMouseHE); // this is not required for the GE as the original hook already catches that too. 132 | 133 | return true; 134 | } 135 | 136 | void CMouseHook::Patch() { 137 | TRACE; 138 | OnMouseButtonHook.patch(); 139 | OnMouseWheelHookHE.patch(); 140 | } 141 | 142 | void CMouseHook::Unpatch() { 143 | TRACE; 144 | OnMouseButtonHook.unpatch(); 145 | OnMouseWheelHookHE.unpatch(); 146 | } 147 | 148 | CMouseHook::CMouseHook() { TRACE; } 149 | -------------------------------------------------------------------------------- /S4ModApi/CMouseHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CMouseHook : public CHook { 27 | public: 28 | static CMouseHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CMouseHook(); 37 | static bool __stdcall OnMouse(HWND hwnd, DWORD msg, DWORD wparam, DWORD lparam); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CS4Casting.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "patterns.h" 24 | #include "globals.h" 25 | #include "safemem.h" 26 | #include "s4.h" 27 | 28 | BOOL CSettlers4Api::CastSpell(DWORD priest, DWORD spell, INT x, INT y, DWORD player) { 29 | TRACE; 30 | 31 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 32 | if (!vtbl) return FALSE; 33 | 34 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 35 | if (!localPlayer) return FALSE; 36 | 37 | #pragma pack(push, 1) 38 | static union { 39 | struct EventStruct_t { 40 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 41 | /*04*/DWORD eventId; // 0x13B8 42 | /*08*/WORD spell; 43 | /*0A*/WORD priest; 44 | /*0C*/WORD x; 45 | /*0E*/WORD y; 46 | /*10*/DWORD tick; // 47 | /*14*/BYTE flags; // always 0 ? 48 | /*16*/BYTE __pad[3]; // ignored 49 | /*18*/DWORD settlersArray; // must be 0 50 | /*1C*/WORD sizeofArray; // always 0 51 | /*1E*/BYTE player; // 52 | } eventStruct; 53 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 54 | } u1; 55 | #pragma pack(pop) 56 | 57 | ZeroMemory(&u1, sizeof(u1)); 58 | 59 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; 60 | u1.eventStruct.eventId = 0x13B8; 61 | u1.eventStruct.spell = (WORD)spell; 62 | u1.eventStruct.priest = (WORD)priest; 63 | u1.eventStruct.x = (WORD)x; 64 | u1.eventStruct.y = (WORD)y; 65 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 66 | u1.eventStruct.player = (BYTE)localPlayer; 67 | 68 | return S4::GetInstance().SendNetEvent(&u1); 69 | } 70 | -------------------------------------------------------------------------------- /S4ModApi/CS4CustomUi.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "CMessageBox.h" 24 | #include "CCustomUi.h" 25 | 26 | static HRESULT S4HCALL OnMessageBoxHide(CMessageBox* messagebox, INT reason) { 27 | UNREFERENCED_PARAMETER(reason); 28 | delete messagebox; 29 | return 0; 30 | } 31 | 32 | S4CUSTOMUI CSettlers4Api::ShowMessageBox(LPCWSTR title, LPCWSTR message, INT x, INT y, INT w, INT h, DWORD flags) { 33 | TRACE; 34 | auto mb = new CMessageBox(title,message,x,y,w,h,flags); 35 | mb->SetHandler(OnMessageBoxHide); 36 | mb->Show(); 37 | return mb; 38 | } 39 | 40 | S4CUSTOMUI CSettlers4Api::CreateCustomUiElement(LPCS4CUSTOMUIELEMENT arg) { 41 | TRACE; 42 | if (arg && arg->size == sizeof(*arg)) { 43 | auto cui = new CCustomUi(arg); 44 | cui->Show(); 45 | return cui; 46 | } 47 | return NULL; 48 | } 49 | 50 | BOOL CSettlers4Api::DestroyCustomUiElement(S4CUSTOMUI arg) { 51 | TRACE; 52 | return HideCustomUiElement(arg); // TODO: calling delete may be harmful when calling from a S4UiCallbackProc 53 | //if (arg) { 54 | // delete arg; 55 | //} 56 | return NULL; 57 | } 58 | 59 | BOOL CSettlers4Api::HideCustomUiElement(S4CUSTOMUI arg) { 60 | TRACE; 61 | if (arg) { 62 | auto diag = (CDialog*)arg; 63 | diag->Hide(); 64 | return TRUE; 65 | } else { 66 | return FALSE; 67 | } 68 | } 69 | 70 | BOOL CSettlers4Api::ShowCustomUiElement(S4CUSTOMUI arg) { 71 | TRACE; 72 | if (arg) { 73 | auto diag = (CDialog*)arg; 74 | diag->Show(); 75 | return TRUE; 76 | } else { 77 | return FALSE; 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /S4ModApi/CS4Debug.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | 24 | LPVOID CSettlers4Api::GetDebugData(LPVOID reserved0, LPVOID reserved1) { 25 | TRACE; 26 | UNREFERENCED_PARAMETER(reserved0); 27 | UNREFERENCED_PARAMETER(reserved1); 28 | 29 | return (LPVOID)m_refs; 30 | } 31 | -------------------------------------------------------------------------------- /S4ModApi/CS4Error.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | 24 | DWORD CSettlers4Api::GetLastError() { 25 | TRACE; 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /S4ModApi/CS4GarrisonWarriors.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "patterns.h" 24 | #include "globals.h" 25 | #include "safemem.h" 26 | #include "s4.h" 27 | #include "hlib.h" 28 | 29 | BOOL CSettlers4Api::GarrisonWarriors(DWORD building, DWORD player) { 30 | TRACE; 31 | 32 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 33 | if (!vtbl) return FALSE; 34 | 35 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 36 | if (!localPlayer) return FALSE; 37 | 38 | #pragma pack(push, 1) 39 | static union { 40 | struct EventStruct_t { 41 | /*00*/DWORD CEvn_Logic_vtbl; // [2C] vtable 42 | /*04*/DWORD eventId; // [28] 0x13A7 43 | /*08*/DWORD buildingIndex; // [24] 44 | /*0C*/INT32 amount; // [20] Must be -1. Other values have no effect? 45 | /*10*/DWORD tick; // [1C] 46 | /*14*/BYTE flags; // [18] always 0x00 ? 47 | /*16*/BYTE __pad[3]; // [17] ignored 48 | /*18*/DWORD settlersArray; // [14] must be 0 49 | /*1C*/WORD sizeofArray; // [10] always 0 50 | /*1E*/BYTE player; // [E] 51 | } eventStruct; 52 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 53 | } u1; 54 | #pragma pack(pop) 55 | 56 | ZeroMemory(&u1, sizeof(u1)); 57 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; 58 | u1.eventStruct.eventId = 0x13A7; // garrison event 59 | u1.eventStruct.buildingIndex = building; 60 | u1.eventStruct.amount = -1; 61 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 62 | u1.eventStruct.player = (BYTE)localPlayer; 63 | 64 | return S4::GetInstance().SendNetEvent(&u1); 65 | } 66 | 67 | BOOL CSettlers4Api::UnGarrisonWarriors(DWORD building, INT column, BOOL bowman, DWORD player) { 68 | TRACE; 69 | 70 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 71 | if (!vtbl) return FALSE; 72 | 73 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 74 | if (!localPlayer) return FALSE; 75 | 76 | #pragma pack(push, 1) 77 | static union { 78 | struct EventStruct_t { 79 | /*00*/DWORD CEvn_Logic_vtbl; // [2C] vtable 80 | /*04*/DWORD eventId; // [28] 0x13A8 81 | /*08*/WORD type;// 0==swordmen, 1==bowmen 82 | /*0A*/WORD buildingIndex; // 83 | /*0C*/INT32 unit; // index of the unit in the building to remove. Is in range 0..5. Use -1 to remove em all. 84 | /*10*/DWORD tick; // [1C] 85 | /*14*/BYTE flags; // [18] always 0x0f00 ? 86 | /*16*/BYTE __pad[3]; // [17] ignored 87 | /*18*/DWORD settlersArray; // [14] must be 0 88 | /*1C*/WORD sizeofArray; // [10] always 0 89 | /*1E*/BYTE player; // [E] 90 | } eventStruct; 91 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 92 | } u1; 93 | #pragma pack(pop) 94 | 95 | ZeroMemory(&u1, sizeof(u1)); 96 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; 97 | u1.eventStruct.eventId = 0x13A8; // ungarrison event 98 | u1.eventStruct.type = (WORD)bowman; 99 | u1.eventStruct.buildingIndex = (WORD)building; 100 | u1.eventStruct.unit = column; 101 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 102 | u1.eventStruct.player = (BYTE)localPlayer; 103 | 104 | return S4::GetInstance().SendNetEvent(&u1); 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /S4ModApi/CS4GoodDistribution.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "patterns.h" 24 | #include "globals.h" 25 | #include "safemem.h" 26 | #include "s4.h" 27 | 28 | BOOL CSettlers4Api::ChangeGoodDistribution(S4_GOOD_ENUM good, S4_BUILDING_ENUM building, INT percent, DWORD ecosector, DWORD player) { 29 | TRACE; 30 | 31 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 32 | if (!vtbl) return FALSE; 33 | 34 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 35 | if (!localPlayer) return FALSE; 36 | 37 | #pragma pack(push, 1) 38 | static union { 39 | struct EventStruct_t { 40 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 41 | /*04*/DWORD eventId; 42 | /*08*/WORD building; 43 | /*0A*/WORD good; 44 | /*0C*/INT16 change; 45 | /*0E*/WORD ecosector; 46 | /*10*/DWORD tick; // 47 | /*14*/BYTE flags; // always 0 ? 48 | /*16*/BYTE __pad[3]; // ignored 49 | /*18*/DWORD settlersArray; // must be 0 50 | /*1C*/WORD sizeofArray; // always 0 51 | /*1E*/BYTE player; // 52 | } eventStruct; 53 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 54 | } u1; 55 | #pragma pack(pop) 56 | 57 | ZeroMemory(&u1, sizeof(u1)); 58 | 59 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 60 | u1.eventStruct.eventId = 0x13A4; 61 | u1.eventStruct.good = (WORD)(good); 62 | u1.eventStruct.building = (WORD)(building); 63 | u1.eventStruct.change = (INT16)percent; 64 | u1.eventStruct.ecosector = (WORD)ecosector; 65 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 66 | u1.eventStruct.player = (BYTE)localPlayer; 67 | 68 | return S4::GetInstance().SendNetEvent(&u1); 69 | } 70 | 71 | // positive offset means lower priority, negative offset means higher priority 72 | BOOL CSettlers4Api::ChangeGoodPriority(S4_GOOD_ENUM good, INT offset, DWORD ecosector, DWORD player) { 73 | TRACE; 74 | 75 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 76 | if (!vtbl) return FALSE; 77 | 78 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 79 | if (!localPlayer) return FALSE; 80 | 81 | #pragma pack(push, 1) 82 | static union { 83 | struct EventStruct_t { 84 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 85 | /*04*/DWORD eventId; 86 | /*08*/INT16 offset; 87 | /*0A*/WORD good; 88 | /*0C*/DWORD ecosector; 89 | /*10*/DWORD tick; // 90 | /*14*/BYTE flags; // always 0 ? 91 | /*16*/BYTE __pad[3]; // ignored 92 | /*18*/DWORD settlersArray; // must be 0 93 | /*1C*/WORD sizeofArray; // always 0 94 | /*1E*/BYTE player; // 95 | } eventStruct; 96 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 97 | } u1; 98 | #pragma pack(pop) 99 | 100 | ZeroMemory(&u1, sizeof(u1)); 101 | 102 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 103 | u1.eventStruct.eventId = 0x13A5; 104 | u1.eventStruct.good = (WORD)(good); 105 | u1.eventStruct.offset = (INT16)offset; 106 | u1.eventStruct.ecosector = ecosector; 107 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 108 | u1.eventStruct.player = (BYTE)localPlayer; 109 | 110 | return S4::GetInstance().SendNetEvent(&u1); 111 | } 112 | 113 | -------------------------------------------------------------------------------- /S4ModApi/CS4Landscape.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "patterns.h" 24 | #include "s4.h" 25 | #include "safemem.h" 26 | #include "globals.h" 27 | 28 | DWORD CSettlers4Api::LandscapeGetHeight(INT x, INT y) { 29 | TRACE; 30 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 31 | if (landscape) return landscape->GetTerrainHeight(); 32 | return 0; 33 | } 34 | 35 | S4_GROUND_ENUM CSettlers4Api::LandscapeGetType(INT x, INT y) { 36 | TRACE; 37 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 38 | if (landscape) return landscape->GetTerrainType(); 39 | return S4_GROUND_ENUM::WATER8; 40 | } 41 | 42 | BOOL CSettlers4Api::LandscapeIsPond(INT x, INT y) { 43 | TRACE; 44 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 45 | if (landscape) return landscape->IsPondBrush(); 46 | return FALSE; 47 | } 48 | 49 | BOOL CSettlers4Api::LandscapeIsDarkLand(INT x, INT y) { 50 | TRACE; 51 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 52 | if (landscape) return landscape->IsDarkLand(); 53 | return FALSE; 54 | } 55 | 56 | BOOL CSettlers4Api::LandscapeIsDarkLandBorder(INT x, INT y) { 57 | TRACE; 58 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 59 | if (landscape) return landscape->IsDarkBorder(); 60 | return FALSE; 61 | } 62 | 63 | DWORD CSettlers4Api::LandscapeGetFogOfWar(INT x, INT y) { 64 | TRACE; 65 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 66 | if (landscape) return landscape->GetFogOfWarLevel(); 67 | return (DWORD)-1; 68 | } 69 | 70 | BOOL CSettlers4Api::LandscapeIsFoundingStone(INT x, INT y) { 71 | TRACE; 72 | auto landscape = S4::GetInstance().GetLandscapeAt((WORD)x, (WORD)y); 73 | if (landscape) return landscape->IsFoundingStone(); 74 | return FALSE; 75 | } 76 | 77 | S4_RESOURCE_ENUM CSettlers4Api::LandscapeGetResource(INT x, INT y) { 78 | TRACE; 79 | return S4::GetInstance().GetResourceAt((WORD)x, (WORD)y); 80 | } 81 | 82 | BOOL CSettlers4Api::LandscapeSetResource(INT x, INT y, S4_RESOURCE_ENUM res) { 83 | TRACE; 84 | return S4::GetInstance().SetResourceAt((WORD)x, (WORD)y, res); 85 | } 86 | 87 | DWORD CSettlers4Api::LandscapeGetObject(INT x, INT y) { 88 | TRACE; 89 | return S4::GetInstance().GetEntityIdAt((WORD)x, (WORD)y); 90 | } 91 | 92 | DWORD CSettlers4Api::LandscapeGetOwner(INT x, INT y) { 93 | TRACE; 94 | return S4::GetInstance().GetOwnerAt((WORD)x, (WORD)y); 95 | } 96 | 97 | DWORD CSettlers4Api::LandscapeGetEcoSector(INT x, INT y) { 98 | TRACE; 99 | return S4::GetInstance().LandscapeGetEcoSector((WORD)x, (WORD)y); 100 | } 101 | 102 | BOOL CSettlers4Api::LandscapeIsOccupied(INT x, INT y) { 103 | TRACE; 104 | return S4::GetInstance().IsOccupied((WORD)x, (WORD)y); 105 | } -------------------------------------------------------------------------------- /S4ModApi/CS4Listeners.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | 24 | #include "CFrameHook.h" 25 | #include "CMapInitHook.h" 26 | #include "CMouseHook.h" 27 | #include "CSettlerSendHook.h" 28 | #include "CTickHook.h" 29 | #include "CLuaOpenHook.h" 30 | #include "CBltHook.h" 31 | #include "CEntityHook.h" 32 | #include "CGuiBltHook.h" 33 | #include "CGuiClearHook.h" 34 | #include "CGuiElementBltHook.h" 35 | 36 | extern "C" { 37 | 38 | HRESULT CSettlers4Api::RemoveListener(S4HOOK id) { 39 | TRACE; 40 | return CHook::RemoveListener(id); 41 | } 42 | 43 | S4HOOK CSettlers4Api::AddFrameListener(LPS4FRAMECALLBACK cb) { 44 | TRACE; 45 | return CFrameHook::GetInstance().AddListener(cb); 46 | } 47 | 48 | S4HOOK CSettlers4Api::AddUIFrameListener(LPS4FRAMECALLBACK cb, S4_GUI_ENUM param) { 49 | TRACE; 50 | return CFrameHook::GetInstance().AddListener(cb, param); 51 | } 52 | 53 | S4HOOK CSettlers4Api::AddMapInitListener(LPS4MAPINITCALLBACK cb) { 54 | TRACE; 55 | return CMapInitHook::GetInstance().AddListener(cb); 56 | } 57 | 58 | S4HOOK CSettlers4Api::AddMouseListener(LPS4MOUSECALLBACK cb) { 59 | TRACE; 60 | return CMouseHook::GetInstance().AddListener(cb); 61 | } 62 | 63 | S4HOOK CSettlers4Api::AddSettlerSendListener(LPS4SETTLERSENDCALLBACK cb) { 64 | TRACE; 65 | return CSettlerSendHook::GetInstance().AddListener(cb); 66 | } 67 | 68 | S4HOOK CSettlers4Api::AddTickListener(LPS4TICKCALLBACK cb) { 69 | TRACE; 70 | return CTickHook::GetInstance().AddListener(cb); 71 | } 72 | 73 | S4HOOK CSettlers4Api::AddLuaOpenListener(LPS4LUAOPENCALLBACK cb) { 74 | TRACE; 75 | return CLuaOpenHook::GetInstance().AddListener(cb); 76 | } 77 | 78 | S4HOOK CSettlers4Api::AddBltListener(LPS4BLTCALLBACK cb) { 79 | TRACE; 80 | return CBltHook::GetInstance().AddListener(cb); 81 | } 82 | 83 | S4HOOK CSettlers4Api::AddEntityListener(LPS4ENTITYCALLBACK cb) { 84 | TRACE; 85 | return CEntityHook::GetInstance().AddListener(cb); 86 | } 87 | 88 | S4HOOK CSettlers4Api::AddGuiBltListener(LPS4GUIBLTCALLBACK cb) { 89 | TRACE; 90 | return CGuiBltHook::GetInstance().AddListener(cb); 91 | } 92 | 93 | S4HOOK CSettlers4Api::AddGuiElementBltListener(LPS4GUIDRAWCALLBACK cb) { 94 | TRACE; 95 | return CGuiElementBltHook::GetInstance().AddListener(cb); 96 | } 97 | 98 | S4HOOK CSettlers4Api::AddGuiClearListener(LPS4GUICLEARCALLBACK cb) { 99 | TRACE; 100 | return CGuiClearHook::GetInstance().AddListener(cb); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /S4ModApi/CS4MenuEvents.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "s4.h" 24 | 25 | 26 | BOOL CSettlers4Api::StartBuildingPlacement(S4_BUILDING_ENUM building) { 27 | TRACE; 28 | 29 | Event_t ev(0, 0, 0, building, 0, 0x1B5); 30 | if (!ev.eventId) return FALSE; 31 | 32 | return S4::GetInstance().SendLocalEvent(ev); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /S4ModApi/CS4Misc.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "globals.h" 24 | #include "s4.h" 25 | #include "md5.h" 26 | #include "safemem.h" 27 | 28 | HRESULT CSettlers4Api::GetMD5OfModule(HMODULE module, LPSTR out, SIZE_T sz) { 29 | TRACE; 30 | if (!out || !sz) return ERROR_BAD_ARGUMENTS; 31 | MD5 md5; 32 | WCHAR filename[MAX_PATH + 1]; 33 | auto len = GetModuleFileNameW(module, filename, MAX_PATH); 34 | if (!len) return GetLastError(); 35 | filename[len] = '\0'; 36 | auto res = ComputeMD5(filename, &md5); 37 | if (!res) return res; 38 | md5.ToString(out, sz); // covert to string 39 | return ERROR_SUCCESS; 40 | } 41 | 42 | BOOL CSettlers4Api::IsEdition(S4_EDITION_ENUM edition) { 43 | TRACE; 44 | switch (edition) { 45 | case S4_EDITION_GOLD: return g_isGE; 46 | case S4_EDITION_HISTORY: return !g_isGE; 47 | default: return FALSE; 48 | } 49 | } 50 | 51 | HWND CSettlers4Api::GetHwnd() { 52 | TRACE; 53 | auto& pHwnd = S4::GetInstance().Hwnd; 54 | return (HWND)READ_AT(pHwnd); 55 | } 56 | 57 | HRESULT CSettlers4Api::GetHoveringUiElement(LPS4UIELEMENT out) { 58 | TRACE; 59 | if (out) { 60 | auto& ppUi = S4::GetInstance().HoveringUiElement; 61 | UiElement_t* pUi = (UiElement_t*)READ_AT(ppUi); 62 | if (pUi) { 63 | UiElement_t ui; 64 | memget_s(&ui, pUi, sizeof ui); 65 | out->x = ui.x; 66 | out->y = ui.y; 67 | out->w = ui.w; 68 | out->h = ui.h; 69 | out->id = ui.id; 70 | out->sprite = ui.sprite; 71 | return 0; 72 | } 73 | } 74 | return -1; 75 | } 76 | -------------------------------------------------------------------------------- /S4ModApi/CS4Recruit.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "patterns.h" 24 | #include "globals.h" 25 | #include "safemem.h" 26 | #include "s4.h" 27 | 28 | // for some units (specialists) building is the eco sector number 29 | BOOL CSettlers4Api::RecruitWarriors(DWORD building, S4_SETTLER_ENUM unit, INT amount, DWORD player) { 30 | TRACE; 31 | 32 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 33 | if (!vtbl) return FALSE; 34 | 35 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 36 | if (!localPlayer) return FALSE; 37 | 38 | #pragma pack(push, 1) 39 | union { 40 | struct EventStruct_t { 41 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 42 | /*04*/DWORD eventId; // 0x13B7 43 | /*08*/WORD unit; // 1D == swordman lv1, 1E == lv2 etc 44 | /*10*/WORD buildingIndex; // 45 | /*0C*/INT32 amount; // put 100 for infinite 46 | /*10*/DWORD tick; // 47 | /*14*/BYTE flags; // always 0xf500 ? 48 | /*16*/BYTE __pad[3]; // ignored 49 | /*18*/DWORD settlersArray; // must be 0 50 | /*1C*/WORD sizeofArray; // always 0 51 | /*1E*/BYTE player; // 52 | } eventStruct; 53 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 54 | } u1; 55 | #pragma pack(pop) 56 | 57 | ZeroMemory(&u1, sizeof(u1)); 58 | 59 | switch (unit) { 60 | case S4_SETTLER_CARRIER: 61 | case S4_SETTLER_DIGGER: 62 | case S4_SETTLER_BUILDER: 63 | u1.eventStruct.eventId = 0x13A3; // civilian recruitment event 64 | u1.eventStruct.unit = (WORD)(unit); 65 | //building is the eco sector id !!! 66 | break; 67 | case S4_SETTLER_SWORDSMAN_01: 68 | case S4_SETTLER_SWORDSMAN_02: 69 | case S4_SETTLER_SWORDSMAN_03: 70 | case S4_SETTLER_BOWMAN_01: 71 | case S4_SETTLER_BOWMAN_02: 72 | case S4_SETTLER_BOWMAN_03: 73 | case S4_SETTLER_MEDIC_01: 74 | case S4_SETTLER_MEDIC_02: 75 | case S4_SETTLER_MEDIC_03: 76 | case S4_SETTLER_AXEWARRIOR_01: 77 | case S4_SETTLER_AXEWARRIOR_02: 78 | case S4_SETTLER_AXEWARRIOR_03: 79 | case S4_SETTLER_BLOWGUNWARRIOR_01: 80 | case S4_SETTLER_BLOWGUNWARRIOR_02: 81 | case S4_SETTLER_BLOWGUNWARRIOR_03: 82 | case S4_SETTLER_SQUADLEADER: 83 | case S4_SETTLER_BACKPACKCATAPULTIST_01: 84 | case S4_SETTLER_BACKPACKCATAPULTIST_02: 85 | case S4_SETTLER_BACKPACKCATAPULTIST_03: 86 | u1.eventStruct.eventId = 0x13B7; // barracks recruitment event 87 | u1.eventStruct.unit = (WORD)(unit); 88 | break; 89 | case S4_SETTLER_SABOTEUR: 90 | case S4_SETTLER_PIONEER: 91 | case S4_SETTLER_THIEF: 92 | case S4_SETTLER_GEOLOGIST: 93 | case S4_SETTLER_GARDENER: 94 | //case S4_SETTLER_LANDSCAPER: 95 | //case S4_SETTLER_DARKGARDENER: 96 | //case S4_SETTLER_SHAMAN: 97 | u1.eventStruct.eventId = 0x13AF; // specialists recruitment event 98 | u1.eventStruct.unit = (WORD)(unit); 99 | //building is the eco sector id !!! 100 | break; 101 | 102 | default: return FALSE; // currently not supported 103 | } 104 | 105 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 106 | u1.eventStruct.buildingIndex = (WORD)building; 107 | u1.eventStruct.amount = amount; 108 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 109 | u1.eventStruct.player = (BYTE)localPlayer; 110 | 111 | return S4::GetInstance().SendNetEvent(&u1); 112 | } 113 | 114 | BOOL CSettlers4Api::RecruitVehicle(DWORD building, S4_VEHICLE_ENUM unit, INT amount, DWORD player) { 115 | TRACE; 116 | 117 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 118 | if (!vtbl) return FALSE; 119 | 120 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 121 | if (!localPlayer) return FALSE; 122 | 123 | #pragma pack(push, 1) 124 | union { 125 | struct EventStruct_t { 126 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 127 | /*04*/DWORD eventId; // 0x13B7 128 | /*08*/WORD unit; // 1D == swordman lv1, 1E == lv2 etc 129 | /*10*/WORD buildingIndex; // 130 | /*0C*/INT32 amount; // put 100 for infinite 131 | /*10*/DWORD tick; // 132 | /*14*/BYTE flags; // always 0xf500 ? 133 | /*16*/BYTE __pad[3]; // ignored 134 | /*18*/DWORD settlersArray; // must be 0 135 | /*1C*/WORD sizeofArray; // always 0 136 | /*1E*/BYTE player; // 137 | } eventStruct; 138 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 139 | } u1; 140 | #pragma pack(pop) 141 | 142 | ZeroMemory(&u1, sizeof(u1)); 143 | 144 | switch (unit) { 145 | case S4_VEHICLE_WARSHIP: 146 | case S4_VEHICLE_FERRY: 147 | case S4_VEHICLE_TRANSPORTSHIP: 148 | case S4_VEHICLE_WARMACHINE: 149 | case S4_VEHICLE_CART: 150 | case S4_VEHICLE_FOUNDATION_CART: 151 | u1.eventStruct.eventId = 0x13B0; // vehicle recruitment event (shipyard, vehicle hall) 152 | u1.eventStruct.unit = (WORD)(unit); 153 | break; 154 | 155 | default: return FALSE; // currently not supported 156 | } 157 | 158 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 159 | u1.eventStruct.buildingIndex = (WORD)building; 160 | u1.eventStruct.amount = amount; 161 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 162 | u1.eventStruct.player = (BYTE)localPlayer; 163 | 164 | return S4::GetInstance().SendNetEvent(&u1); 165 | } 166 | 167 | -------------------------------------------------------------------------------- /S4ModApi/CS4Selection.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "CSettlers4Api.h" 24 | #include "hlib.h" // JmpPatch 25 | #include "patterns.h" 26 | #include "s4.h" 27 | #include "safemem.h" 28 | #include 29 | #include "CSelectionMod.h" 30 | 31 | BOOL CSettlers4Api::ClearSelection() { 32 | TRACE; 33 | typedef void(__stdcall* ClearSelection_t)(); 34 | auto ClearSelection = (ClearSelection_t)g_Patterns.ClearSelection.addr; 35 | if (!ClearSelection) return FALSE; 36 | ClearSelection(); 37 | return TRUE; 38 | } 39 | 40 | BOOL CSettlers4Api::GetSelection(PWORD out, SIZE_T outlen, PSIZE_T selectionCount) { 41 | TRACE; 42 | if (!out) return FALSE; 43 | auto& s = S4::GetInstance().Selection; 44 | if (!s) return FALSE; 45 | auto ct = s->count(); 46 | auto elementsToCopy = min(ct, outlen); 47 | if (selectionCount) *selectionCount = ct; 48 | LOG("s->BasePtr == " << HEXNUM(s->BasePtr)) 49 | if (out && elementsToCopy) memget_s(out, s->BasePtr, elementsToCopy * sizeof(*s->BasePtr)); 50 | return TRUE; 51 | } 52 | 53 | BOOL CSettlers4Api::RemoveSelection(PWORD settlers, SIZE_T settlerslen, PSIZE_T removedCount) { 54 | TRACE; 55 | if (!settlers) return FALSE; 56 | if (!settlerslen) { 57 | if (removedCount) *removedCount = 0; 58 | return TRUE; 59 | } 60 | auto& s = S4::GetInstance().Selection; 61 | if (!s) return FALSE; 62 | auto ppool = S4::GetInstance().EntityPool; 63 | if (!ppool) return FALSE; 64 | auto pool = *ppool; 65 | 66 | // build a set for settlers to remove 67 | std::unordered_set removeSet; 68 | for (SIZE_T i = 0; i < settlerslen; i++) { 69 | auto e = settlers[i]; 70 | if (e) removeSet.insert(e); 71 | } 72 | 73 | auto end = s->EndPtr; 74 | auto cur = s->BasePtr; 75 | for (auto sp = cur; sp < end; ++sp) { 76 | if (removeSet.find(*sp) != removeSet.end()) { 77 | pool[*sp].clrSelectionVisibility(); 78 | continue; 79 | } 80 | *cur = *sp; 81 | ++cur; 82 | } 83 | if (removedCount) *removedCount = end - cur; 84 | if (cur == s->BasePtr) { 85 | // all elements have been removed 86 | //ClearSelection(); 87 | } 88 | s->EndPtr = cur; 89 | return TRUE; 90 | } 91 | 92 | DWORD CSettlers4Api::SetMaxSelection(DWORD newLimit) { 93 | TRACE; 94 | return CSelectionMod::GetInstance().SetMaxSelection(newLimit); 95 | } 96 | 97 | DWORD CSettlers4Api::GetMaxSelection() { 98 | TRACE; 99 | return CSelectionMod::GetInstance().GetMaxSelection(); 100 | } 101 | -------------------------------------------------------------------------------- /S4ModApi/CS4SendWarriors.cpp: -------------------------------------------------------------------------------- 1 | #include "CSettlers4Api.h" 2 | #include "patterns.h" 3 | #include "globals.h" 4 | #include "safemem.h" 5 | #include "s4.h" 6 | 7 | BOOL CSettlers4Api::SendWarriors(INT x, INT y, S4_MOVEMENT_ENUM mode, PWORD warriors, SIZE_T countOfWarriors, DWORD player) { 8 | TRACE; 9 | 10 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 11 | if (!localPlayer) return FALSE; 12 | 13 | DWORD pos = ((WORD)y) << 16 | ((WORD)x); 14 | 15 | static DWORD heapAlloc = 0; 16 | static DWORD fillEventArg = 0; 17 | static DWORD one; 18 | static DWORD fillEvent = 0; 19 | static DWORD sendEvent = 0; 20 | one = 1; 21 | if (!heapAlloc) { 22 | DWORD addr = g_Patterns.OnSettlerCommandHook + (g_isGE ? 88 : 99); 23 | DWORD off = READ_AT((LPCVOID)addr, 1); 24 | if (addr && off) 25 | heapAlloc = addr + off + 5; 26 | else 27 | return FALSE; 28 | } 29 | if (!g_isGE && !fillEvent) { 30 | DWORD addr = g_Patterns.OnSettlerCommandHook + 0xB4; 31 | DWORD off = READ_AT((LPCVOID)addr, 1); 32 | if (addr && off) 33 | fillEvent = addr + off + 5; 34 | else 35 | return FALSE; 36 | } 37 | if (!sendEvent) { 38 | DWORD addr = g_Patterns.OnSettlerCommandHook + (g_isGE ? 0xE9 : 0xC3); 39 | DWORD off = READ_AT((LPCVOID)addr, 1); 40 | if (addr && off) 41 | sendEvent = addr + off + 5; 42 | else 43 | return FALSE; 44 | } 45 | //if (!fillEventArg) 46 | // fillEventArg = READ_AT((LPCVOID)(g_Patterns.OnSettlerCommandHook - (g_isGE ? 0x73 : 0x66))); // local player 47 | //if (!fillEventArg) 48 | // fillEventArg = (DWORD)&one; 49 | //DWORD dwFillEventArg = *(DWORD*)fillEventArg; 50 | 51 | auto repetitions = (countOfWarriors+99u) / 100u; 52 | for (auto i = 0u; i < repetitions; i++) { 53 | auto lower = i * 100; 54 | auto count = min(countOfWarriors - lower, 100) * sizeof(WORD); 55 | void* mem = NULL; 56 | 57 | __asm { 58 | // Allocate the mem just like the game would do it. 59 | // The game will free it for us later 60 | push count 61 | //mov eax, S4_Main 62 | //add eax, 0x94FBF7 63 | call heapAlloc 64 | add esp, 04 // cdecl! 65 | mov mem, eax 66 | } 67 | 68 | if (mem) { 69 | memcpy(mem, &warriors[lower], count); 70 | 71 | #pragma pack(push, 1) 72 | union { 73 | struct EventStruct_t { 74 | /*00*/DWORD CEvn_Logic_vtbl; // 0x14 // vtable 75 | /*04*/DWORD movementCommandId; // 0x18 // 0x1396 76 | /*08*/DWORD position; // 0x1C 77 | /*0C*/DWORD commandType; // 0x20 78 | /*10*/DWORD tick; // 0x24 79 | /*14*/DWORD null; // 0x28 // always 0 ? 80 | /*18*/DWORD settlersArray; // 0x2C 81 | /*1C*/WORD sizeofArray; // 0x30 82 | /*1E*/BYTE dl; // 0x32 // local player 83 | } eventStruct; 84 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 85 | } u1; 86 | #pragma pack(pop) 87 | 88 | if (g_isGE) { 89 | // note for the GE we must populate the struct ourselfs as the function is inlined :( 90 | static const DWORD vtblPtr = READ_AT(g_Patterns.OnSettlerCommandHook, 0xC5); 91 | u1.eventStruct.CEvn_Logic_vtbl = *(DWORD*)(vtblPtr); 92 | u1.eventStruct.movementCommandId = 0x1396; 93 | u1.eventStruct.position = pos; 94 | u1.eventStruct.commandType = mode; 95 | DWORD stick = 0; 96 | static const DWORD tickPtr = READ_AT(g_Patterns.OnSettlerCommandHook, 0x87); 97 | if (tickPtr) { 98 | stick = *(DWORD*)(tickPtr); 99 | if (stick) { 100 | stick = *(DWORD*)(stick + 0x18); 101 | if (stick) { 102 | stick = *(DWORD*)(stick); 103 | } 104 | } 105 | } 106 | u1.eventStruct.tick = stick; 107 | u1.eventStruct.null = 0; 108 | u1.eventStruct.settlersArray = (DWORD)mem; 109 | u1.eventStruct.sizeofArray = (WORD)count; 110 | u1.eventStruct.dl = (BYTE)localPlayer; 111 | void* arg = &u1.eventStruct; 112 | static const DWORD* pthisptr = (DWORD*)READ_AT(g_Patterns.OnSettlerCommandHook, 0x7D); 113 | if (pthisptr && *pthisptr) { 114 | DWORD pthis = *pthisptr; 115 | __asm { 116 | // send the event just like the game would do it 117 | mov ecx, pthis 118 | push arg 119 | call sendEvent 120 | } 121 | } 122 | } else { 123 | // we could populate this ourselfs buf its easier to let 124 | // the game do it for us. The game will basically just 125 | // copy the arguments and insert the events tick number 126 | __asm { 127 | // fill the event struct just like the game would do it 128 | push count 129 | lea ecx, u1.eventStructBytes 130 | push mem 131 | push localPlayer 132 | push mode // command type 133 | push pos // target position 134 | push 0x1396 // movement command id 135 | call fillEvent 136 | 137 | // send the event just like the game would do it 138 | lea eax, u1.eventStructBytes 139 | push eax 140 | call sendEvent 141 | } 142 | } 143 | 144 | 145 | } // if (mem) 146 | } // for 147 | 148 | return TRUE; 149 | } 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /S4ModApi/CS4Singleton.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | 24 | CSettlers4Api& CSettlers4Api::GetInstance() { static CSettlers4Api instance; return instance; } 25 | CSettlers4Api::CSettlers4Api() : m_refs(0) { TRACE; } 26 | CSettlers4Api::~CSettlers4Api() { TRACE; } 27 | -------------------------------------------------------------------------------- /S4ModApi/CS4Trading.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "patterns.h" 24 | #include "globals.h" 25 | #include "safemem.h" 26 | #include "s4.h" 27 | 28 | BOOL CSettlers4Api::SetTradingRoute(DWORD sourceBuilding, DWORD destinationBuilding, DWORD player) { 29 | TRACE; 30 | 31 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 32 | if (!vtbl) return FALSE; 33 | 34 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 35 | if (!localPlayer) return FALSE; 36 | 37 | #pragma pack(push, 1) 38 | static union { 39 | struct EventStruct_t { 40 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 41 | /*04*/DWORD eventId; // 0x138D 42 | /*08*/DWORD sourceBuilding; 43 | /*0C*/DWORD destinationBuilding; 44 | /*10*/DWORD tick; // 45 | /*14*/BYTE flags; // always 0 ? 46 | /*16*/BYTE __pad[3]; // ignored 47 | /*18*/DWORD settlersArray; // must be 0 48 | /*1C*/WORD sizeofArray; // always 0 49 | /*1E*/BYTE player; // 50 | } eventStruct; 51 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 52 | } u1; 53 | #pragma pack(pop) 54 | 55 | ZeroMemory(&u1, sizeof(u1)); 56 | 57 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 58 | if (!u1.eventStruct.CEvn_Logic_vtbl) return FALSE; 59 | u1.eventStruct.eventId = 0x138D; 60 | u1.eventStruct.sourceBuilding = sourceBuilding; 61 | u1.eventStruct.destinationBuilding = destinationBuilding; 62 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 63 | u1.eventStruct.player = (BYTE)localPlayer; 64 | 65 | return S4::GetInstance().SendNetEvent(&u1); 66 | } 67 | 68 | BOOL CSettlers4Api::TradeGood(DWORD buidling, S4_GOOD_ENUM good, INT amount, DWORD player) { 69 | TRACE; 70 | 71 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 72 | if (!vtbl) return FALSE; 73 | 74 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 75 | if (!localPlayer) return FALSE; 76 | 77 | #pragma pack(push, 1) 78 | static union { 79 | struct EventStruct_t { 80 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 81 | /*04*/DWORD eventId; // 0x13BE 82 | /*08*/WORD good; 83 | /*0A*/WORD buidling; 84 | /*0C*/INT32 amount; 85 | /*10*/DWORD tick; // 86 | /*14*/BYTE flags; // always 0 ? 87 | /*16*/BYTE __pad[3]; // ignored 88 | /*18*/DWORD settlersArray; // must be 0 89 | /*1C*/WORD sizeofArray; // always 0 90 | /*1E*/BYTE player; // 91 | } eventStruct; 92 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 93 | } u1; 94 | #pragma pack(pop) 95 | 96 | ZeroMemory(&u1, sizeof(u1)); 97 | 98 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 99 | u1.eventStruct.eventId = 0x138E; 100 | u1.eventStruct.good = (WORD)(good); 101 | u1.eventStruct.buidling = (WORD)buidling; 102 | u1.eventStruct.amount = amount; 103 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 104 | u1.eventStruct.player = (BYTE)localPlayer; 105 | 106 | return S4::GetInstance().SendNetEvent(&u1); 107 | } 108 | 109 | BOOL CSettlers4Api::StoreGood(DWORD buidling, S4_GOOD_ENUM good, BOOL enable, DWORD player) { 110 | TRACE; 111 | 112 | DWORD vtbl = S4::GetInstance().GetNetEventVTbl(); // 00E4BA08 113 | if (!vtbl) return FALSE; 114 | 115 | DWORD localPlayer = player ? player : S4::GetInstance().GetLocalPlayer(); 116 | if (!localPlayer) return FALSE; 117 | 118 | #pragma pack(push, 1) 119 | static union { 120 | struct EventStruct_t { 121 | /*00*/DWORD CEvn_Logic_vtbl; // vtable 122 | /*04*/DWORD eventId; // 0x13B4 123 | /*08*/WORD good; 124 | /*0A*/WORD buidling; 125 | /*0C*/INT32 enable; 126 | /*10*/DWORD tick; // 127 | /*14*/BYTE flags; // always 0 ? 128 | /*16*/BYTE __pad[3]; // ignored 129 | /*18*/DWORD settlersArray; // must be 0 130 | /*1C*/WORD sizeofArray; // always 0 131 | /*1E*/BYTE player; // 132 | } eventStruct; 133 | BYTE eventStructBytes[32]; // event struct is at least 32 bytes 134 | } u1; 135 | #pragma pack(pop) 136 | 137 | ZeroMemory(&u1, sizeof(u1)); 138 | 139 | u1.eventStruct.CEvn_Logic_vtbl = vtbl; // 00E4BA08 140 | u1.eventStruct.eventId = 0x13B4; 141 | u1.eventStruct.good = (WORD)(good); 142 | u1.eventStruct.buidling = (WORD)buidling; 143 | u1.eventStruct.enable = enable; 144 | u1.eventStruct.tick = S4::GetInstance().GetCurrentTick(); 145 | u1.eventStruct.player = (BYTE)localPlayer; 146 | 147 | return S4::GetInstance().SendNetEvent(&u1); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /S4ModApi/CS4Unknown.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "CSettlers4Api.h" 23 | #include "globals.h" 24 | #include 25 | 26 | HRESULT CSettlers4Api::QueryInterface(REFIID riid, LPVOID* ppvObj) { 27 | TRACE; 28 | if (ppvObj == NULL) { 29 | return E_POINTER; 30 | } 31 | 32 | if (riid == IID_IUnknown) { 33 | *ppvObj = static_cast(this); 34 | } 35 | else if (riid == IID_ISettlers4Api2) { 36 | *ppvObj = static_cast(this); 37 | } 38 | // Template that can be used when adding version 3.x of the interface 39 | //else if (riid == IID_ISettlers4Api3) { 40 | // *ppvObj = static_cast(this); 41 | //} 42 | else { 43 | *ppvObj = NULL; 44 | return E_NOINTERFACE; 45 | } 46 | 47 | (static_cast(*ppvObj))->AddRef(); 48 | 49 | return S_OK; 50 | } 51 | 52 | static std::mutex mtx; // ref counter lock 53 | 54 | ULONG CSettlers4Api::AddRef() { 55 | TRACE; 56 | std::lock_guard lock(mtx); 57 | return ++m_refs; 58 | } 59 | 60 | ULONG CSettlers4Api::Release() { 61 | TRACE; 62 | std::lock_guard lock(mtx); 63 | // Decrement the object's internal counter. 64 | auto lRefCount = --m_refs; 65 | if (lRefCount <= 0) { 66 | //delete this; 67 | return 0; 68 | } 69 | return lRefCount; 70 | } 71 | -------------------------------------------------------------------------------- /S4ModApi/CSelectionMod.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CMod.h" 25 | 26 | /// 27 | /// Selection Mod that allows the player to select and command more than 28 | /// 100 settlers. 29 | /// 30 | class CSelectionMod : public CMod { 31 | public: 32 | static CSelectionMod& GetInstance(); 33 | 34 | DWORD SetMaxSelection(DWORD newLimit); 35 | DWORD GetMaxSelection(); 36 | 37 | protected: 38 | virtual bool Init(); 39 | virtual void Patch(); 40 | virtual void Unpatch(); 41 | 42 | private: 43 | CSelectionMod(); 44 | static HRESULT S4HCALL CSelectionMod::OnSettlersSend(DWORD dwPosition, S4_MOVEMENT_ENUM dwCommand, LPVOID lpReserved); 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /S4ModApi/CSettlerSendHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // CallPatch 24 | #include "patterns.h" 25 | #include "CSettlerSendHook.h" 26 | 27 | static hlib::CallPatch OnSettlerCommandHook; 28 | 29 | bool __stdcall CSettlerSendHook::OnNewCommand(DWORD position, S4_MOVEMENT_ENUM command) { 30 | TRACE; 31 | mutex.lock(); 32 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 33 | mutex.unlock(); 34 | for (auto& observer : observers) { 35 | if (((LPS4SETTLERSENDCALLBACK)observer.callback)(position, command, 0)) 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | static void __declspec(naked) __newCommand() { 42 | __asm { 43 | push eax 44 | push ecx 45 | push edx 46 | push esi 47 | cmp g_isGE, 0 48 | jz lbl_he 49 | push ebp // this is the position for the GE 50 | jmp lbl_cont 51 | lbl_he : 52 | push ebx // this is the position for the HE 53 | lbl_cont : 54 | call CSettlerSendHook::OnNewCommand 55 | pop edx 56 | pop ecx 57 | test al, al 58 | pop eax 59 | jz lbl_cont2 60 | mov eax, edi // cancel the command 61 | lbl_cont2 : 62 | sub edi, eax 63 | sar edi, 1 64 | test edi, edi 65 | ret 66 | } 67 | } 68 | 69 | CSettlerSendHook& CSettlerSendHook::GetInstance() { 70 | static CSettlerSendHook inst; 71 | return inst; 72 | } 73 | 74 | bool CSettlerSendHook::Init() { 75 | TRACE; 76 | if (!g_Patterns.OnSettlerCommandHook) return false; 77 | 78 | DWORD addr = g_Patterns.OnSettlerCommandHook; 79 | OnSettlerCommandHook = hlib::CallPatch(addr, (DWORD)__newCommand, 1); 80 | 81 | return true; 82 | } 83 | 84 | void CSettlerSendHook::Patch() { 85 | TRACE; 86 | OnSettlerCommandHook.patch(); 87 | } 88 | 89 | void CSettlerSendHook::Unpatch() { 90 | TRACE; 91 | OnSettlerCommandHook.unpatch(); 92 | } 93 | 94 | CSettlerSendHook::CSettlerSendHook() { TRACE; } 95 | -------------------------------------------------------------------------------- /S4ModApi/CSettlerSendHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CSettlerSendHook : public CHook { 27 | public: 28 | static CSettlerSendHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CSettlerSendHook(); 37 | static bool __stdcall OnNewCommand(DWORD position, S4_MOVEMENT_ENUM command); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CTickHook.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "globals.h" // g_isGE, hProcess 23 | #include "hlib.h" // CallPatch 24 | #include "patterns.h" 25 | #include "CTickHook.h" 26 | 27 | static hlib::CallPatch OnTickHook; 28 | 29 | bool __stdcall CTickHook::OnTick(DWORD tick, bool hasEvent) { 30 | TRACE; 31 | bool delay = false; 32 | 33 | mutex.lock(); 34 | auto observers = GetInstance().observers; // obtain a copy since the callbacks may modify the vector 35 | mutex.unlock(); 36 | for (auto& observer : observers) { 37 | delay |= (bool)(((LPS4TICKCALLBACK)observer.callback)(tick, hasEvent, delay)); 38 | } 39 | return delay; 40 | } 41 | 42 | static void __declspec(naked) __onTick() { 43 | __asm { 44 | cmp g_isGE, 0 45 | jz lbl_he 46 | mov eax, [ecx] // only for ge 47 | lbl_he: 48 | mov eax, [eax + 0x0C] 49 | call eax 50 | push eax 51 | push ecx 52 | push edx 53 | movzx eax, al 54 | push eax 55 | push ebx // tick 56 | call CTickHook::OnTick 57 | pop edx 58 | pop ecx 59 | test al, al 60 | pop eax 61 | jz lbl_processEvent 62 | xor eax, eax 63 | lbl_processEvent : 64 | ret 65 | } 66 | } 67 | 68 | CTickHook& CTickHook::GetInstance() { 69 | static CTickHook inst; 70 | return inst; 71 | } 72 | 73 | bool CTickHook::Init() { 74 | TRACE; 75 | if (!g_Patterns.OnSettlerCommandHook) return false; 76 | 77 | DWORD addr = g_Patterns.OnTickHook + (g_isGE ? 6 : 8); 78 | OnTickHook = hlib::CallPatch(addr, (DWORD)__onTick); 79 | 80 | return true; 81 | } 82 | 83 | void CTickHook::Patch() { 84 | TRACE; 85 | OnTickHook.patch(); 86 | } 87 | 88 | void CTickHook::Unpatch() { 89 | TRACE; 90 | OnTickHook.unpatch(); 91 | } 92 | 93 | CTickHook::CTickHook() { TRACE; } 94 | -------------------------------------------------------------------------------- /S4ModApi/CTickHook.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "CHook.h" 25 | 26 | class CTickHook : public CHook { 27 | public: 28 | static CTickHook& GetInstance(); 29 | 30 | protected: 31 | virtual bool Init(); 32 | virtual void Patch(); 33 | virtual void Unpatch(); 34 | 35 | private: 36 | CTickHook(); 37 | static bool __stdcall OnTick(DWORD tick, bool hasEvent); 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /S4ModApi/CUpdate.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | /** 23 | * This is a quick and dirty auto update script. It will replace the S4ModApi.dll with the latest 24 | * non-prerelease version from the github release. 25 | **/ 26 | 27 | #pragma once 28 | 29 | #include "windef.h" 30 | #include 31 | 32 | class CUpdate { 33 | public: 34 | enum EUpdateCheckStatus { 35 | UPDATE_CHECK_UNK, 36 | UPDATE_CHECK_ERROR, 37 | UPDATE_CHECK_AVAILABLE, 38 | UPDATE_CHECK_UPTODATE, 39 | }; 40 | 41 | static CUpdate& GetInstance(); 42 | 43 | EUpdateCheckStatus check(); // check for updates 44 | DWORD getMillisSinceCheck(); // how many milliseconds elapsed since we polled for the last result 45 | 46 | private: 47 | void InitVersion(); 48 | void InstallUpdate(const std::string& url); 49 | 50 | CUpdate& operator=(const CUpdate&) = delete; 51 | CUpdate(const CUpdate&) = delete; 52 | CUpdate() = default; 53 | 54 | bool m_hasChecked = false; 55 | EUpdateCheckStatus m_status = UPDATE_CHECK_UNK; 56 | DWORD m_receivedTick = 0xFFFFFFFF; 57 | WORD m_verMayor = 0, m_verMinor = 0; 58 | }; -------------------------------------------------------------------------------- /S4ModApi/Console.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #if _DEBUG 23 | 24 | #define WIN32_LEAN_AND_MEAN 25 | #include "windows.h" 26 | #include 27 | #include 28 | #include 29 | 30 | static FILE* g_ConsoleFile = NULL; 31 | 32 | void InitConsole() { 33 | AllocConsole(); 34 | g_ConsoleFile = NULL; 35 | freopen_s(&g_ConsoleFile, "conout$", "w", stdout); 36 | } 37 | 38 | void DestroyConsole() { 39 | if (g_ConsoleFile != NULL) { 40 | fclose(g_ConsoleFile); 41 | g_ConsoleFile = NULL; 42 | } 43 | FreeConsole(); 44 | } 45 | 46 | HWND GetConsoleHwnd() { 47 | // This snipped was taken from https://support.microsoft.com/de-ch/help/124103/how-to-obtain-a-console-window-handle-hwnd 48 | 49 | const unsigned MY_BUFSIZE = 1024; // Buffer size for console window titles. 50 | HWND hwndFound; // This is what is returned to the caller. 51 | char pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated WindowTitle 52 | char pszOldWindowTitle[MY_BUFSIZE]; // Contains original WindowTitle 53 | GetConsoleTitleA(pszOldWindowTitle, MY_BUFSIZE); // Fetch current window title. 54 | sprintf_s(pszNewWindowTitle, "%d/%d", // Format a "unique" NewWindowTitle. 55 | GetTickCount(), 56 | GetCurrentProcessId()); 57 | SetConsoleTitleA(pszNewWindowTitle); // Change current window title. 58 | Sleep(40); // Ensure window title has been updated. 59 | hwndFound = FindWindowA(NULL, pszNewWindowTitle); // Look for NewWindowTitle. 60 | SetConsoleTitleA(pszOldWindowTitle); // Restore original window title. 61 | return hwndFound; 62 | } 63 | 64 | #endif -------------------------------------------------------------------------------- /S4ModApi/Console.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #if _DEBUG 25 | 26 | #include 27 | #include // std::setfill, std::setw 28 | #include "windows.h" 29 | 30 | using std::cout; 31 | using std::hex; 32 | using std::dec; 33 | using std::endl; 34 | 35 | #define HEXNUM(a) "0x" << hex << std::setfill('0') << std::setw(8) << ((DWORD)(a)) 36 | 37 | void InitConsole(); 38 | void DestroyConsole(); 39 | HWND GetConsoleHwnd(); 40 | 41 | #endif -------------------------------------------------------------------------------- /S4ModApi/DebugInfo.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/DebugInfo.cpp -------------------------------------------------------------------------------- /S4ModApi/DebugProgram.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #if _DEBUG 23 | 24 | #include "windows.h" 25 | #include "Console.h" 26 | #include "S4ModApi.h" 27 | #include 28 | #include "DebugRender.h" 29 | #include "CMessageBox.h" 30 | #include "globals.h" 31 | #include "Log.h" 32 | 33 | #define DEBUG_KEY VK_F5 34 | #define DEBUG_KEY_STR "F5" 35 | 36 | extern "C" HRESULT __declspec(nothrow) S4HCALL S4HooksGetDebugData(UINT32 type, LPSTR buf, SIZE_T bufsize); 37 | 38 | CMessageBox g_GreetingsMessageBox( 39 | L"g_GreetingsMessageBox", 40 | L"It appears that you are running a debug build of the S4ModApi.dll.\n" 41 | "You should update it to a release build if you are not a developer or bug tester. " 42 | "See https://github.com/nyfrk/S4ModApi for proper release.\n\n" 43 | "You can press " DEBUG_KEY_STR " to toggle the console window. ", 100, 100, 450, 250); 44 | 45 | void DebugProgramMain() { 46 | TRACE; 47 | 48 | //std::vector hooks; 49 | 50 | while (1) { 51 | TRACE; 52 | 53 | cout << endl << "** Welcome to the S4ModApi Debug Menu **" << endl << endl; 54 | 55 | { 56 | // print the patterns 57 | char* buf = new char[4096]; 58 | cout << "$ S4HooksGetDebugData(0x80000000," << HEXNUM(buf) << "," << dec << 2048 << ")" << endl; 59 | auto ret = S4HooksGetDebugData(0x80000000, buf, 4096); 60 | cout << " " << HEXNUM(ret) << endl; 61 | delete[] buf; 62 | } 63 | 64 | Sleep(1000); 65 | 66 | cout << "$ S4ApiCreate()" << endl; 67 | auto S4API = S4ApiCreate(); 68 | if (S4API) { 69 | cout << " success." << endl; 70 | } else { 71 | cout << " failure." << endl; 72 | for (int t = 3; t >= 0; t--) { 73 | cout << " will retry in " << dec << t << " seconds." << endl; 74 | Sleep(1000); 75 | } 76 | continue; 77 | } 78 | 79 | g_GreetingsMessageBox.Show(); 80 | 81 | //{ cout << "$ " << HEXNUM(S4API) << "->AddFrameListener(" << HEXNUM(DebugFrameProc) << ")" << endl; 82 | // auto res = S4API->AddFrameListener(DebugFrameProc); 83 | // cout << " " << dec << res << endl; 84 | // hooks.push_back(res); 85 | //} 86 | 87 | while (GetAsyncKeyState(DEBUG_KEY) >= 0) { 88 | Sleep(100); 89 | 90 | if (GetAsyncKeyState(VK_MULTIPLY) < 0) { 91 | CMessageBox test(L"Caption", L"This is a test message", 200, 200, 400, 150); 92 | test.Show(); 93 | while (GetAsyncKeyState(VK_MULTIPLY) < 0) { Sleep(10); } 94 | cout << "Hide Reason = " << dec << (DWORD)test.GetHideReason() << endl; 95 | } 96 | } 97 | while (GetAsyncKeyState(DEBUG_KEY) < 0) Sleep(10); 98 | 99 | //for (auto& hook : hooks) { 100 | // cout << "$ " << HEXNUM(S4API) << "->RemoveListener(" << dec << (DWORD)hook << ")" << endl; 101 | // auto res = S4API->RemoveListener(hook); 102 | // cout << " " << dec << res << endl; 103 | //} 104 | 105 | //hooks.clear(); 106 | 107 | { cout << "$ " << HEXNUM(S4API) << "->Release()" << endl; 108 | auto res = S4API->Release(); 109 | cout << " " << dec << res << endl; 110 | } 111 | 112 | cout << endl << "** goodbye **" << endl << endl; 113 | 114 | 115 | Sleep(2000); 116 | 117 | HWND hwnd = GetConsoleHwnd(); 118 | ShowWindow(hwnd, SW_HIDE); 119 | 120 | while (GetAsyncKeyState(DEBUG_KEY) >= 0) Sleep(100); 121 | while (GetAsyncKeyState(DEBUG_KEY) < 0) Sleep(10); 122 | 123 | ShowWindow(hwnd, SW_SHOW); 124 | } 125 | 126 | } 127 | 128 | 129 | #endif -------------------------------------------------------------------------------- /S4ModApi/DebugRender.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #if _DEBUG 23 | 24 | #include "DebugRender.h" 25 | #include "Console.h" 26 | 27 | HRESULT S4HCALL DebugFrameProc(LPDIRECTDRAWSURFACE7 lpSurface, INT32 iPillarboxWidth, LPVOID lpReserved) { 28 | UNREFERENCED_PARAMETER(lpSurface); 29 | UNREFERENCED_PARAMETER(iPillarboxWidth); 30 | UNREFERENCED_PARAMETER(lpReserved); 31 | 32 | auto S4API = S4ApiCreate(); 33 | if (!S4API) return 0; 34 | 35 | POINT p = { 0 }; 36 | HWND hwnd = S4API->GetHwnd(); 37 | const bool hasCursor = hwnd && GetCursorPos(&p) && ScreenToClient(hwnd, &p); 38 | 39 | //for (DWORD i = 0; i < S4_GUI_ENUM_MAXVALUE; i++) { 40 | // if (S4API->IsCurrentlyOnScreen((S4_GUI_ENUM)i)) { 41 | // cout << " " << dec << i << " is on screen" << endl; 42 | // } 43 | //} 44 | 45 | S4API->Release(); 46 | return 0; 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /S4ModApi/DebugRender.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #if _DEBUG 25 | 26 | #include "S4ModApi.h" 27 | 28 | HRESULT S4HCALL DebugFrameProc(LPDIRECTDRAWSURFACE7 lpSurface, INT32 iPillarboxWidth, LPVOID lpReserved); 29 | 30 | #endif -------------------------------------------------------------------------------- /S4ModApi/Log.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #ifdef _DEBUG 23 | 24 | #include "Log.h" 25 | #include 26 | 27 | std::ofstream g_LogStream; 28 | std::recursive_mutex g_LogStream_Mutex; 29 | volatile int isLogTraceInit = false; 30 | static __declspec(thread) int depth = 0; 31 | static __declspec(thread) std::string g_lastfunc; 32 | 33 | std::string GetLogstreamFilename() { 34 | char fname[MAX_PATH + 1]; 35 | auto len = GetModuleFileNameA(NULL, fname, MAX_PATH); 36 | fname[len] = '\0'; 37 | char* logfname = fname; 38 | for (int i = len; i >= 0; --i) { 39 | if (fname[i] == '\\' || fname[i] == '/') { 40 | fname[++i] = '\0'; 41 | break; 42 | } 43 | } 44 | return std::string(logfname) + "S4ModApi.log"; 45 | } 46 | 47 | void DestroyLogstream() { 48 | std::lock_guard lock(g_LogStream_Mutex); 49 | isLogTraceInit = false; 50 | g_LogStream.close(); 51 | } 52 | 53 | void InitLogstream() { 54 | std::lock_guard lock(g_LogStream_Mutex); 55 | g_LogStream.open(GetLogstreamFilename(), std::ios_base::out); 56 | g_LogStream << "This is a S4ModApi.log file. It has been produced by S4ModApi.dll." << endl 57 | << "See https://github.com/nyfrk/S4Hooks for more information on this project." << endl 58 | << "You can safely delete this log file. If the log creation annoys you, just switch" << endl 59 | << "to a release build (you are using a debug build)" << endl << endl; 60 | isLogTraceInit = true; 61 | } 62 | 63 | std::string RAIILogTrace::Timestamp(int extended) { 64 | SYSTEMTIME time; 65 | GetSystemTime(&time); 66 | std::stringstream ss; 67 | ss << dec; 68 | if (extended) { 69 | ss << 70 | std::setfill('0') << std::setw(4) << time.wYear << '-' << 71 | std::setfill('0') << std::setw(2) << time.wMonth << '-' << 72 | std::setfill('0') << std::setw(2) << time.wDay << ' ' << 73 | std::setfill('0') << std::setw(2) << time.wHour << ':' << 74 | std::setfill('0') << std::setw(2) << time.wMinute << ':' << 75 | std::setfill('0') << std::setw(2) << time.wSecond << "#" << 76 | std::setfill('0') << std::setw(4) << time.wMilliseconds; 77 | } 78 | else { 79 | DWORD t = ((DWORD)time.wMilliseconds) 80 | + (1000u * (DWORD)time.wSecond) 81 | + (1000u * 60u * (DWORD)time.wMinute); 82 | t %= 1000000; 83 | ss << std::setfill(' ') << std::setw(6) << t; 84 | } 85 | return ss.str(); 86 | } 87 | 88 | std::string RAIILogTrace::Indentation() { 89 | std::stringstream ss; 90 | for (int i = 0; i < depth; i++) { 91 | ss << " "; 92 | } 93 | return ss.str(); 94 | } 95 | 96 | RAIILogTrace::RAIILogTrace(std::string file, unsigned line, std::string func, LPCVOID a) { 97 | if (!isLogTraceInit) return; 98 | std::lock_guard lock(g_LogStream_Mutex); 99 | if (!isLogTraceInit) return; 100 | g_LogStream << LOG_PROLOG_LONG << Indentation(); 101 | if (g_lastfunc == func) { 102 | g_LogStream << "code at " << file << ":" << dec << line << " // in " << func << std::endl; 103 | nodestructor = true; 104 | } 105 | else { 106 | g_LogStream << func << "("<< HEXNUM(a) <<") { // at " << file << ":" << dec << line << std::endl; 107 | ++depth; 108 | lastfunc = g_lastfunc; 109 | g_lastfunc = func; 110 | nodestructor = false; 111 | } 112 | g_LogStream.flush(); 113 | } 114 | 115 | RAIILogTrace::RAIILogTrace(std::string file, unsigned line, std::string func) : func(func) { 116 | if (!isLogTraceInit) return; 117 | std::lock_guard lock(g_LogStream_Mutex); 118 | if (!isLogTraceInit) return; 119 | g_LogStream << LOG_PROLOG_LONG << Indentation(); 120 | if (g_lastfunc == func) { 121 | g_LogStream << "code at " << file << ":" << dec << line << " // in " << func << std::endl; 122 | nodestructor = true; 123 | } 124 | else { 125 | g_LogStream << func << " { // at " << file << ":" << dec << line << std::endl; 126 | ++depth; 127 | lastfunc = g_lastfunc; 128 | g_lastfunc = func; 129 | nodestructor = false; 130 | } 131 | g_LogStream.flush(); 132 | } 133 | 134 | RAIILogTrace::~RAIILogTrace() { 135 | if (!isLogTraceInit) return; 136 | std::lock_guard lock(g_LogStream_Mutex); 137 | if (!isLogTraceInit) return; 138 | g_lastfunc = lastfunc; 139 | if (!nodestructor) { 140 | --depth; 141 | g_LogStream << LOG_PROLOG_LONG << Indentation() << "} // " << func << std::endl; 142 | g_LogStream.flush(); 143 | } 144 | } 145 | 146 | #endif -------------------------------------------------------------------------------- /S4ModApi/Log.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #ifdef _DEBUG 25 | 26 | #include "Console.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | extern std::ofstream g_LogStream; 32 | 33 | std::string GetLogstreamFilename(); 34 | void InitLogstream(); 35 | void DestroyLogstream(); 36 | 37 | extern volatile int isLogTraceInit; 38 | 39 | #define LOG(a) {\ 40 | if (isLogTraceInit) {\ 41 | g_LogStream_Mutex.lock();\ 42 | cout << LOG_PROLOG_SHORT << a << endl;\ 43 | g_LogStream << LOG_PROLOG_LONG << RAIILogTrace::Indentation() << "| " << a << endl;\ 44 | g_LogStream.flush();\ 45 | g_LogStream_Mutex.unlock();\ 46 | }\ 47 | } 48 | 49 | #define TRACE_(...) RAIILogTrace __raii_logtrace__(__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__); 50 | #define TRACE TRACE_() 51 | 52 | #define LOG_PROLOG(a) "[t:" << dec << std::setw(6) << std::setfill(' ') << GetCurrentThreadId() << ','\ 53 | << RAIILogTrace::Timestamp(a) << "] " 54 | #define LOG_PROLOG_LONG LOG_PROLOG(1) 55 | #define LOG_PROLOG_SHORT LOG_PROLOG(0) 56 | 57 | extern std::recursive_mutex g_LogStream_Mutex; 58 | 59 | struct RAIILogTrace { 60 | static std::string RAIILogTrace::Indentation(); 61 | static std::string RAIILogTrace::Timestamp(int extended); 62 | RAIILogTrace(std::string file, unsigned line, std::string func); 63 | RAIILogTrace(std::string file, unsigned line, std::string func, LPCVOID a); 64 | ~RAIILogTrace(); 65 | std::string func; 66 | std::string lastfunc; 67 | bool nodestructor = false; 68 | }; 69 | 70 | #else // _DEBUG 71 | #define LOG(x) ; 72 | #define TRACE ; 73 | #define TRACE_(x) ; 74 | #endif // _DEBUG 75 | -------------------------------------------------------------------------------- /S4ModApi/S4CreateInterface.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | #define WIN32_LEAN_AND_MEAN 24 | #include 25 | #include "CSettlers4Api.h" 26 | #include // new(std::nothrow) 27 | #include // sprintf_s 28 | 29 | HRESULT __declspec(nothrow) S4HCALL S4CreateInterface(CONST GUID FAR* lpGUID, S4API FAR* lplpS4H) { 30 | #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__ ",@1") // undecorated 31 | #pragma comment(linker, "/EXPORT:" __FUNCDNAME__ ) // stdcall decorated 32 | TRACE; 33 | 34 | if (!lplpS4H) return E_POINTER; 35 | if (!lpGUID) { 36 | *lplpS4H = NULL; 37 | return E_POINTER; 38 | } 39 | 40 | if (S_OK == CSettlers4Api::GetInstance().QueryInterface(*lpGUID, (LPVOID*)lplpS4H)) return S_OK; 41 | 42 | //if (*lpGUID == IID_ISettlers4Api) { 43 | // return ((*lplpS4H = new(std::nothrow) CSettlers4Api()) == nullptr) ? E_OUTOFMEMORY : S_OK; 44 | //} 45 | 46 | static bool showMessageBox = true; 47 | if (showMessageBox) { 48 | const char fmt[] = 49 | "Error: Missing Interface in S4ModApi.dll (%s)\n\n" 50 | "It appears that you are attempting to run a mod that expects a newer " 51 | "interface. Please go to https://github.com/nyfrk/S4ModApi and download " 52 | "the latest version.\n\n\n" 53 | "Do you want to open the URL in your browser?\n\n" 54 | "Click Yes if you want me to open the Download Page.\n" 55 | "Click No if you want to continue (no more warnings are shown)\n" 56 | "Click Cancel to stop the process.\n"; 57 | 58 | char buf[_countof(fmt) + 45*2]; // 45 is length of a uuid in characters 59 | const char* txt = buf; 60 | LPOLESTR uuidStr = NULL; 61 | 62 | if (S_OK != StringFromCLSID(*lpGUID, &uuidStr) || uuidStr == NULL) { 63 | txt = fmt; 64 | } else { 65 | sprintf_s(buf, fmt, uuidStr); 66 | CoTaskMemFree(uuidStr); 67 | } 68 | 69 | auto idc = MessageBoxA( 70 | NULL, 71 | txt, 72 | "S4ModApi.dll", 73 | MB_YESNOCANCEL | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST | MB_ICONERROR); 74 | 75 | switch (idc) { 76 | case IDNO: 77 | break; 78 | case IDYES: 79 | system("start https://github.com/nyfrk/S4ModApi/issues/1"); 80 | Sleep(2000); 81 | default: // cancel 82 | ExitProcess(0); 83 | } 84 | 85 | showMessageBox = false; 86 | } 87 | 88 | *lplpS4H = NULL; 89 | return E_NOINTERFACE; 90 | } -------------------------------------------------------------------------------- /S4ModApi/S4ModApi.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/S4ModApi.rc -------------------------------------------------------------------------------- /S4ModApi/S4ModApi.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | false 5 | 6 | 7 | WindowsLocalDebugger 8 | 9 | -------------------------------------------------------------------------------- /S4ModApi/dllmain.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #define WIN32_LEAN_AND_MEAN 23 | #include 24 | #include "globals.h" 25 | #include "Console.h" 26 | #include "Log.h" 27 | #include "module.h" // g_hModule 28 | 29 | BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { 30 | UNREFERENCED_PARAMETER(lpReserved); 31 | 32 | switch (ul_reason_for_call) { 33 | case DLL_PROCESS_ATTACH: 34 | g_hModule = hModule; 35 | 36 | #if _DEBUG 37 | InitConsole(); 38 | InitLogstream(); 39 | LOG("S4ModApi.dll has been attached at " << HEXNUM(g_hModule) << '.'); 40 | #endif 41 | 42 | { 43 | // check file name 44 | WCHAR exeFQFilename[MAX_PATH + 1]; // fully qualified file name of the process executable 45 | auto len = GetModuleFileNameW(NULL, exeFQFilename, MAX_PATH); 46 | exeFQFilename[len] = '\0'; 47 | LPCWSTR exeFilename = exeFQFilename; // the filename of the process executable (without path) 48 | for (int i = len; i >= 0; i--) { 49 | auto c = exeFQFilename[i]; 50 | if (c == '\\' || c == '/') { 51 | exeFilename = &(exeFQFilename[i + 1]); 52 | break; 53 | } 54 | } 55 | // is filename S4_Main.exe ? 56 | if (0 == wcscmp(L"S4_Main.exe", exeFilename)) { 57 | TRACE; 58 | 59 | // compute the md5 of the target and cache it 60 | ComputeMD5(exeFQFilename, &g_md5); 61 | 62 | #if _DEBUG 63 | char md5str[2 * MD5LEN + 1]; 64 | g_md5.ToString(md5str, sizeof(md5str)); 65 | LOG("MD5 of " << exeFilename << " is " << md5str << '.'); 66 | #endif 67 | 68 | // prevent lib from beeing unloaded when we are not ready with cleanup yet 69 | // use FreeLibraryAndExitThread to unload it. 70 | HMODULE mod = IncreaseModuleRefcount(InitializeGlobals); 71 | if (mod) { 72 | // evade the loader lock (thread gets started as soon as it becomes attached, witch will 73 | // only happen if the loader lock is released - thus everything is loaded 74 | HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)InitializeGlobals, mod, 0, NULL); 75 | if (!hThread) { 76 | DecreaseModuleRefcount(mod); 77 | return FALSE; // unload DLL 78 | } else { 79 | CloseHandle(hThread); 80 | } 81 | } 82 | } 83 | } 84 | 85 | break; 86 | case DLL_THREAD_ATTACH: 87 | LOG("thread attached"); 88 | break; 89 | case DLL_THREAD_DETACH: 90 | LOG("thread detached"); 91 | break; 92 | case DLL_PROCESS_DETACH: 93 | #ifdef _DEBUG 94 | LOG("S4ModApi.dll has been detached."); 95 | DestroyConsole(); 96 | DestroyLogstream(); 97 | #endif 98 | 99 | break; 100 | } 101 | return TRUE; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /S4ModApi/globals.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #define WIN32_LEAN_AND_MEAN 23 | #include "globals.h" 24 | #include "patterns.h" 25 | #include "s4.h" 26 | #include 27 | #include "CHook.h" 28 | #include "CMod.h" 29 | #include "md5.h" 30 | #include "CMessageBox.h" 31 | #include "CUpdate.h" 32 | 33 | bool g_isGE; 34 | 35 | DWORD S4_Main = 0; 36 | DWORD DDRAW = 0; 37 | DWORD EventEngine = 0; 38 | DWORD GuiEngine2 = 0; 39 | DWORD GfxEngine = 0; 40 | MD5 g_md5; 41 | std::atomic_bool g_isInitialized = false; 42 | 43 | #if _DEBUG 44 | void DebugProgramMain(); 45 | #endif 46 | 47 | DWORD WINAPI InitializeGlobals(HMODULE mod) { 48 | TRACE; 49 | 50 | // find base addresses of modules of interest 51 | S4_Main = (DWORD)GetModuleHandleA(NULL); 52 | DDRAW = (DWORD)GetModuleHandleA("DDRAW"); 53 | EventEngine = (DWORD)GetModuleHandleA("EventEngine"); // GE only 54 | GuiEngine2 = (DWORD)GetModuleHandleA("GuiEngine2"); // GE only 55 | GfxEngine = (DWORD)GetModuleHandleA("GfxEngine"); // GE only 56 | 57 | // set flag if we detect the presence of any dll that is used in the gold edition 58 | g_isGE = EventEngine || GuiEngine2 || GfxEngine; 59 | 60 | // scan for patterns 61 | g_Patterns.Scan(); 62 | 63 | // initialize pointers to game structs 64 | S4::GetInstance().Initialize(); 65 | 66 | // initialize all instantiated hooks (others will be lazy initialized) 67 | CHook::InitAll(); 68 | 69 | // Initialize all mods 70 | CMod::InitAll(); 71 | 72 | // Check for updates 73 | CUpdate::GetInstance().check(); 74 | 75 | g_isInitialized = true; 76 | 77 | #if _DEBUG 78 | DebugProgramMain(); 79 | #endif 80 | 81 | FreeLibraryAndExitThread(mod, 0); // decrements the reference counter 82 | return 0; // never reached 83 | } 84 | -------------------------------------------------------------------------------- /S4ModApi/globals.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include "md5.h" 27 | 28 | extern bool g_isGE; // true if gold edition, false if history edition. 29 | 30 | extern DWORD S4_Main; // base address of S4_Main.exe 31 | extern DWORD DDRAW; // base address of DDRAW.dll 32 | extern DWORD EventEngine; // base address of EventEngine.dll. This is only present in the gold edition. 33 | extern DWORD GuiEngine2; // base address of GuiEngine2.dll. This is only present in the gold edition. 34 | extern DWORD GfxEngine; // base address of GfxEngine.dll. This is only present in the gold edition. 35 | extern MD5 g_md5; // md5 of the exe 36 | extern std::atomic_bool g_isInitialized; // variable that indicates when s4api has been initialized 37 | 38 | 39 | DWORD WINAPI InitializeGlobals(HMODULE mod); 40 | -------------------------------------------------------------------------------- /S4ModApi/lib/.gitignore: -------------------------------------------------------------------------------- 1 | /Dummy 2 | *.cpp 3 | *.bat 4 | *.md -------------------------------------------------------------------------------- /S4ModApi/lib/Debug/Lua321.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/lib/Debug/Lua321.lib -------------------------------------------------------------------------------- /S4ModApi/lib/Debug/Precompiled.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/lib/Debug/Precompiled.lib -------------------------------------------------------------------------------- /S4ModApi/lib/Debug142/Lua321.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/lib/Debug142/Lua321.lib -------------------------------------------------------------------------------- /S4ModApi/lib/Debug142/Precompiled.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/lib/Debug142/Precompiled.lib -------------------------------------------------------------------------------- /S4ModApi/lib/Release/Lua321.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/lib/Release/Lua321.lib -------------------------------------------------------------------------------- /S4ModApi/lib/Release/Precompiled.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyfrk/S4ModApi/bb5d40ead1bb2a111ec0f787a6da5c15e130684e/S4ModApi/lib/Release/Precompiled.lib -------------------------------------------------------------------------------- /S4ModApi/lib/hlib.cpp: -------------------------------------------------------------------------------- 1 | // hlib aggregation placeholder 2 | -------------------------------------------------------------------------------- /S4ModApi/lib/lauxlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lauxlib.h,v 1.12 1999/03/10 14:19:41 roberto Exp $ 3 | ** Auxiliary functions for building Lua libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef auxlib_h 9 | #define auxlib_h 10 | 11 | 12 | #include "lua.h" 13 | 14 | 15 | struct luaL_reg { 16 | char *name; 17 | lua_CFunction func; 18 | }; 19 | 20 | 21 | #define luaL_arg_check(cond,numarg,extramsg) if (!(cond)) \ 22 | luaL_argerror(numarg,extramsg) 23 | 24 | void luaL_openlib (struct luaL_reg *l, int n); 25 | void luaL_argerror (int numarg, char *extramsg); 26 | #define luaL_check_string(n) (luaL_check_lstr((n), NULL)) 27 | char *luaL_check_lstr (int numArg, long *len); 28 | #define luaL_opt_string(n, d) (luaL_opt_lstr((n), (d), NULL)) 29 | char *luaL_opt_lstr (int numArg, char *def, long *len); 30 | double luaL_check_number (int numArg); 31 | #define luaL_check_int(n) ((int)luaL_check_number(n)) 32 | #define luaL_check_long(n) ((long)luaL_check_number(n)) 33 | double luaL_opt_number (int numArg, double def); 34 | #define luaL_opt_int(n,d) ((int)luaL_opt_number(n,d)) 35 | #define luaL_opt_long(n,d) ((long)luaL_opt_number(n,d)) 36 | lua_Object luaL_functionarg (int arg); 37 | lua_Object luaL_tablearg (int arg); 38 | lua_Object luaL_nonnullarg (int numArg); 39 | void luaL_verror (char *fmt, ...); 40 | char *luaL_openspace (int size); 41 | void luaL_resetbuffer (void); 42 | void luaL_addchar (int c); 43 | int luaL_getsize (void); 44 | void luaL_addsize (int n); 45 | int luaL_newbuffer (int size); 46 | void luaL_oldbuffer (int old); 47 | char *luaL_buffer (void); 48 | int luaL_findstring (char *name, char *list[]); 49 | void luaL_chunkid (char *out, char *source, int len); 50 | void luaL_filesource (char *out, char *filename, int len); 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /S4ModApi/lib/luadebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: luadebug.h,v 1.6 1999/03/04 21:17:26 roberto Exp $ 3 | ** Debugging API 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef luadebug_h 9 | #define luadebug_h 10 | 11 | 12 | #include "lua.h" 13 | 14 | typedef lua_Object lua_Function; 15 | 16 | typedef void (*lua_LHFunction) (int line); 17 | typedef void (*lua_CHFunction) (lua_Function func, char *file, int line); 18 | 19 | lua_Function lua_stackedfunction (int level); 20 | void lua_funcinfo (lua_Object func, char **source, int *linedefined); 21 | int lua_currentline (lua_Function func); 22 | char *lua_getobjname (lua_Object o, char **name); 23 | 24 | lua_Object lua_getlocal (lua_Function func, int local_number, char **name); 25 | int lua_setlocal (lua_Function func, int local_number); 26 | 27 | int lua_nups (lua_Function func); 28 | 29 | lua_LHFunction lua_setlinehook (lua_LHFunction func); 30 | lua_CHFunction lua_setcallhook (lua_CHFunction func); 31 | int lua_setdebug (int debug); 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /S4ModApi/lib/lualib.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** $Id: lualib.h,v 1.6 1999/05/05 19:23:11 roberto Exp $ 3 | ** Lua standard libraries 4 | ** See Copyright Notice in lua.h 5 | */ 6 | 7 | 8 | #ifndef lualib_h 9 | #define lualib_h 10 | 11 | #include "lua.h" 12 | 13 | void lua_iolibopen (void); 14 | void lua_strlibopen (void); 15 | void lua_mathlibopen (void); 16 | void lua_dblibopen (void); 17 | 18 | 19 | void lua_userinit (void); 20 | 21 | 22 | /* To keep compatibility with old versions */ 23 | 24 | #define iolib_open lua_iolibopen 25 | #define strlib_open lua_strlibopen 26 | #define mathlib_open lua_mathlibopen 27 | 28 | 29 | 30 | /* Auxiliary functions (private) */ 31 | 32 | char *luaI_classend (char *p); 33 | int luaI_singlematch (int c, char *p, char *ep); 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /S4ModApi/md5.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "md5.h" 23 | 24 | #include 25 | #include 26 | #include "Log.h" 27 | 28 | #define BUFSIZE 1024 29 | 30 | SIZE_T MD5::ToString(LPSTR out, SIZE_T sz) { 31 | TRACE; 32 | CONST CHAR rgbDigits[] = "0123456789ABCDEF"; 33 | auto to = min(sz, MD5LEN * 2); 34 | for (size_t i = 0; i < to; i++) { 35 | auto& b = bytes[i / 2]; // byte takes two characters 36 | out[i] = rgbDigits[(i % 2) ? (b & 0xF) : (b >> 4)]; 37 | } 38 | if (to < sz) { 39 | out[to] = '\0'; 40 | ++to; 41 | } 42 | return to; 43 | } 44 | 45 | #pragma warning(push) 46 | #pragma warning( disable : 4706 ) 47 | HRESULT ComputeMD5(LPCWSTR filename, MD5* out) { 48 | TRACE; 49 | // This is basically just the sample from here: 50 | // https://docs.microsoft.com/de-de/windows/win32/seccrypto/example-c-program--creating-an-md-5-hash-from-file-content?redirectedfrom=MSDN 51 | // Note, you may change CALG_MD5 to CALG_SHA1 to get the SHA1 sum. 52 | 53 | DWORD dwStatus = 0; 54 | BOOL bResult = FALSE; 55 | HCRYPTPROV hProv = 0; 56 | HCRYPTHASH hHash = 0; 57 | HANDLE hFile = NULL; 58 | BYTE rgbFile[BUFSIZE]; 59 | DWORD cbRead = 0; 60 | auto& rgbHash = out->bytes; 61 | DWORD cbHash = 0; 62 | 63 | hFile = CreateFileW(filename, 64 | GENERIC_READ, 65 | FILE_SHARE_READ, 66 | NULL, 67 | OPEN_EXISTING, 68 | FILE_FLAG_SEQUENTIAL_SCAN, 69 | NULL); 70 | 71 | if (INVALID_HANDLE_VALUE == hFile) { 72 | dwStatus = GetLastError(); 73 | return dwStatus; 74 | } 75 | 76 | // Get handle to the crypto provider 77 | if (!CryptAcquireContext(&hProv, 78 | NULL, 79 | NULL, 80 | PROV_RSA_FULL, 81 | CRYPT_VERIFYCONTEXT)) { 82 | dwStatus = GetLastError(); 83 | CloseHandle(hFile); 84 | return dwStatus; 85 | } 86 | 87 | if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { 88 | dwStatus = GetLastError(); 89 | CloseHandle(hFile); 90 | CryptReleaseContext(hProv, 0); 91 | return dwStatus; 92 | } 93 | 94 | while (bResult = ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL)) { 95 | if (0 == cbRead) { 96 | break; 97 | } 98 | 99 | if (!CryptHashData(hHash, rgbFile, cbRead, 0)) { 100 | dwStatus = GetLastError(); 101 | CryptReleaseContext(hProv, 0); 102 | CryptDestroyHash(hHash); 103 | CloseHandle(hFile); 104 | return dwStatus; 105 | } 106 | } 107 | #pragma warning(pop) 108 | 109 | if (!bResult) { 110 | dwStatus = GetLastError(); 111 | CryptReleaseContext(hProv, 0); 112 | CryptDestroyHash(hHash); 113 | CloseHandle(hFile); 114 | return dwStatus; 115 | } 116 | 117 | cbHash = MD5LEN; 118 | if (!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) { 119 | dwStatus = GetLastError(); 120 | } 121 | 122 | CryptDestroyHash(hHash); 123 | CryptReleaseContext(hProv, 0); 124 | CloseHandle(hFile); 125 | 126 | return dwStatus; 127 | } -------------------------------------------------------------------------------- /S4ModApi/md5.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #define MD5LEN 16 25 | 26 | #include "Windows.h" 27 | 28 | struct MD5 { 29 | BYTE bytes[MD5LEN] = { 0 }; 30 | 31 | SIZE_T ToString(LPSTR out, SIZE_T sz); 32 | }; 33 | 34 | HRESULT ComputeMD5(LPCWSTR filename, MD5 *out); 35 | -------------------------------------------------------------------------------- /S4ModApi/module.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #define WIN32_LEAN_AND_MEAN 23 | #include "windows.h" 24 | #include "Log.h" 25 | 26 | HMODULE g_hModule = NULL; 27 | 28 | HMODULE IncreaseModuleRefcount(LPCVOID target) { 29 | TRACE; 30 | HMODULE out; 31 | if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)target, &out)) { 32 | return out; 33 | } 34 | return NULL; 35 | } 36 | 37 | BOOL DecreaseModuleRefcount(HMODULE mod) { 38 | TRACE; 39 | return FreeLibrary(mod); 40 | } -------------------------------------------------------------------------------- /S4ModApi/module.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include "windows.h" 25 | 26 | extern HMODULE g_hModule; 27 | HMODULE IncreaseModuleRefcount(LPCVOID target); // NULL on failure 28 | BOOL DecreaseModuleRefcount(HMODULE module); // true if successfull 29 | -------------------------------------------------------------------------------- /S4ModApi/patterns.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | struct PatternAddr { 27 | void Scan(LPCSTR name, DWORD base, LPCSTR basename, LPCSTR patternStr); 28 | 29 | DWORD addr; 30 | DWORD base; 31 | LPCSTR name; 32 | LPCSTR basename; 33 | 34 | operator bool() const; 35 | operator DWORD() const; 36 | operator LPCVOID() const; 37 | DWORD operator+(int off); 38 | DWORD operator-(int off); 39 | }; 40 | 41 | extern struct Patterns { 42 | // Debug Rendering Patterns 43 | PatternAddr 44 | OnMapInitHook, 45 | PillarboxWidth, 46 | OnFrameHook, 47 | Hwnd, 48 | Backbuffer, 49 | OnSettlerCommandHook, 50 | OnTickHook, 51 | OnMouseButtonHook, 52 | HoveringUiElement, 53 | MenuScreenObj, 54 | CurrentMenuScreen, 55 | GameMenusWndProc, 56 | WndProcChain, 57 | ActiveIngameMenu, 58 | SettlerFilter, 59 | ClearSelection, 60 | NetEventConstuctor, 61 | RecruitmentEventConstructor, 62 | LocalEvent, 63 | Lua, 64 | ShowTextMessage, 65 | OnLuaOpenHook, 66 | OnBltHook, 67 | 68 | BoxSelect, 69 | AltSelect, 70 | UnitsPerRightclick, 71 | SelectionMarkerBufferGetter, 72 | SelectionMarkerBufferSetter, 73 | HealthBubbleBufferGetter, 74 | HealthBubbleBufferSetter 75 | ; 76 | 77 | void Scan(); 78 | 79 | Patterns() = default; 80 | private: 81 | Patterns(const Patterns&) = delete; 82 | Patterns& operator=(Patterns const&) = delete; 83 | } g_Patterns; 84 | 85 | -------------------------------------------------------------------------------- /S4ModApi/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Von Microsoft Visual C++ generierte Includedatei. 3 | // Verwendet durch S4ModApi.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 104 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1005 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /S4ModApi/safemem.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // GNU Lesser General Public License v3 (LGPL v3) 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // This file is part of S4ModApi. 7 | // 8 | // S4ModApi is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // S4ModApi is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with S4ModApi. If not, see . 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #define WIN32_LEAN_AND_MEAN 23 | #include "Windows.h" 24 | #include "Log.h" 25 | 26 | extern "C" { 27 | 28 | void* __stdcall memget_s(void* dst, const void* src, size_t len) { 29 | #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__ ) // export undecorated 30 | #pragma comment(linker, "/EXPORT:" __FUNCDNAME__ ) // export stdcall decorated 31 | TRACE; 32 | DWORD read = 0; 33 | if (!ReadProcessMemory(GetCurrentProcess(), src, dst, len, &read) || read != len) { 34 | return NULL; 35 | } 36 | return dst; 37 | } 38 | 39 | void* __stdcall memset_s(void* dst, const void* src, size_t len) { 40 | #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__ ) // export undecorated 41 | #pragma comment(linker, "/EXPORT:" __FUNCDNAME__ ) // export stdcall decorated 42 | TRACE; 43 | DWORD writtn = 0; 44 | if (!WriteProcessMemory(GetCurrentProcess(), dst, src, len, &writtn) || writtn != len) { 45 | return NULL; 46 | } 47 | return dst; 48 | } 49 | 50 | DWORD __stdcall READ_AT(const void* src, int offset) { 51 | #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__ ) // export undecorated 52 | #pragma comment(linker, "/EXPORT:" __FUNCDNAME__ ) // export stdcall decorated 53 | TRACE; 54 | DWORD ret; 55 | if (src && ReadProcessMemory(GetCurrentProcess(), (LPCVOID)((DWORD)src + offset), &ret, sizeof(DWORD), NULL)) { 56 | return ret; 57 | } 58 | return 0; 59 | } 60 | 61 | BOOL __stdcall WRITE_AT(void* dst, DWORD val, int offset) { 62 | #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__ ) // export undecorated 63 | #pragma comment(linker, "/EXPORT:" __FUNCDNAME__ ) // export stdcall decorated 64 | TRACE; 65 | return (dst && WriteProcessMemory(GetCurrentProcess(), (LPVOID)((DWORD)dst + offset), &val, sizeof(DWORD), NULL)); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /S4ModApi/safemem.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // MIT License 3 | // 4 | // Copyright (c) 2022 nyfrk and contributors 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | /////////////////////////////////////////////////////////////////////////////// 24 | 25 | #pragma once 26 | 27 | #include "windef.h" 28 | 29 | extern "C" { 30 | 31 | /** 32 | * Read memory from source (safe read) 33 | **/ 34 | void* __stdcall memget_s(void* dst, const void* src, size_t len); 35 | 36 | /** 37 | * Write memory at destination (safe write) 38 | **/ 39 | void* __stdcall memset_s(void* dst, const void* src, size_t len); 40 | 41 | /** 42 | * Read a DWORD from memory or return 0 on failure. (Safe read) 43 | **/ 44 | DWORD __stdcall READ_AT(const void* src, int offset = 0); 45 | 46 | /** 47 | * Write a DWORD to memory or return 0 on failure. (Safe write) 48 | **/ 49 | BOOL __stdcall WRITE_AT(void* dst, DWORD val, int offset = 0); 50 | 51 | } -------------------------------------------------------------------------------- /UpdateExamples.bat: -------------------------------------------------------------------------------- 1 | cd %0\..\Examples 2 | 3 | copy ..\Release\S4ModApi.lib HelloWorld\HelloWorld 4 | copy ..\S4ModApi\S4ModApi.h HelloWorld\HelloWorld 5 | 6 | copy ..\Release\S4ModApi.lib LuaExample\LuaExample 7 | copy ..\S4ModApi\S4ModApi.h LuaExample\LuaExample 8 | 9 | copy ..\Release\S4ModApi.lib HotkeysExample\HotkeysExample 10 | copy ..\S4ModApi\S4ModApi.h HotkeysExample\HotkeysExample 11 | 12 | copy ..\Release\S4ModApi.lib SelectionLimitExample\SelectionLimitExample 13 | copy ..\S4ModApi\S4ModApi.h SelectionLimitExample\SelectionLimitExample 14 | 15 | -------------------------------------------------------------------------------- /VERSION.md: -------------------------------------------------------------------------------- 1 | # S4ModApi Versioning 2 | 3 | Every release gets from now on a fixed Application Binary Interface (ABI), meaning that mods linking against an older version will still be compatible even when a more recent S4ModApi.dll is used. The COM Pattern is used to ensure ABI compatibility. This allows players to update the S4ModApi.dll independently of their plugins. Plugins can be made compatible by updating S4ModApi.dll when new game versions are published - without having to recompile or even touching the source code of a plugin. 4 | 5 | 6 | 7 | ## Semantic Versioning 8 | 9 | S4ModApi now adopts a semantic versioning scheme (mayor.minor.patch). The digits are increased according to the following rules. 10 | 11 | * Mayor digit is increased when a new interface using a fresh UUID is added to the S4ModApi. The new interface may reorder, add, change or remove methods from the interface. Specification of methods may change. Interfaces requested using an older UUID will still get an appropriate interface. 12 | 13 | * Minor digit is increased when specification changes happen that do not break previous versions interfaces and no new UUID is required. That is the case when methods are just appended to the current interface or when all methods still adhere mostly to their previous specification. For example a specification change is acceptable if a previously reserved argument or method is now implemented. This is also the case for bug fixes (changing implementation to comply specification). 14 | 15 | * Patch digit is not used and is always 0. It is ignored by the auto update feature. 16 | 17 | Versions according to these rules may also be increased for changes to older interfaces. Lets say for example the current S4ModApi is in version 3.3. The change to 3.4 may change features that were initially implemented in version 2.0 (e.g. bug fixes). Plugins that were linked to version 2.0 may now enjoy the fixed behavior even though it was linked against the older version. Please note that at some point this will be difficult to maintain and we may thus decide at any point to not fix old bugs. Especially when we notice that plugins rely on these. 18 | 19 | Note: If your plugin was compiled against version 1.x or older you will have to recompile your plugin using a newer S4ModApi Version. 20 | 21 | 22 | 23 | ## ISettlers4Api Interface Versioning 24 | 25 | With every mayor version a new interface is created. These are indicated by the suffix to the interface name. For example ISettlers4Api3 is the interface requested by plugins that were compiled using S4ModApi 3.x.x. When recompiling your plugin using the latest S4ModApi, make sure to replace the old S4ModApi.h header file and the linking library S4ModApi.lib. 26 | 27 | --------------------------------------------------------------------------------