ported some patches

This commit is contained in:
itsmattkc 2021-09-22 12:16:20 -07:00
parent f5dae0804a
commit f0904e54b9
12 changed files with 346 additions and 100 deletions

View file

@ -11,6 +11,10 @@ option(BUILD_UNICODE "Build with Unicode support" ON)
# Build our code injected DLL
#
add_library(Rebld SHARED
cmn/path.cpp
cmn/path.h
lib/config.cpp
lib/config.h
lib/dllmain.cpp
lib/hooks.cpp
lib/hooks.h
@ -21,7 +25,7 @@ add_library(Rebld SHARED
lib/worker.h
)
target_compile_options(Rebld PRIVATE /MT)
target_link_libraries(Rebld PRIVATE winmm.lib)
target_link_libraries(Rebld PRIVATE winmm.lib shlwapi.lib)
# Add property grid
set(PROPERTYGRID_BUILD_APP OFF CACHE BOOL "")
@ -31,6 +35,8 @@ add_subdirectory(ext/PropertyGrid)
# Build launcher/configuration executable
#
add_executable(Rebuilder WIN32
cmn/path.cpp
cmn/path.h
res/res.rc
res/resource.h
src/app.cpp

11
cmn/combo.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COMBO_H
#define COMBO_H
enum ModelQuality {
kModelQualityInfinite,
kModelQualityHigh,
kModelQualityMedium,
kModelQualityLow
};
#endif // COMBO_H

94
cmn/path.cpp Normal file
View file

@ -0,0 +1,94 @@
#include "path.h"
#include <SHLOBJ.H>
#include <SHLWAPI.H>
#include <STRING>
#include <TCHAR.H>
LPCTSTR appName = TEXT("Rebuilder");
BOOL DirectoryExists(LPCTSTR szPath)
{
return PathFileExists(szPath) && PathIsDirectory(szPath);
}
BOOL RecursivelyCreateDirectory(LPCTSTR directory)
{
if (DirectoryExists(directory)) {
// Directory already exists, do nothing
return TRUE;
} else {
// Determine directory of this directory
std::basic_string<TCHAR> copy = directory;
PathRemoveFileSpec(&copy[0]);
// Create if necessary
if (RecursivelyCreateDirectory(copy.c_str())) {
return CreateDirectory(directory, NULL);
} else {
return FALSE;
}
}
}
#ifdef UNICODE
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
#else
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
#endif
BOOL GetAppDataPath(LPTSTR s)
{
OSVERSIONINFO info;
ZeroMemory(&info, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
// Dynamically link to SHGetSpecialFolderPath because not all versions of Windows have it
#ifdef UNICODE
LPCSTR functionName = "SHGetSpecialFolderPathW";
#else
LPCSTR functionName = "SHGetSpecialFolderPathA";
#endif
SHGetSpecialFolderPathSignature GetSpecialFolderPath = (SHGetSpecialFolderPathSignature)GetProcAddress(GetModuleHandle(_T("SHELL32.DLL")), functionName);
BOOL haveDir = FALSE;
BOOL usedShell = FALSE;
if (GetSpecialFolderPath) {
haveDir = GetSpecialFolderPath(NULL, s, CSIDL_APPDATA, TRUE);
usedShell = TRUE;
} else {
// Assume we're on Windows 95 which has no application data folder, we bodge it to write to
// "C:\Windows\Application Data" which is roughly where 98/Me would do it
GetWindowsDirectory(s, MAX_PATH);
_tcscat(s, _T("\\Application Data"));
haveDir = TRUE;
}
//MessageBox(0, s, usedShell ? _T("Using API") : _T("Is this Windows 95?"), 0);
return haveDir;
}
BOOL GetConfigFilename(LPTSTR s)
{
if (GetAppDataPath(s)) {
_tcscat(s, _T("\\LEGOIslandRebuilder"));
if (RecursivelyCreateDirectory(s)) {
_tcscat(s, _T("\\settings.ini"));
return TRUE;
}
}
return FALSE;
}
BOOL GetSafeLEGOIslandSavePath(LPTSTR s)
{
if (GetAppDataPath(s)) {
_tcscat(s, _T("\\LEGO Island"));
if (RecursivelyCreateDirectory(s)) {
return TRUE;
}
}
return FALSE;
}

12
cmn/path.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef PATH_H
#define PATH_H
#include <WINDOWS.H>
BOOL GetSafeLEGOIslandSavePath(LPTSTR s);
BOOL GetConfigFilename(LPTSTR s);
extern LPCTSTR appName;
#endif // PATH_H

24
lib/config.cpp Normal file
View file

@ -0,0 +1,24 @@
#include "config.h"
#include <SHLWAPI.H>
#include "../cmn/path.h"
Config config;
Config::Config()
{
}
BOOL Config::Load()
{
// Get config file
m_configFile.resize(MAX_PATH);
return GetConfigFilename(&m_configFile[0]) && PathFileExists(m_configFile.c_str());
}
UINT Config::GetInt(LPCTSTR name, UINT defaultValue)
{
return GetPrivateProfileInt(appName, name, defaultValue, m_configFile.c_str());
}

24
lib/config.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <STRING>
#include <TCHAR.H>
#include <WINDOWS.H>
class Config
{
public:
Config();
BOOL Load();
UINT GetInt(LPCTSTR name, UINT defaultValue = 0);
private:
std::basic_string<TCHAR> m_configFile;
};
extern Config config;
#endif // CONFIG_H

View file

@ -2,19 +2,23 @@
#include <STDIO.H>
#include "../cmn/path.h"
#include "config.h"
#include "util.h"
HWND isleWindow = NULL;
void InterceptOutputDebugStringA(LPCSTR s)
{
printf("%s\n", s);
MessageBoxA(0,s,"LEGO Island sez",0);
MessageBoxA(isleWindow, s, "LEGO Island sez", 0);
}
HWND WINAPI InterceptCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
{
HWND window = CreateWindowExA(dwExStyle, lpClassName, "LEGO Island: Rebuilt", dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
return window;
// Grab a copy of the ISLE window so we can do stuff with it
isleWindow = CreateWindowExA(dwExStyle, lpClassName, "LEGO Island: Rebuilt", dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
return isleWindow;
}
HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName)
@ -106,10 +110,71 @@ HRESULT WINAPI InterceptDirectDrawCreate(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUn
{
HRESULT res = ddCreateOriginal(lpGUID, lplpDD, pUnkOuter);
if (res == DD_OK && !originalGetDisplayMode) {
originalGetDisplayMode = (ddGetDisplayModeFunction)OverwriteVirtualTable(*lplpDD, 0xC, (LPVOID)InterceptGetDisplayMode);
originalCreateSurfaceFunction = (ddCreateSurfaceFunction)OverwriteVirtualTable(*lplpDD, 0x6, (LPVOID)InterceptCreateSurface);
if (res == DD_OK) {
if (!originalGetDisplayMode) {
originalGetDisplayMode = (ddGetDisplayModeFunction)OverwriteVirtualTable(*lplpDD, 0xC, (LPVOID)InterceptGetDisplayMode);
}
ddCreateSurfaceFunction f = (ddCreateSurfaceFunction)OverwriteVirtualTable(*lplpDD, 0x6, (LPVOID)InterceptCreateSurface);
if (f != InterceptCreateSurface) {
originalCreateSurfaceFunction = f;
}
}
return res;
}
void ReturnRegistryYESNOFromBool(LPBYTE lpData, BOOL value)
{
strcpy((char*)lpData, value ? "YES" : "NO");
}
LONG WINAPI InterceptRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
if (!strcmp(lpValueName, "Music")) {
// Music option
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("MusicToggle"), 1));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "UseJoystick")) {
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("UseJoystick"), 0));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "Full Screen")) {
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("FullScreen"), 1));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "Draw Cursor")) {
ReturnRegistryYESNOFromBool(lpData, config.GetInt(_T("DrawCursor"), 1));
return ERROR_SUCCESS;
} else if (!strcmp(lpValueName, "savepath")) {
// If enabled, return a safe %APPDATA% based save location rather than its default
// "C:\Program Files" location
if (config.GetInt(_T("RedirectSaveData"))) {
// Generate directory
TCHAR save_path[MAX_PATH];
if (GetSafeLEGOIslandSavePath(save_path)) {
strcpy((char*)lpData, save_path);
return ERROR_SUCCESS;
} else {
MessageBoxA(isleWindow, "Failed to redirect save path. Default will be used instead.", 0, 0);
}
}
} else if (!strcmp(lpValueName, "diskpath") || !strcmp(lpValueName, "cdpath")) {
// Pass through
} else {
MessageBoxA(isleWindow, lpValueName, "ISLE asked for...", 0);
}
// Pass these through
return RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
}

View file

@ -21,6 +21,17 @@ HWND WINAPI InterceptCreateWindowExA(
LPVOID lpParam
);
LONG
APIENTRY
InterceptRegQueryValueExA (
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
HWND WINAPI InterceptFindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
typedef HRESULT (WINAPI *ddCreateFunction)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuterS);

View file

@ -1,13 +1,18 @@
#include "worker.h"
#include <TCHAR.H>
#include <VECTOR>
#include "config.h"
#include "hooks.h"
#include "util.h"
DWORD WINAPI Patch()
{
MessageBoxA(0,"Connect debugger now",0,0);
if (!config.Load()) {
MessageBoxA(0, "Failed to find Rebuilder configuration. No patches will be active.", 0, 0);
return 1;
}
// Hook import address table
LPVOID exeBase = GetModuleHandle(TEXT("ISLE.EXE"));
@ -15,31 +20,47 @@ DWORD WINAPI Patch()
// Redirect various imports
OverwriteImport(exeBase, "CreateWindowExA", (LPVOID)InterceptCreateWindowExA);
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
OverwriteImport(dllBase, "OutputDebugStringA", (LPVOID)InterceptOutputDebugStringA);
OverwriteImport(exeBase, "RegQueryValueExA", (LPVOID)InterceptRegQueryValueExA);
ddCreateOriginal = (ddCreateFunction)OverwriteImport(dllBase, "DirectDrawCreate", (LPVOID)InterceptDirectDrawCreate);
// Stay active when defocused
SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3);
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xE0\x00\x00\x00", "\xC7\x44\x24\x24\xE0\x80\x00\x00", 8);
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xB0\x00\x00\x00", "\xC7\x44\x24\x24\xB0\x80\x00\x00", 8);
SearchReplacePattern(dllBase, "\xC7\x45\xCC\x11\x00\x00\x00", "\xC7\x45\xCC\x11\x80\x00\x00", 7);
SearchReplacePattern(dllBase, "\xC7\x45\xCC\xE0\x00\x00\x00", "\xC7\x45\xCC\xE0\x80\x00\x00", 7);
if (config.GetInt(_T("StayActiveWhenDefocused"))) {
// Patch jump if window isn't active
SearchReplacePattern(exeBase, "\x89\x58\x70", "\x90\x90\x90", 3);
// Patch DirectSound flags so that sound doesn't mute when inactive
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xE0\x00\x00\x00", "\xC7\x44\x24\x24\xE0\x80\x00\x00", 8);
SearchReplacePattern(dllBase, "\xC7\x44\x24\x24\xB0\x00\x00\x00", "\xC7\x44\x24\x24\xB0\x80\x00\x00", 8);
SearchReplacePattern(dllBase, "\xC7\x45\xCC\x11\x00\x00\x00", "\xC7\x45\xCC\x11\x80\x00\x00", 7);
SearchReplacePattern(dllBase, "\xC7\x45\xCC\xE0\x00\x00\x00", "\xC7\x45\xCC\xE0\x80\x00\x00", 7);
}
// Allow multiple instances
if (config.GetInt(_T("AllowMultipleInstances"))) {
// Patch FindWindowA import to always tell ISLE that no other ISLE window exists
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
}
// Debug mode
if (config.GetInt(_T("DebugToggle"))) {
// LEGO1 uses a string pointer to know if OGEL has been typed, if the string pointer sees 0x0
// (null-terminator/end of string), then debug mode is enabled. So we just replace the first
// character with 0x0 and it's permanently on.
SearchReplacePattern(dllBase, "OGEL", "\x0GEL", 4, TRUE);
}
// DDRAW GetSurfaceDesc Override
//OverwriteCall((LPVOID) ((UINT_PTR)dllBase+0xBA7D5), (LPVOID)InterceptSurfaceGetDesc);
OverwriteCall((LPVOID) ((UINT_PTR)dllBase+0xBA7D5), (LPVOID)InterceptSurfaceGetDesc);
// Window size hack
/*SearchReplacePattern(exeBase,
"\x80\x02\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00",
"\x40\x01\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00", 24);*/
/*char debug[5];
debug[0] = 0xE8;
*(UINT_PTR*)(&debug[1]) = (UINT_PTR)InterceptOutputDebugStringA;
if (SIZE_T replacements = SearchReplacePattern(legoBase, "\xE8\x34\x08\x00\x00", debug, 5)) {
printf("Hooked some other debug function %lu times", replacements);
}*/
return 0;
}

View file

@ -1,5 +1,9 @@
#include "patchgrid.h"
#include <SSTREAM>
#include "../cmn/path.h"
PatchGrid::PatchGrid()
{
SetBoldModified(true);
@ -39,13 +43,14 @@ PatchGrid::PatchGrid()
HSECTION sectionControls = AddSection(_T("Controls"));
AddPatch("UseWASD",
_T(""),
_T("Enables the use of WASD keys for movement rather than the arrow keys. "
"NOTE: When using Debug Mode, this patch will re-map the conflicting debug keys to the arrow keys."),
AddBoolItem(sectionControls, _T("Use WASD"), false));
AddPatch("UseJoystick",
_T(""),
_T("Enables Joystick functionality."),
AddBoolItem(sectionControls, _T("Use Joystick"), false));
AddPatch("MouseDeadzone",
_T(""),
_T("Sets the radius from the center of the screen where the mouse will do nothing (40 = default)."),
AddIntegerItem(sectionControls, _T("Mouse Deadzone"), 40));
AddPatch("UnhookTurnSpeed",
_T("LEGO Island contains a bug where the turning speed is influenced by the frame rate. Enable this to make the turn speed independent of the frame rate."),
@ -129,12 +134,55 @@ PatchGrid::PatchGrid()
AddBoolItem(sectionMusic, _T("Play Music"), true));
}
template<typename T>
std::string toString(const T &value)
{
std::ostringstream oss;
oss << value;
return oss.str();
}
BOOL PatchGrid::SaveConfiguration(LPCTSTR filename)
{
LPCTSTR appName = TEXT("Rebuilder");
for (std::map<std::string, HITEM>::const_iterator it=m_mPatchItems.begin(); it!=m_mPatchItems.end(); it++) {
CItem *item = FindItem(it->second);
std::string value;
// Convert value to string
switch (item->m_type) {
case IT_STRING:
case IT_TEXT:
case IT_FILE:
case IT_FOLDER:
value = item->m_strValue;
break;
case IT_BOOLEAN:
value = toString(item->m_bValue);
break;
case IT_COMBO:
case IT_INTEGER:
value = toString(item->m_nValue);
break;
case IT_DOUBLE:
value = toString(item->m_dValue);
break;
case IT_COLOR:
value = toString(item->m_clrValue);
break;
case IT_CUSTOM:
case IT_DATE:
case IT_DATETIME:
case IT_FONT:
{
// Report inability to serialize
TCHAR buf[200];
sprintf(buf, "Failed to serialize %s to string.", it->first.c_str());
MessageBox(buf);
break;
}
}
this->GetItemValue(it->second, value);
if (!WritePrivateProfileString(appName, it->first.c_str(), value.c_str(), filename)) {
return FALSE;

View file

@ -1,8 +1,8 @@
#include "window.h"
#include <SHLWAPI.H>
#include <WINDOWS.H>
#include "../cmn/path.h"
#include "launcher.h"
#include "../res/resource.h"
@ -91,10 +91,8 @@ DWORD WINAPI WaitForProcessToClose(HANDLE hProcess)
void CRebuilderWindow::OnRunClick()
{
TCHAR configPath[MAX_PATH];
if (GetConfigPath(configPath)) {
// Append path and save configuration
_tcscat(configPath, _T("\\settings.ini"));
if (GetConfigFilename(configPath)) {
if (m_cPatchGrid.SaveConfiguration(configPath)) {
if (HANDLE proc = Launcher::Launch(this->GetSafeHwnd())) {
m_lProcesses.push_back(proc);
@ -252,72 +250,6 @@ void CRebuilderWindow::SwitchButtonMode(BOOL running)
}
}
BOOL DirectoryExists(LPCTSTR szPath)
{
return PathFileExists(szPath) && PathIsDirectory(szPath);
}
BOOL RecursivelyCreateDirectory(LPCTSTR directory)
{
if (DirectoryExists(directory)) {
// Directory already exists, do nothing
return TRUE;
} else {
// Determine directory of this directory
std::basic_string<TCHAR> copy = directory;
PathRemoveFileSpec(&copy[0]);
// Create if necessary
if (RecursivelyCreateDirectory(copy.c_str())) {
return CreateDirectory(directory, NULL);
} else {
return FALSE;
}
}
}
#ifdef UNICODE
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
#else
typedef BOOL (WINAPI *SHGetSpecialFolderPathSignature)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
#endif
BOOL CRebuilderWindow::GetConfigPath(LPTSTR s)
{
OSVERSIONINFO info;
ZeroMemory(&info, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
// Dynamically link to SHGetSpecialFolderPath because not all versions of Windows have it
#ifdef UNICODE
LPCSTR functionName = "SHGetSpecialFolderPathW";
#else
LPCSTR functionName = "SHGetSpecialFolderPathA";
#endif
SHGetSpecialFolderPathSignature GetSpecialFolderPath = (SHGetSpecialFolderPathSignature)GetProcAddress(GetModuleHandle(_T("SHELL32.DLL")), functionName);
BOOL haveDir = FALSE;
BOOL usedShell = FALSE;
if (GetSpecialFolderPath) {
haveDir = GetSpecialFolderPath(NULL, s, CSIDL_APPDATA, TRUE);
usedShell = TRUE;
} else {
// Assume we're on Windows 95 which has no application data folder, we bodge it to write to
// "C:\Windows\Application Data" which is roughly where 98/Me would do it
GetWindowsDirectory(s, MAX_PATH);
_tcscat(s, _T("\\Application Data"));
haveDir = TRUE;
}
if (haveDir) {
_tcscat(s, _T("\\LEGOIslandRebuilder"));
MessageBox(s, usedShell ? _T("Using API") : _T("Is this Windows 95?"));
return RecursivelyCreateDirectory(s);
} else {
return FALSE;
}
}
BEGIN_MESSAGE_MAP(CRebuilderWindow, super)
ON_WM_SIZE()
ON_WM_GETMINMAXINFO()

View file

@ -34,8 +34,6 @@ private:
void SwitchButtonMode(BOOL running);
BOOL GetConfigPath(LPTSTR s);
enum {
ID_RUN = 1000,
ID_KILL,