finished last of the patches

This commit is contained in:
itsmattkc 2021-11-29 09:30:50 -08:00
parent 3816530f4e
commit 08c3ac2f54
6 changed files with 127 additions and 12 deletions

View file

@ -190,16 +190,8 @@ LONG WINAPI InterceptRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpR
void WINAPI InterceptSleep(DWORD dwMilliseconds) void WINAPI InterceptSleep(DWORD dwMilliseconds)
{ {
// Do nothing // If uncapped, do nothing. Otherwise pass through as normal.
std::string fps_behavior = config.GetString(_T("FPSLimit")); if (config.GetString(_T("FPSLimit")) != "Uncapped") {
// If uncapped, do nothing
if (fps_behavior != "Uncapped") {
// If not default, pass through new FPS
if (fps_behavior == "Limited") {
dwMilliseconds = 1000.0f / config.GetFloat(_T("CustomFPS"));
}
Sleep(dwMilliseconds); Sleep(dwMilliseconds);
} }
} }
@ -216,6 +208,37 @@ HRESULT WINAPI InterceptD3DRMViewportSetField(LPDIRECT3DRMVIEWPORT viewport, D3D
return d3drmViewportSetFieldOriginal(viewport, field); return d3drmViewportSetFieldOriginal(viewport, field);
} }
const SIZE_T max_frame_numbers = 60;
SIZE_T current_frame = 0;
DWORD frame_deltas[max_frame_numbers];
DWORD last_time = 0;
typedef HRESULT (WINAPI *d3drmDeviceUpdateFunction)(LPDIRECT3DRMDEVICE device);
d3drmDeviceUpdateFunction d3drmDeviceUpdateOriginal = NULL;
HRESULT WINAPI InterceptD3DRMDeviceUpdate(LPDIRECT3DRMDEVICE device)
{
DWORD now = timeGetTime();
if (last_time != 0) {
DWORD diff = now - last_time;
frame_deltas[current_frame%max_frame_numbers] = diff;
current_frame++;
if (current_frame >= max_frame_numbers) {
double avg_delta = 0;
for (size_t i=0; i<max_frame_numbers; i++) {
avg_delta += frame_deltas[i];
}
avg_delta /= max_frame_numbers;
printf("Avg FPS: %f\n", 1000.0 / avg_delta);
}
}
last_time = now;
return d3drmDeviceUpdateOriginal(device);
}
typedef HRESULT (WINAPI *d3drmCreateViewportFunction)(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport); typedef HRESULT (WINAPI *d3drmCreateViewportFunction)(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport);
d3drmCreateViewportFunction d3drmCreateViewportOriginal = NULL; d3drmCreateViewportFunction d3drmCreateViewportOriginal = NULL;
HRESULT WINAPI InterceptD3DRMCreateViewport(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport) HRESULT WINAPI InterceptD3DRMCreateViewport(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVICE device, LPDIRECT3DRMFRAME frame, DWORD x, DWORD y, DWORD w, DWORD h, LPDIRECT3DRMVIEWPORT *viewport)
@ -223,6 +246,10 @@ HRESULT WINAPI InterceptD3DRMCreateViewport(LPDIRECT3DRM d3drm, LPDIRECT3DRMDEVI
HRESULT res = d3drmCreateViewportOriginal(d3drm, device, frame, x, y, w, h, viewport); HRESULT res = d3drmCreateViewportOriginal(d3drm, device, frame, x, y, w, h, viewport);
if (res == DD_OK) { if (res == DD_OK) {
if (!d3drmDeviceUpdateOriginal) {
d3drmDeviceUpdateOriginal = (d3drmDeviceUpdateFunction)OverwriteVirtualTable(device, 14, (LPVOID)InterceptD3DRMDeviceUpdate);
}
if (!d3drmViewportSetFieldOriginal) { if (!d3drmViewportSetFieldOriginal) {
d3drmViewportSetFieldOriginal = (d3drmViewportSetFieldFunction)OverwriteVirtualTable(*viewport, 0x10, (LPVOID)InterceptD3DRMViewportSetField); d3drmViewportSetFieldOriginal = (d3drmViewportSetFieldFunction)OverwriteVirtualTable(*viewport, 0x10, (LPVOID)InterceptD3DRMViewportSetField);
} }

View file

@ -135,3 +135,46 @@ BOOL OverwriteCall(LPVOID destination, LPVOID localCall)
return WriteMemory(destination, callInst, 5); return WriteMemory(destination, callInst, 5);
} }
LPVOID SearchPattern(LPVOID imageBase, LPCVOID search, SIZE_T count)
{
LPVOID ret = NULL;
HANDLE process = GetCurrentProcess();
MEMORY_BASIC_INFORMATION mbi = {0};
// Loop through memory pages
UINT_PTR addr = (UINT_PTR)imageBase;
while (VirtualQueryEx(process, (LPVOID)addr, &mbi, sizeof(mbi)) && mbi.AllocationBase == imageBase) {
if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS) {
DWORD oldProtec;
// Try to gain access to this memory page
if (VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &oldProtec)) {
// Loop through every byte to find the pattern
SIZE_T maxOffset = mbi.RegionSize - count;
for (SIZE_T i=0; i<maxOffset; i++) {
LPVOID offset = (LPVOID)((UINT_PTR)(mbi.BaseAddress)+i);
if (!memcmp(offset, search, count)) {
// Found pattern, overwrite it
ret = offset;
break;
}
}
// Restore original permissions
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, oldProtec, &oldProtec);
}
}
if (ret) {
break;
}
addr += mbi.RegionSize;
}
return ret;
}

View file

@ -7,6 +7,8 @@ BOOL WriteMemory(LPVOID destination, LPVOID source, size_t length, LPVOID oldDat
BOOL OverwriteCall(LPVOID destination, LPVOID localCall); BOOL OverwriteCall(LPVOID destination, LPVOID localCall);
LPVOID SearchPattern(LPVOID imageBase, LPCVOID search, SIZE_T count);
SIZE_T SearchReplacePattern(LPVOID imageBase, LPCVOID search, LPCVOID replace, SIZE_T count, BOOL only_once = FALSE); SIZE_T SearchReplacePattern(LPVOID imageBase, LPCVOID search, LPCVOID replace, SIZE_T count, BOOL only_once = FALSE);
LPVOID OverwriteImport(LPVOID imageBase, LPCSTR overrideFunction, LPVOID override); LPVOID OverwriteImport(LPVOID imageBase, LPCSTR overrideFunction, LPVOID override);

View file

@ -43,6 +43,15 @@ DWORD WINAPI Patch()
OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA); OverwriteImport(exeBase, "FindWindowA", (LPVOID)InterceptFindWindowA);
} }
// Speed up startup
if (config.GetInt(_T("SpeedUpStartUp"))) {
// Replace "200" frame wait value with "1"
const char *speedup_pattern = "\xC8\x00\x00\x00\x00\x00\x00\x00";
const char *speedup_replace = "\x01\x00\x00\x00\x00\x00\x00\x00";
SearchReplacePattern(exeBase, speedup_pattern, speedup_replace, 8, TRUE);
}
// Debug mode // Debug mode
if (config.GetInt(_T("DebugToggle"))) { if (config.GetInt(_T("DebugToggle"))) {
// LEGO1 uses a string pointer to know if OGEL has been typed, if the string pointer sees 0x0 // LEGO1 uses a string pointer to know if OGEL has been typed, if the string pointer sees 0x0
@ -65,6 +74,20 @@ DWORD WINAPI Patch()
} }
} }
// Unhook turn speed
float turn_max_spd = config.GetFloat(_T("TurnMaxSpeed"), 20.0f);
if (config.GetInt(_T("UnhookTurnSpeed"))) {
LPVOID code_offset = SearchPattern(dllBase, "\x74\x26\xD9\x46\x34", 5);
if (code_offset) {
const char *new_code = "\xD9\x46\x24\xD8\x4C\x24\x14\xD8\x4E\x34\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90";
WriteMemory(code_offset, (LPVOID)new_code, 36);
turn_max_spd *= 2.0f;
} else {
printf("Failed to find code for unhooking turn speed\n");
}
}
// Patch navigation // Patch navigation
{ {
const int nav_block_sz = 0x30; const int nav_block_sz = 0x30;
@ -78,7 +101,7 @@ DWORD WINAPI Patch()
float movement_max_spd = config.GetFloat(_T("MovementMaxSpeed"), 40.0f); float movement_max_spd = config.GetFloat(_T("MovementMaxSpeed"), 40.0f);
memcpy(nav_block_dst+0x8, &movement_max_spd, sizeof(movement_max_spd)); memcpy(nav_block_dst+0x8, &movement_max_spd, sizeof(movement_max_spd));
float turn_max_spd = config.GetFloat(_T("TurnMaxSpeed"), 20.0f); // Value retrieved above
memcpy(nav_block_dst+0xC, &turn_max_spd, sizeof(turn_max_spd)); memcpy(nav_block_dst+0xC, &turn_max_spd, sizeof(turn_max_spd));
float movement_max_accel = config.GetFloat(_T("MovementMaxAcceleration"), 15.0f); float movement_max_accel = config.GetFloat(_T("MovementMaxAcceleration"), 15.0f);
@ -133,6 +156,20 @@ DWORD WINAPI Patch()
memcpy(fov_replace, &fov, sizeof(fov)); // Store back into bytes memcpy(fov_replace, &fov, sizeof(fov)); // Store back into bytes
SearchReplacePattern(dllBase, fov_pattern, fov_replace, 12); SearchReplacePattern(dllBase, fov_pattern, fov_replace, 12);
// FPS Cap
std::string fps_behavior = config.GetString(_T("FPSLimit"));
if (fps_behavior != "Default") {
UINT32 frame_delta;
if (fps_behavior == "Limited") {
frame_delta = 1000.0f / config.GetFloat(_T("CustomFPS"));
} else {
frame_delta = 0;
}
WriteMemory((char*)exeBase+0x10B4, &frame_delta, sizeof(UINT32));
}
// Window size hack // Window size hack
/*SearchReplacePattern(exeBase, /*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", "\x80\x02\x00\x00\xE0\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x80\x02\x00\x00\xE0\x01\x00\x00",

View file

@ -21,6 +21,11 @@ PatchGrid::PatchGrid()
"This patch allows infinite instances of LEGO Island to run."), "This patch allows infinite instances of LEGO Island to run."),
AddBoolItem(sectionGeneral, _T("Allow Multiple Instances"), false)); AddBoolItem(sectionGeneral, _T("Allow Multiple Instances"), false));
AddPatch("SpeedUpStartUp",
_T("By default, LEGO Island waits 200 frames to ensure everything is initialized before starting. "
"That interval can be skipped without consequence in many cases."),
AddBoolItem(sectionGeneral, _T("Speed Up Startup"), false));
AddPatch("StayActiveWhenDefocused", AddPatch("StayActiveWhenDefocused",
_T("By default, LEGO Island pauses when it's not the active window. " _T("By default, LEGO Island pauses when it's not the active window. "
"This patch prevents that behavior."), "This patch prevents that behavior."),

View file

@ -57,7 +57,8 @@ CRebuilderWindow::CRebuilderWindow()
// Create property grid // Create property grid
m_cPatchGrid.Create(AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW), _T("Patch Grid"), WS_CHILD | WS_VISIBLE, CRect(), &m_cTabCtrl, ID_PATCHGRID); m_cPatchGrid.Create(AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW), _T("Patch Grid"), WS_CHILD | WS_VISIBLE, CRect(), &m_cTabCtrl, ID_PATCHGRID);
m_cMusicTable.Create(_T("Coming back soon"), WS_CHILD | SS_CENTER, CRect(), &m_cTabCtrl); m_cMusicTable.Create(_T("Coming back soon. If you need music replacement, download the old .NET version here."),
WS_CHILD | SS_CENTER, CRect(), &m_cTabCtrl);
// Create run button // Create run button
m_cRunBtn.Create(GetResourceString(IDS_RUN), WS_CHILD | WS_VISIBLE, CRect(), this, ID_RUN); m_cRunBtn.Create(GetResourceString(IDS_RUN), WS_CHILD | WS_VISIBLE, CRect(), this, ID_RUN);