diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 55a1eb50..3e98bafd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,8 +32,7 @@ jobs: C:\msys64\usr\bin\wget.exe https://archive.org/download/idx5sdk/idx5sdk.exe 7z x .\idx5sdk.exe 7z x .\DX5SDK.EXE - cd cdrom - + - name: Cache DX5 SDK if: steps.cache-dx5.outputs.cache-hit != 'true' id: save-dx5 @@ -41,19 +40,28 @@ jobs: with: path: dx5sdk key: dx5sdk - + - name: Setup DX5 SDK run: | cd dx5sdk cd cdrom .\SETUP.EXE /s - + - name: Build shell: cmd run: | call .\msvc420\bin\VCVARS32.BAT x86 mkdir Release .\msvc420\bin\NMAKE.EXE /f isle.mak CFG="ISLE - Win32 Release" + + - name: Summarize Accuracy + shell: cmd + run: | + C:\msys64\usr\bin\wget.exe https://legoisland.org/download/ISLE.EXE + C:\msys64\usr\bin\wget.exe https://legoisland.org/download/LEGO1.DLL + pip install capstone + python3 tools/reccomp/reccomp.py ISLE.EXE Release/ISLE.EXE Release/ISLE.PDB ISLE + python3 tools/reccomp/reccomp.py LEGO1.DLL Release/LEGO1.DLL Release/LEGO1.PDB LEGO1 - name: Upload Artifact uses: actions/upload-artifact@master diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..8a05d04f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing + +## Learning Decompilation + +Generally, decompilation is a fairly advanced skill. If you aren't already familiar with it, it will likely take you months, or even years, to learn the skills necessary to do it (depending on your current proficiency with C/C++ and x86 assembly). If you're still interested, [part 1 of the decompilation vlog](https://www.youtube.com/watch?v=MToTEqoVv3I) covers the overall process and should give you a starting point that you can dive in from. + +## Ghidra Server + +For documenting the original binaries and generating pseudocode that we decompile with, we primarily use [Ghidra](https://ghidra-sre.org/) (it's free and open source). To help with collaboration, we have a shared Ghidra repository with all of our current work. It is available to the public but read-only; to contribute to it yourself, you'll need approval from a current maintainer. + +To access the Ghidra repository, use the following details: + +- Address: `server.mattkc.com` +- Port: `13100` + +## Code Style + +In general, we're not exhaustively strict about coding style, but there are some preferable guidelines to follow: + +- Indent: 2 spaces +- `PascalCase` for classes and function names. +- `m_camelCase` for member variables. +- `g_camelCase` for global variables. + +## Kinds of Contributions + +This repository has only one goal: accuracy to the original executables. As such, we are not likely to accept pull requests that attempt to modernize the code, or improve compatibility in a newer compiler that ends up reducing compatibility in MSVC 4.20. Essentially, accuracy is king, everything else is secondary. For modernizations and enhancements, it's recommended to create a fork downstream from this one instead. + +## Questions? + +For any further questions, feel free to ask in either the [Matrix chatroom](https://matrix.to/#/#isledecomp:matrix.org) or on the [forum](https://forum.mattkc.com/viewforum.php?f=1). diff --git a/ISLE/define.cpp b/ISLE/define.cpp index 0e38f2c8..a5122188 100644 --- a/ISLE/define.cpp +++ b/ISLE/define.cpp @@ -1,17 +1,43 @@ #include "define.h" +// 0x410030 Isle *g_isle = 0; + +// 0x410034 +unsigned char g_mousedown = 0; + +// 0x410038 +unsigned char g_mousemoved = 0; + +// 0x41003c int g_closed = 0; -const char *WINDOW_TITLE = "LEGO\xAE"; +// 0x410040 +RECT g_windowRect = {0, 0, 640, 480}; -unsigned char g_mousedown = 0; -unsigned char g_mousemoved = 0; +// 0x410050 int g_rmDisabled = 0; + +// 0x410054 int g_waitingForTargetDepth = 1; + +// 0x410058 int g_targetWidth = 640; + +// 0x41005c int g_targetHeight = 480; + +// 0x410060 unsigned int g_targetDepth = 16; + +// 0x410064 int g_reqEnableRMDevice = 0; + +// 0x4101bc int g_startupDelay = 200; + +// 0x4101c0 long g_lastFrameTime = 0; + +// 0x4101dc +const char *WINDOW_TITLE = "LEGO\xAE"; diff --git a/ISLE/define.h b/ISLE/define.h index c7d91fb9..36f69993 100644 --- a/ISLE/define.h +++ b/ISLE/define.h @@ -1,6 +1,8 @@ #ifndef DEFINE_H #define DEFINE_H +#include + class Isle; extern Isle *g_isle; @@ -9,6 +11,7 @@ extern int g_closed; extern const char *WINDOW_TITLE; extern unsigned char g_mousedown; extern unsigned char g_mousemoved; +extern RECT g_windowRect; extern int g_rmDisabled; extern int g_waitingForTargetDepth; extern int g_targetWidth; diff --git a/ISLE/isle.cpp b/ISLE/isle.cpp index 96479e93..3517cb78 100644 --- a/ISLE/isle.cpp +++ b/ISLE/isle.cpp @@ -1,14 +1,18 @@ #include "isle.h" #include "define.h" +#include "legoanimationmanager.h" +#include "legobuildingmanager.h" +#include "legomodelpresenter.h" #include "legoomni.h" +#include "legopartpresenter.h" +#include "legoworldpresenter.h" #include "mxdirectdraw.h" #include "mxdsaction.h" #include "mxomni.h" #include "res/resource.h" -RECT windowRect = {0, 0, 640, 480}; - +// OFFSET: ISLE 0x401000 Isle::Isle() { m_hdPath = NULL; @@ -51,10 +55,11 @@ Isle::Isle() LegoOmni::CreateInstance(); } +// OFFSET: ISLE 0x4011a0 Isle::~Isle() { if (LegoOmni::GetInstance()) { - close(); + Close(); MxOmni::DestroyInstance(); } @@ -75,7 +80,8 @@ Isle::~Isle() } } -void Isle::close() +// OFFSET: ISLE 0x401260 +void Isle::Close() { MxDSAction ds; @@ -109,7 +115,8 @@ void Isle::close() } } -BOOL readReg(LPCSTR name, LPSTR outValue, DWORD outSize) +// OFFSET: ISLE 0x402740 +BOOL ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize) { HKEY hKey; DWORD valueType; @@ -127,11 +134,12 @@ BOOL readReg(LPCSTR name, LPSTR outValue, DWORD outSize) return out; } -int readRegBool(LPCSTR name, BOOL *out) +// OFFSET: ISLE 0x4027b0 +int ReadRegBool(LPCSTR name, BOOL *out) { char buffer[256]; - BOOL read = readReg(name, buffer, 0x100); + BOOL read = ReadReg(name, buffer, sizeof(buffer)); if (read) { if (strcmp("YES", buffer) == 0) { *out = TRUE; @@ -146,11 +154,12 @@ int readRegBool(LPCSTR name, BOOL *out) return FALSE; } -int readRegInt(LPCSTR name, int *out) +// OFFSET: ISLE 0x402880 +int ReadRegInt(LPCSTR name, int *out) { char buffer[256]; - if (readReg(name, buffer, 0x100)) { + if (ReadReg(name, buffer, sizeof(buffer))) { *out = atoi(buffer); return TRUE; } @@ -158,13 +167,12 @@ int readRegInt(LPCSTR name, int *out) return FALSE; } -void Isle::loadConfig() +// OFFSET: ISLE 0x4028d0 +void Isle::LoadConfig() { - #define BUFFER_SIZE 1024 + char buffer[1024]; - char buffer[BUFFER_SIZE]; - - if (!readReg("diskpath", buffer, BUFFER_SIZE)) { + if (!ReadReg("diskpath", buffer, sizeof(buffer))) { strcpy(buffer, MxOmni::GetHD()); } @@ -172,7 +180,7 @@ void Isle::loadConfig() strcpy(m_hdPath, buffer); MxOmni::SetHD(m_hdPath); - if (!readReg("cdpath", buffer, BUFFER_SIZE)) { + if (!ReadReg("cdpath", buffer, sizeof(buffer))) { strcpy(buffer, MxOmni::GetCD()); } @@ -180,22 +188,22 @@ void Isle::loadConfig() strcpy(m_cdPath, buffer); MxOmni::SetCD(m_cdPath); - readRegBool("Flip Surfaces", &m_flipSurfaces); - readRegBool("Full Screen", &m_fullScreen); - readRegBool("Wide View Angle", &m_wideViewAngle); - readRegBool("3DSound", &m_use3dSound); - readRegBool("Music", &m_useMusic); - readRegBool("UseJoystick", &m_useJoystick); - readRegInt("JoystickIndex", &m_joystickIndex); - readRegBool("Draw Cursor", &m_drawCursor); + ReadRegBool("Flip Surfaces", &m_flipSurfaces); + ReadRegBool("Full Screen", &m_fullScreen); + ReadRegBool("Wide View Angle", &m_wideViewAngle); + ReadRegBool("3DSound", &m_use3dSound); + ReadRegBool("Music", &m_useMusic); + ReadRegBool("UseJoystick", &m_useJoystick); + ReadRegInt("JoystickIndex", &m_joystickIndex); + ReadRegBool("Draw Cursor", &m_drawCursor); int backBuffersInVRAM; - if (readRegBool("Back Buffers in Video RAM",&backBuffersInVRAM)) { + if (ReadRegBool("Back Buffers in Video RAM",&backBuffersInVRAM)) { m_backBuffersInVram = !backBuffersInVRAM; } int bitDepth; - if (readRegInt("Display Bit Depth", &bitDepth)) { + if (ReadRegInt("Display Bit Depth", &bitDepth)) { if (bitDepth == 8) { m_using8bit = TRUE; } else if (bitDepth == 16) { @@ -203,28 +211,29 @@ void Isle::loadConfig() } } - if (!readReg("Island Quality", buffer, BUFFER_SIZE)) { + if (!ReadReg("Island Quality", buffer, sizeof(buffer))) { strcpy(buffer, "1"); } m_islandQuality = atoi(buffer); - if (!readReg("Island Texture", buffer, BUFFER_SIZE)) { + if (!ReadReg("Island Texture", buffer, sizeof(buffer))) { strcpy(buffer, "1"); } m_islandTexture = atoi(buffer); - if (readReg("3D Device ID", buffer, BUFFER_SIZE)) { + if (ReadReg("3D Device ID", buffer, sizeof(buffer))) { m_deviceId = new char[strlen(buffer) + 1]; strcpy(m_deviceId, buffer); } - if (readReg("savepath", buffer, BUFFER_SIZE)) { + if (ReadReg("savepath", buffer, sizeof(buffer))) { m_savePath = new char[strlen(buffer) + 1]; strcpy(m_savePath, buffer); } } -void Isle::setupVideoFlags(BOOL fullScreen, BOOL flipSurfaces, BOOL backBuffers, +// OFFSET: ISLE 0x401560 +void Isle::SetupVideoFlags(BOOL fullScreen, BOOL flipSurfaces, BOOL backBuffers, BOOL using8bit, BOOL m_using16bit, BOOL param_6, BOOL param_7, BOOL wideViewAngle, char *deviceId) { @@ -244,10 +253,11 @@ void Isle::setupVideoFlags(BOOL fullScreen, BOOL flipSurfaces, BOOL backBuffers, } } -BOOL Isle::setupLegoOmni() +// OFFSET: ISLE 0x4013b0 +BOOL Isle::SetupLegoOmni() { char mediaPath[256]; - GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, 256); + GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, sizeof(mediaPath)); if (Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__ *) m_windowHandle, m_videoParam, MxOmniCreateFlags())) != FAILURE) { VariableTable()->SetVariable("ACTOR_01", ""); @@ -258,7 +268,8 @@ BOOL Isle::setupLegoOmni() return FALSE; } -void Isle::setupCursor(WPARAM wParam) +// OFFSET: ISLE 0x402e80 +void Isle::SetupCursor(WPARAM wParam) { switch (wParam) { case 0: @@ -278,6 +289,7 @@ void Isle::setupCursor(WPARAM wParam) SetCursor(m_cursorCurrent); } +// OFFSET: ISLE 0x401d20 LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (!g_isle) { @@ -292,9 +304,9 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_ACTIVATEAPP: if (g_isle) { if ((wParam != 0) && (g_isle->m_fullScreen)) { - MoveWindow(hWnd, windowRect.left, windowRect.top, - (windowRect.right - windowRect.left) + 1, - (windowRect.bottom - windowRect.top) + 1, TRUE); + MoveWindow(hWnd, g_windowRect.left, g_windowRect.top, + (g_windowRect.right - g_windowRect.left) + 1, + (g_windowRect.bottom - g_windowRect.top) + 1, TRUE); } g_isle->m_windowActive = wParam; } @@ -313,10 +325,10 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { MINMAXINFO *mmi = (MINMAXINFO *) lParam; - mmi->ptMaxTrackSize.x = (windowRect.right - windowRect.left) + 1; - mmi->ptMaxTrackSize.y = (windowRect.bottom - windowRect.top) + 1; - mmi->ptMinTrackSize.x = (windowRect.right - windowRect.left) + 1; - mmi->ptMinTrackSize.y = (windowRect.bottom - windowRect.top) + 1; + mmi->ptMaxTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1; + mmi->ptMaxTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1; + mmi->ptMinTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1; + mmi->ptMinTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1; return 0; } @@ -339,13 +351,13 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } return DefWindowProcA(hWnd,WM_SYSCOMMAND,wParam,lParam); case WM_EXITMENULOOP: - return DefWindowProcA(hWnd,WM_EXITMENULOOP,wParam,lParam); + return DefWindowProcA(hWnd, WM_EXITMENULOOP, wParam, lParam); case WM_MOVING: if (g_isle && g_isle->m_fullScreen) { GetWindowRect(hWnd, (LPRECT) lParam); return 0; } - return DefWindowProcA(hWnd,WM_MOVING,wParam,lParam); + return DefWindowProcA(hWnd, WM_MOVING, wParam, lParam); case WM_NCPAINT: if (g_isle && g_isle->m_fullScreen) { return 0; @@ -387,8 +399,10 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) switch (uMsg) { case WM_KEYDOWN: - if (lParam & 0x40000000) { - return DefWindowProcA(hWnd,WM_KEYDOWN,wParam,lParam); + // While this probably should be (HIWORD(lParam) & KF_REPEAT), this seems + // to be what the assembly is actually doing + if (lParam & (KF_REPEAT << 16)) { + return DefWindowProcA(hWnd, WM_KEYDOWN, wParam, lParam); } keyCode = wParam; type = KEYDOWN; @@ -419,7 +433,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) break; case 0x5400: if (g_isle) { - g_isle->setupCursor(wParam); + g_isle->SetupCursor(wParam); return 0; } } @@ -447,14 +461,15 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return DefWindowProcA(hWnd,uMsg,wParam,lParam); } -MxResult Isle::setupWindow(HINSTANCE hInstance) +// OFFSET: ISLE 0x4023e0 +MxResult Isle::SetupWindow(HINSTANCE hInstance) { WNDCLASSA wndclass; ZeroMemory(&wndclass, sizeof(WNDCLASSA)); - loadConfig(); + LoadConfig(); - setupVideoFlags(m_fullScreen, m_flipSurfaces, m_backBuffersInVram, m_using8bit, + SetupVideoFlags(m_fullScreen, m_flipSurfaces, m_backBuffersInVram, m_using8bit, m_using16bit, m_unk24, FALSE, m_wideViewAngle, m_deviceId); MxOmni::SetSound3D(m_use3dSound); @@ -486,21 +501,21 @@ MxResult Isle::setupWindow(HINSTANCE hInstance) int x, y, width, height; if (!m_fullScreen) { - AdjustWindowRectEx(&windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW); + AdjustWindowRectEx(&g_windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW); - height = windowRect.bottom - windowRect.top; - width = windowRect.right - windowRect.left; + height = g_windowRect.bottom - g_windowRect.top; + width = g_windowRect.right - g_windowRect.left; y = CW_USEDEFAULT; x = CW_USEDEFAULT; dwStyle = WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; } else { - AdjustWindowRectEx(&windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW); - height = windowRect.bottom - windowRect.top; - width = windowRect.right - windowRect.left; + AdjustWindowRectEx(&g_windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW); + height = g_windowRect.bottom - g_windowRect.top; + width = g_windowRect.right - g_windowRect.left; dwStyle = WS_CAPTION | WS_SYSMENU; - x = windowRect.left; - y = windowRect.top; + x = g_windowRect.left; + y = g_windowRect.top; } m_windowHandle = CreateWindowExA(WS_EX_APPWINDOW, WNDCLASS_NAME, WINDOW_TITLE, dwStyle, @@ -510,12 +525,12 @@ MxResult Isle::setupWindow(HINSTANCE hInstance) } if (m_fullScreen) { - MoveWindow(m_windowHandle, windowRect.left, windowRect.top, (windowRect.right - windowRect.left) + 1, (windowRect.bottom - windowRect.top) + 1, TRUE); + MoveWindow(m_windowHandle, g_windowRect.left, g_windowRect.top, (g_windowRect.right - g_windowRect.left) + 1, (g_windowRect.bottom - g_windowRect.top) + 1, TRUE); } ShowWindow(m_windowHandle, SW_SHOWNORMAL); UpdateWindow(m_windowHandle); - if (!setupLegoOmni()) { + if (!SetupLegoOmni()) { return FAILURE; } @@ -546,7 +561,7 @@ MxResult Isle::setupWindow(HINSTANCE hInstance) } } if (m_fullScreen) { - MoveWindow(m_windowHandle, windowRect.left, windowRect.top, (windowRect.right - windowRect.left) + 1, (windowRect.bottom - windowRect.top) + 1, TRUE); + MoveWindow(m_windowHandle, g_windowRect.left, g_windowRect.top, (g_windowRect.right - g_windowRect.left) + 1, (g_windowRect.bottom - g_windowRect.top) + 1, TRUE); } ShowWindow(m_windowHandle, SW_SHOWNORMAL); UpdateWindow(m_windowHandle); @@ -554,7 +569,8 @@ MxResult Isle::setupWindow(HINSTANCE hInstance) return SUCCESS; } -void Isle::tick(BOOL sleepIfNotNextFrame) +// OFFSET: ISLE 0x402c20 +void Isle::Tick(BOOL sleepIfNotNextFrame) { if (this->m_windowActive) { if (!Lego()) return; @@ -592,7 +608,7 @@ void Isle::tick(BOOL sleepIfNotNextFrame) return; } - ds.m_atomId = stream->atom; + ds.setAtomId(stream->atom); ds.m_unk24 = 0xFFFF; ds.m_unk1c = 0; VideoManager()->EnableFullScreenMovie(TRUE, TRUE); @@ -601,7 +617,7 @@ void Isle::tick(BOOL sleepIfNotNextFrame) return; } } else { - ds.m_atomId = stream->atom; + ds.setAtomId(stream->atom); ds.m_unk24 = 0xFFFF; ds.m_unk1c = 0; if (Start(&ds) != SUCCESS) { diff --git a/ISLE/isle.h b/ISLE/isle.h index e23fb8cb..d4f4e42e 100644 --- a/ISLE/isle.h +++ b/ISLE/isle.h @@ -1,7 +1,7 @@ #ifndef ISLE_H #define ISLE_H -#include +#include #include "mxresult.h" #include "mxvideoparam.h" @@ -12,21 +12,21 @@ class Isle Isle(); ~Isle(); - static void close(); + static void Close(); - MxResult setupWindow(HINSTANCE hInstance); + MxResult SetupWindow(HINSTANCE hInstance); - void tick(BOOL sleepIfNotNextFrame); + void Tick(BOOL sleepIfNotNextFrame); - BOOL setupLegoOmni(); - void loadConfig(); - void setupVideoFlags(BOOL fullScreen, BOOL flipSurfaces, BOOL backBuffers, + BOOL SetupLegoOmni(); + void LoadConfig(); + void SetupVideoFlags(BOOL fullScreen, BOOL flipSurfaces, BOOL backBuffers, BOOL using8bit, BOOL m_using16bit, BOOL param_6, BOOL param_7, BOOL wideViewAngle, char *deviceId); - void setupCursor(WPARAM wParam); + void SetupCursor(WPARAM wParam); -//private: +// private: // 0 LPSTR m_hdPath; diff --git a/ISLE/main.cpp b/ISLE/main.cpp index 9ef4466e..dd48e97e 100644 --- a/ISLE/main.cpp +++ b/ISLE/main.cpp @@ -1,11 +1,12 @@ -#include -#include +#include +#include #include "define.h" #include "isle.h" #include "legoomni.h" -BOOL findExistingInstance(void) +// OFFSET: ISLE 0x401ca0 +BOOL FindExistingInstance(void) { HWND hWnd = FindWindowA(WNDCLASS_NAME, WINDOW_TITLE); if (hWnd) { @@ -17,9 +18,10 @@ BOOL findExistingInstance(void) return 1; } -BOOL startDirectSound(void) +// OFFSET: ISLE 0x401ce0 +BOOL StartDirectSound(void) { - LPDIRECTSOUND lpDS = 0; + LPDIRECTSOUND lpDS = NULL; HRESULT ret = DirectSoundCreate(NULL, &lpDS, NULL); if (ret == DS_OK && lpDS != NULL) { lpDS->Release(); @@ -29,6 +31,7 @@ BOOL startDirectSound(void) return FALSE; } +// OFFSET: ISLE 0x401610 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { // Look for another instance, if we find one, bring it to the foreground instead @@ -49,7 +52,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // Throw error if sound unavailable if (!soundReady) { MessageBoxA(NULL, "\"LEGO\xAE Island\" is not detecting a DirectSound compatible sound card. Please quit all other applications and try again.", - "Lego Island Error",0); + "Lego Island Error", MB_OK); return 0; } @@ -57,8 +60,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_isle = new Isle(); // Create window - if (g_isle->setupWindow(hInstance) != SUCCESS) { - MessageBoxA(NULL, "\"LEGO\xAE Island\" failed to start. Please quit all other applications and try again.", "LEGO\xAE Island Error",0); + if (g_isle->SetupWindow(hInstance) != SUCCESS) { + MessageBoxA(NULL, "\"LEGO\xAE Island\" failed to start. Please quit all other applications and try again.", "LEGO\xAE Island Error", MB_OK); return 0; } @@ -76,12 +79,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine while (!g_closed) { while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (g_isle) { - g_isle->tick(1); + g_isle->Tick(1); } } if (g_isle) { - g_isle->tick(1); + g_isle->Tick(1); } if (g_closed) { @@ -121,7 +124,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } } else if (g_mousemoved) { if (g_isle) { - g_isle->tick(0); + g_isle->Tick(0); } goto LAB_00401bc7; } diff --git a/ISLE/res/isle.rc b/ISLE/res/isle.rc index 59bd314b..4534ea64 100644 Binary files a/ISLE/res/isle.rc and b/ISLE/res/isle.rc differ diff --git a/LEGO1/dllmain.cpp b/LEGO1/dllmain.cpp index 060bd70c..43654cb6 100644 --- a/LEGO1/dllmain.cpp +++ b/LEGO1/dllmain.cpp @@ -1,5 +1,6 @@ -#include +#include "legoinc.h" +// OFFSET: LEGO1 0x10091ee0 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { return TRUE; diff --git a/LEGO1/legoinc.h b/LEGO1/legoinc.h new file mode 100644 index 00000000..d1377c23 --- /dev/null +++ b/LEGO1/legoinc.h @@ -0,0 +1,10 @@ +#ifndef LEGOINC_H +#define LEGOINC_H + +// It is recommended to include this over directly because this way +// we can undef stuff that might cause issues with our code. + +#include +#undef GetClassName + +#endif // LEGOINC_H diff --git a/LEGO1/legoinputmanager.h b/LEGO1/legoinputmanager.h index 2f3f6412..714b4ce7 100644 --- a/LEGO1/legoinputmanager.h +++ b/LEGO1/legoinputmanager.h @@ -1,14 +1,16 @@ #ifndef LEGOINPUTMANAGER_H #define LEGOINPUTMANAGER_H +#include "mxcore.h" + __declspec(dllexport) enum NotificationId { - NONE = 0x0, - KEYDOWN = 0x7, - MOUSEUP = 0x8, - MOUSEDOWN = 0x9, - MOUSEMOVE = 0x10, - TIMER = 0xF + NONE = 0, + KEYDOWN = 7, + MOUSEUP = 8, + MOUSEDOWN = 9, + MOUSEMOVE = 10, + TIMER = 15 }; class LegoInputManager diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 6fc0ad68..062764f7 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -1,18 +1,115 @@ #include "legoomni.h" -LegoOmni *LegoOmni::m_instance = NULL; +// OFFSET: LEGO1 0x10058a00 +LegoOmni::LegoOmni() +{ + Init(); +} +// OFFSET: LEGO1 0x10058b50 +LegoOmni::~LegoOmni() +{ + Destroy(); +} + +// OFFSET: LEGO1 0x1005ad10 LegoOmni *LegoOmni::GetInstance() { - return m_instance; + return (LegoOmni *) m_instance; } +// OFFSET: LEGO1 0x10015700 LegoOmni *Lego() { - return LegoOmni::GetInstance(); + return (LegoOmni *) MxOmni::GetInstance(); } +// OFFSET: LEGO1 0x10015720 LegoVideoManager *VideoManager() { return LegoOmni::GetInstance()->GetVideoManager(); } + +// OFFSET: LEGO1 0x1005b5f0 +long LegoOmni::Notify(MxParam &p) +{ + // FIXME: Stub + return 0; +} + +// OFFSET: LEGO1 0x10058aa0 +const char *LegoOmni::GetClassName() const +{ + return "LegoOmni"; +} + +// OFFSET: LEGO1 0x10058ab0 +MxBool LegoOmni::IsClass(const char *name) const +{ + return strcmp("LegoOmni", name) == 0; +} + +// OFFSET: LEGO1 0x10058bd0 +void LegoOmni::Init() +{ + // FIXME: Stub +} + +// OFFSET: LEGO1 0x10058e70 +MxResult LegoOmni::Create(MxOmniCreateParam &p) +{ + // FIXME: Stub + return SUCCESS; +} + +void LegoOmni::Destroy() +{ + // FIXME: Stub +} + +void LegoOmni::vtable20() +{ + // FIXME: Stub +} + +void LegoOmni::vtable24(MxDSAction &ds) +{ + // FIXME: Stub +} + +MxBool LegoOmni::vtable28(MxDSAction &ds) +{ + // FIXME: Stub + return MX_TRUE; +} + +void LegoOmni::vtable2c() +{ + // FIXME: Stub +} + +void LegoOmni::vtable30() +{ + // FIXME: Stub +} + +void LegoOmni::vtable34() +{ + // FIXME: Stub +} + +void LegoOmni::vtable38() +{ + // FIXME: Stub +} + +void LegoOmni::vtable3c() +{ + // FIXME: Stub +} + +unsigned char LegoOmni::vtable40() +{ + // FIXME: Stub + return 0; +} diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index 514415fe..10f05665 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -1,36 +1,23 @@ #ifndef LEGOOMNI_H #define LEGOOMNI_H +#include "legoentity.h" +#include "legoinputmanager.h" +#include "legogamestate.h" +#include "legonavcontroller.h" +#include "legoroi.h" +#include "legovideomanager.h" +#include "mxatomid.h" #include "mxbackgroundaudiomanager.h" #include "mxdsaction.h" #include "mxdsfile.h" #include "mxdsobject.h" #include "mxomni.h" -#include "mxomnicreateparam.h" -#include "mxresult.h" -#include "mxstreamer.h" -#include "mxticklemanager.h" -#include "mxtimer.h" #include "mxtransitionmanager.h" -#include "legoanimationmanager.h" -#include "legobuildingmanager.h" -#include "legoentity.h" -#include "legogamestate.h" -#include "legoinputmanager.h" -#include "legomodelpresenter.h" -#include "legopartpresenter.h" -#include "legoroi.h" -#include "legoworldpresenter.h" -#include "legovideomanager.h" class LegoSoundManager; -class MxEventManager; -class MxMusicManager; -class MxNotificationManager; -class MxSoundManager; -// class LegoOmni : public MxOmni -class LegoOmni +class LegoOmni : public MxOmni { public: __declspec(dllexport) void CreateBackgroundAudio(); @@ -39,15 +26,15 @@ class LegoOmni __declspec(dllexport) static void CreateInstance(); __declspec(dllexport) static LegoOmni *GetInstance(); - virtual ~LegoOmni(); + LegoOmni(); + virtual ~LegoOmni(); // vtable+00 - virtual void vtable04(); - virtual void vtable08(); - virtual void vtable0c(); - virtual void vtable10(); - virtual void vtable14(); - virtual MxResult Create(const MxOmniCreateParam &p); - virtual void vtable1c(); + virtual long Notify(MxParam &p); // vtable+04 + virtual const char *GetClassName() const; // vtable+0c + virtual MxBool IsClass(const char *name) const; // vtable+10; + virtual void Init(); // vtable+14 + virtual MxResult Create(MxOmniCreateParam &p); // vtable+18 + virtual void Destroy(); // vtable+1c virtual void vtable20(); virtual void vtable24(MxDSAction &ds); virtual MxBool vtable28(MxDSAction &ds); @@ -58,40 +45,20 @@ class LegoOmni virtual void vtable3c(); virtual unsigned char vtable40(); - LegoVideoManager *GetVideoManager() { return m_videoMgr; } + LegoVideoManager *GetVideoManager() { return (LegoVideoManager *) m_videoManager; } LegoInputManager *GetInputManager() { return m_inputMgr; } private: - int m_unk04; - int m_unk08; - int m_unk0c; - int m_unk10; - int m_unk14; - int m_unk18; - int m_unk1c; - int m_unk20; - int m_unk24; - int m_unk28; - LegoVideoManager *m_videoMgr; - int m_unk30; - int m_unk34; - int m_unk38; - int m_unk3c; - int m_unk40; - int m_unk44; - int m_unk48; - int m_unk4c; - int m_unk50; - int m_unk54; - int m_unk58; - int m_unk5c; - int m_unk60; - int m_unk64; int m_unk68; int m_unk6c; - LegoInputManager *m_inputMgr; - - static LegoOmni *m_instance; + LegoInputManager *m_inputMgr; // 0x70 + char m_unk74[0x10]; + LegoNavController *m_navController; // 0x84 + char m_unk88[0x14]; + LegoGameState *m_gameState; // 0x9c + char m_unka0[0x94]; + MxBackgroundAudioManager *m_bkgAudioManager; // 0x134 + MxTransitionManager *m_transitionManager; // 0x138 }; diff --git a/LEGO1/mxatomid.h b/LEGO1/mxatomid.h index 3e3ce24b..537b097e 100644 --- a/LEGO1/mxatomid.h +++ b/LEGO1/mxatomid.h @@ -1,7 +1,9 @@ #ifndef MXATOMID_H #define MXATOMID_H -enum LookupMode; +enum LookupMode +{ +}; class MxAtomId { diff --git a/LEGO1/mxautolocker.cpp b/LEGO1/mxautolocker.cpp index 9020afaf..f5cf0853 100644 --- a/LEGO1/mxautolocker.cpp +++ b/LEGO1/mxautolocker.cpp @@ -1,5 +1,6 @@ #include "mxautolocker.h" +// OFFSET: LEGO1 0x100b8ed0 MxAutoLocker::MxAutoLocker(MxCriticalSection *critsect) { this->m_criticalSection = critsect; @@ -7,6 +8,7 @@ MxAutoLocker::MxAutoLocker(MxCriticalSection *critsect) this->m_criticalSection->Enter(); } +// OFFSET: LEGO1 0x100b8ef0 MxAutoLocker::~MxAutoLocker() { if (this->m_criticalSection != 0) diff --git a/LEGO1/mxcore.cpp b/LEGO1/mxcore.cpp index da8fe0b9..1187cdbe 100644 --- a/LEGO1/mxcore.cpp +++ b/LEGO1/mxcore.cpp @@ -2,33 +2,40 @@ #include +// 0x1010141c unsigned int g_mxcoreCount = 0; +// OFFSET: LEGO1 0x100ae1a0 MxCore::MxCore() { m_id = g_mxcoreCount; g_mxcoreCount++; } +// OFFSET: LEGO1 0x100ae1e0 MxCore::~MxCore() { } +// OFFSET: LEGO1 0x100ae1f0 long MxCore::Notify(MxParam &p) { return 0; } +// OFFSET: LEGO1 0x10001f70 long MxCore::Tickle() { return 0; } +// OFFSET: LEGO1 0x100144c0 const char *MxCore::GetClassName() const { return "MxCore"; } +// OFFSET: LEGO1 0x100140d0 MxBool MxCore::IsClass(const char *name) const { return strcmp(name, "MxCore") == 0; diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index b4038b06..64e916a1 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -9,11 +9,11 @@ class MxCore { public: __declspec(dllexport) MxCore(); - __declspec(dllexport) virtual ~MxCore(); - __declspec(dllexport) virtual long Notify(MxParam &p); - virtual long Tickle(); - virtual const char *GetClassName() const; - virtual MxBool IsClass(const char *name) const; + __declspec(dllexport) virtual ~MxCore(); // vtable+00 + __declspec(dllexport) virtual long Notify(MxParam &p); // vtable+04 + virtual long Tickle(); // vtable+08 + virtual const char *GetClassName() const; // vtable+0c + virtual MxBool IsClass(const char *name) const; // vtable+10 private: unsigned int m_id; diff --git a/LEGO1/mxcriticalsection.cpp b/LEGO1/mxcriticalsection.cpp index b94c021c..d0d11f15 100644 --- a/LEGO1/mxcriticalsection.cpp +++ b/LEGO1/mxcriticalsection.cpp @@ -2,8 +2,10 @@ #include +// 0x10101e78 int g_useMutex = 0; +// OFFSET: LEGO1 0x100b6d20 MxCriticalSection::MxCriticalSection() { HANDLE mutex; @@ -19,6 +21,7 @@ MxCriticalSection::MxCriticalSection() this->m_mutex = NULL; } +// OFFSET: LEGO1 0x100b6d60 MxCriticalSection::~MxCriticalSection() { if (this->m_mutex != NULL) @@ -30,11 +33,13 @@ MxCriticalSection::~MxCriticalSection() DeleteCriticalSection(&this->m_criticalSection); } +// OFFSET: LEGO1 0x100b6e00 void MxCriticalSection::SetDoMutex() { g_useMutex = 1; } +// OFFSET: LEGO1 0x100b6d80 void MxCriticalSection::Enter() { DWORD result; @@ -61,6 +66,7 @@ void MxCriticalSection::Enter() } } +// OFFSET: LEGO1 0x100b6de0 void MxCriticalSection::Leave() { if (this->m_mutex != NULL) @@ -70,4 +76,4 @@ void MxCriticalSection::Leave() } LeaveCriticalSection(&this->m_criticalSection); -} \ No newline at end of file +} diff --git a/LEGO1/mxcriticalsection.h b/LEGO1/mxcriticalsection.h index bd84babb..5b905741 100644 --- a/LEGO1/mxcriticalsection.h +++ b/LEGO1/mxcriticalsection.h @@ -1,7 +1,7 @@ #ifndef MXCRITICALSECTION_H #define MXCRITICALSECTION_H -#include +#include "legoinc.h" class MxCriticalSection { diff --git a/LEGO1/mxdsaction.h b/LEGO1/mxdsaction.h index d76f6930..aa5a7e4b 100644 --- a/LEGO1/mxdsaction.h +++ b/LEGO1/mxdsaction.h @@ -47,6 +47,11 @@ class MxDSAction int m_unk8c; int m_unk90; + void setAtomId(MxAtomId &atomId) + { + this->m_atomId = atomId; + } + }; #endif // MXDSACTION_H diff --git a/LEGO1/mxdsfile.cpp b/LEGO1/mxdsfile.cpp new file mode 100644 index 00000000..27d6668d --- /dev/null +++ b/LEGO1/mxdsfile.cpp @@ -0,0 +1,6 @@ +#include "mxdsfile.h" + +unsigned long MxDSFile::GetBufferSize() +{ + return this->m_buffersize; +} diff --git a/LEGO1/mxdsfile.h b/LEGO1/mxdsfile.h index d8f9440c..d28928dc 100644 --- a/LEGO1/mxdsfile.h +++ b/LEGO1/mxdsfile.h @@ -12,6 +12,9 @@ class MxDSFile __declspec(dllexport) virtual long Open(unsigned long); __declspec(dllexport) virtual long Read(unsigned char *,unsigned long); __declspec(dllexport) virtual long Seek(long,int); +private: + char m_unknown[0x70]; + unsigned long m_buffersize; }; #endif // MXDSFILE_H diff --git a/LEGO1/mxeventmanager.h b/LEGO1/mxeventmanager.h new file mode 100644 index 00000000..5d187256 --- /dev/null +++ b/LEGO1/mxeventmanager.h @@ -0,0 +1,9 @@ +#ifndef MXEVENTMANAGER_H +#define MXEVENTMANAGER_H + +class MxEventManager +{ + +}; + +#endif // MXEVENTMANAGER_H diff --git a/LEGO1/mxmusicmanager.h b/LEGO1/mxmusicmanager.h new file mode 100644 index 00000000..23134708 --- /dev/null +++ b/LEGO1/mxmusicmanager.h @@ -0,0 +1,9 @@ +#ifndef MXMUSICMANAGER_H +#define MXMUSICMANAGER_H + +class MxMusicManager +{ + +}; + +#endif // MXMUSICMANAGER_H diff --git a/LEGO1/mxnotificationmanager.h b/LEGO1/mxnotificationmanager.h new file mode 100644 index 00000000..afa378e1 --- /dev/null +++ b/LEGO1/mxnotificationmanager.h @@ -0,0 +1,9 @@ +#ifndef MXNOTIFICATIONMANAGER_H +#define MXNOTIFICATIONMANAGER_H + +class MxNotificationManager +{ + +}; + +#endif // MXNOTIFICATIONMANAGER_H diff --git a/LEGO1/mxobjectfactory.h b/LEGO1/mxobjectfactory.h new file mode 100644 index 00000000..ad341edd --- /dev/null +++ b/LEGO1/mxobjectfactory.h @@ -0,0 +1,9 @@ +#ifndef MXOBJECTFACTORY_H +#define MXOBJECTFACTORY_H + +class MxObjectFactory +{ + +}; + +#endif MXOBJECTFACTORY_H diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index fdf7e610..9e0786c3 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -1,27 +1,72 @@ -#include "mxomni.h" - -MxOmni *MxOmni::m_instance = NULL; - -MxOmni *MxOmni::GetInstance() -{ - return m_instance; -} - -MxResult MxOmni::Create(const MxOmniCreateParam &p) -{ - if (p.CreateFlags().CreateTimer()) - { - MxTimer *timer = new MxTimer(); - this->m_Timer = timer; - - if (timer == NULL) - return FAILURE; - } - - return SUCCESS; -} - +#include "mxomni.h" + +// 0x101015b0 +MxOmni* MxOmni::m_instance = NULL; + +// OFFSET: LEGO1 0x100aef10 +MxOmni::MxOmni() +{ + Init(); +} + +// OFFSET: LEGO1 0x100aeff0 +MxOmni::~MxOmni() +{ + Destroy(); +} + +void MxOmni::Init() +{ + m_windowHandle = NULL; + m_objectFactory = NULL; + m_variableTable = NULL; + m_tickleManager = NULL; + m_notificationManager = NULL; + m_videoManager = NULL; + m_soundManager = NULL; + m_musicManager = NULL; + m_eventManager = NULL; + m_timer = NULL; + m_streamer = NULL; + m_unk44 = NULL; + m_unk64 = NULL; +} + +// OFFSET: LEGO1 0x100b0680 +MxOmni *MxOmni::GetInstance() +{ + return m_instance; +} + +// OFFSET: LEGO1 0x100af0c0 +MxResult MxOmni::Create(MxOmniCreateParam &p) +{ + if (p.CreateFlags().CreateTimer()) + { + MxTimer *timer = new MxTimer(); + this->m_timer = timer; + + if (timer == NULL) + return FAILURE; + } + + return SUCCESS; +} + +// OFFSET: LEGO1 0x100afe90 +void MxOmni::Destroy() +{ + // FIXME: Stub +} + +// OFFSET: LEGO1 0x100b07f0 +long MxOmni::Notify(MxParam &p) +{ + // FIXME: Stub + return 0; +} + MxTimer* Timer() { return MxOmni::GetInstance()->GetTimer(); -} \ No newline at end of file +} diff --git a/LEGO1/mxomni.h b/LEGO1/mxomni.h index e241c065..8b794ebe 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -1,12 +1,22 @@ #ifndef MXOMNI_H #define MXOMNI_H -#include "mxresult.h" -#include "mxomnicreateparam.h" +#include "mxcriticalsection.h" +#include "mxeventmanager.h" +#include "mxmusicmanager.h" +#include "mxnotificationmanager.h" +#include "mxobjectfactory.h" #include "mxomnicreateflags.h" +#include "mxomnicreateparam.h" +#include "mxresult.h" +#include "mxsoundmanager.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" #include "mxtimer.h" +#include "mxvariabletable.h" +#include "mxvideomanager.h" -class MxOmni +class MxOmni : public MxCore { public: __declspec(dllexport) static void DestroyInstance(); @@ -18,15 +28,36 @@ class MxOmni __declspec(dllexport) static void SetHD(const char *s); __declspec(dllexport) static void SetSound3D(unsigned char); - MxResult MxOmni::Create(const MxOmniCreateParam &p); + virtual ~MxOmni(); - MxTimer* GetTimer() const { return this->m_Timer; } + virtual long Notify(MxParam &p); // vtable+04 + virtual void Init(); // vtable+14 + virtual MxResult Create(MxOmniCreateParam &p); // vtable+18 + virtual void Destroy(); // vtable+1c -private: - char padding[0x3c]; - MxTimer* m_Timer; + MxTimer* GetTimer() const { return this->m_timer; } - static MxOmni *m_instance; +protected: + static MxOmni* m_instance; + + MxString m_mediaPath; // 0x8 + HWND *m_windowHandle; // 0x18; + MxObjectFactory *m_objectFactory; // 0x1C + MxVariableTable* m_variableTable; //0x20 + MxTickleManager* m_tickleManager; //0x24 + MxNotificationManager* m_notificationManager; //0x28 + MxVideoManager *m_videoManager; //0x2C + MxSoundManager* m_soundManager; //0x30 + MxMusicManager* m_musicManager; //0x34 + MxEventManager* m_eventManager; //0x38 + MxTimer* m_timer; //0x3C + MxStreamer* m_streamer; //0x40 + + int m_unk44; // 0x44 + + MxCriticalSection m_criticalsection; // 0x48 + + int m_unk64; // 0x64 }; __declspec(dllexport) MxTimer * Timer(); diff --git a/LEGO1/mxomnicreateflags.cpp b/LEGO1/mxomnicreateflags.cpp index 46f735d7..ebed554c 100644 --- a/LEGO1/mxomnicreateflags.cpp +++ b/LEGO1/mxomnicreateflags.cpp @@ -1,5 +1,6 @@ #include "mxomnicreateflags.h" +// OFFSET: LEGO1 0x100b0a30 MxOmniCreateFlags::MxOmniCreateFlags() { this->CreateObjectFactory(MX_TRUE); diff --git a/LEGO1/mxomnicreateparam.cpp b/LEGO1/mxomnicreateparam.cpp index 96bd541d..65db5b8d 100644 --- a/LEGO1/mxomnicreateparam.cpp +++ b/LEGO1/mxomnicreateparam.cpp @@ -1,5 +1,6 @@ #include "mxomnicreateparam.h" +// OFFSET: LEGO1 0x100b0b00 MxOmniCreateParam::MxOmniCreateParam(const char *mediaPath, struct HWND__ *windowHandle, MxVideoParam &vparam, MxOmniCreateFlags flags) { this->m_mediaPath = mediaPath; diff --git a/LEGO1/mxomnicreateparam.h b/LEGO1/mxomnicreateparam.h index 3729e969..ad11cb55 100644 --- a/LEGO1/mxomnicreateparam.h +++ b/LEGO1/mxomnicreateparam.h @@ -1,8 +1,7 @@ #ifndef MXOMNICREATEPARAM_H #define MXOMNICREATEPARAM_H -#include - +#include "legoinc.h" #include "mxomnicreateflags.h" #include "mxomnicreateparambase.h" #include "mxstring.h" @@ -12,7 +11,6 @@ class MxOmniCreateParam : public MxOmniCreateParamBase { public: __declspec(dllexport) MxOmniCreateParam(const char *mediaPath, struct HWND__ *windowHandle, MxVideoParam &vparam, MxOmniCreateFlags flags); - // virtual void vtable00(); seems to be a destructor const MxOmniCreateFlags& CreateFlags() const { return this->m_createFlags; } diff --git a/LEGO1/mxomnicreateparambase.cpp b/LEGO1/mxomnicreateparambase.cpp index fe7c5836..0091785d 100644 --- a/LEGO1/mxomnicreateparambase.cpp +++ b/LEGO1/mxomnicreateparambase.cpp @@ -1,6 +1 @@ #include "mxomnicreateparam.h" - -MxOmniCreateParamBase::~MxOmniCreateParamBase() -{ - -} diff --git a/LEGO1/mxomnicreateparambase.h b/LEGO1/mxomnicreateparambase.h index fee0a488..605f4d30 100644 --- a/LEGO1/mxomnicreateparambase.h +++ b/LEGO1/mxomnicreateparambase.h @@ -5,8 +5,7 @@ class MxOmniCreateParamBase { public: - ~MxOmniCreateParamBase(); - virtual void vtable00(){} + virtual ~MxOmniCreateParamBase(){} }; diff --git a/LEGO1/mxsoundmanager.h b/LEGO1/mxsoundmanager.h new file mode 100644 index 00000000..7c0b0cf1 --- /dev/null +++ b/LEGO1/mxsoundmanager.h @@ -0,0 +1,9 @@ +#ifndef MXSOUNDMANAGER_H +#define MXSOUNDMANAGER_H + +class MxSoundManager +{ + +}; + +#endif // MXSOUNDMANAGER_H diff --git a/LEGO1/mxstreamcontroller.h b/LEGO1/mxstreamcontroller.h index d98699cd..dba24176 100644 --- a/LEGO1/mxstreamcontroller.h +++ b/LEGO1/mxstreamcontroller.h @@ -1,6 +1,8 @@ #ifndef MXSTREAMCONTROLLER_H #define MXSTREAMCONTROLLER_H +#include "mxatomid.h" + class MxStreamController { public: diff --git a/LEGO1/mxstring.cpp b/LEGO1/mxstring.cpp index 66e84c85..81188291 100644 --- a/LEGO1/mxstring.cpp +++ b/LEGO1/mxstring.cpp @@ -2,6 +2,7 @@ #include #include +// OFFSET: LEGO1 0x100ae200 MxString::MxString() { // Set string to one char in length and set that char to null terminator @@ -11,6 +12,7 @@ MxString::MxString() } // TODO: this *mostly* matches, again weird with the comparison +// OFFSET: LEGO1 0x100ae510 const MxString &MxString::operator=(const char *param) { if (this->m_data != param) @@ -24,6 +26,7 @@ const MxString &MxString::operator=(const char *param) return *this; } +// OFFSET: LEGO1 0x100ae420 MxString::~MxString() { free(this->m_data); diff --git a/LEGO1/mxticklemanager.h b/LEGO1/mxticklemanager.h index d39022f7..afcea455 100644 --- a/LEGO1/mxticklemanager.h +++ b/LEGO1/mxticklemanager.h @@ -1,6 +1,8 @@ #ifndef MXTICKLEMANAGER_H #define MXTICKLEMANAGER_H +#include "mxcore.h" + class MxTickleManager : public MxCore { public: diff --git a/LEGO1/mxtimer.cpp b/LEGO1/mxtimer.cpp index 245787aa..8be837d4 100644 --- a/LEGO1/mxtimer.cpp +++ b/LEGO1/mxtimer.cpp @@ -1,10 +1,14 @@ #include "mxtimer.h" -#include +#include "legoinc.h" +// 0x10101414 long MxTimer::s_LastTimeCalculated = 0; + +// 0x10101418 long MxTimer::s_LastTimeTimerStarted = 0; +// OFFSET: LEGO1 0x100ae060 MxTimer::MxTimer() { this->m_isRunning = MX_FALSE; @@ -12,12 +16,14 @@ MxTimer::MxTimer() this->m_startTime = MxTimer::s_LastTimeCalculated; } +// OFFSET: LEGO1 0x100ae160 void MxTimer::Start() { this->m_isRunning = MX_TRUE; MxTimer::s_LastTimeTimerStarted = timeGetTime(); } +// OFFSET: LEGO1 0x100ae180 void MxTimer::Stop() { long elapsed = this->GetRealTime(); @@ -27,6 +33,7 @@ void MxTimer::Stop() this->m_startTime = this->m_startTime + startTime - 5; } +// OFFSET: LEGO1 0x100ae140 long MxTimer::GetRealTime() { MxTimer::s_LastTimeCalculated = timeGetTime(); diff --git a/LEGO1/mxvideoparam.cpp b/LEGO1/mxvideoparam.cpp index 19dbad96..2a33736a 100644 --- a/LEGO1/mxvideoparam.cpp +++ b/LEGO1/mxvideoparam.cpp @@ -1,5 +1,9 @@ #include "mxvideoparam.h" +#include +#include + +// OFFSET: LEGO1 0x100bec70 MxVideoParam::MxVideoParam() { this->m_flags = MxVideoParamFlags(); @@ -13,6 +17,7 @@ MxVideoParam::MxVideoParam() this->m_deviceId = 0; } +// OFFSET: LEGO1 0x100becf0 MxVideoParam &MxVideoParam::operator=(const MxVideoParam &other) { m_flags = MxVideoParamFlags(); @@ -30,6 +35,7 @@ MxVideoParam &MxVideoParam::operator=(const MxVideoParam &other) return *this; } +// OFFSET: LEGO1 0x100bed70 void MxVideoParam::SetDeviceName(char *id) { if (this->m_deviceId != 0) @@ -48,6 +54,7 @@ void MxVideoParam::SetDeviceName(char *id) } } +// OFFSET: LEGO1 0x100bed50 MxVideoParam::~MxVideoParam() { if (this->m_deviceId != 0) diff --git a/LEGO1/mxvideoparam.h b/LEGO1/mxvideoparam.h index 8dcc2746..eedf3167 100644 --- a/LEGO1/mxvideoparam.h +++ b/LEGO1/mxvideoparam.h @@ -25,7 +25,7 @@ class MxVideoParam int m_right; int m_bottom; MxPalette *m_palette; - BOOL m_backBuffers; + int m_backBuffers; MxVideoParamFlags m_flags; int m_unk1c; char *m_deviceId; diff --git a/LEGO1/mxvideoparamflags.cpp b/LEGO1/mxvideoparamflags.cpp index 00429e30..97f01515 100644 --- a/LEGO1/mxvideoparamflags.cpp +++ b/LEGO1/mxvideoparamflags.cpp @@ -1,5 +1,6 @@ #include "mxvideoparamflags.h" +// OFFSET: LEGO1 0x100bec40 MxVideoParamFlags::MxVideoParamFlags() { // TODO: convert to EnableXXX function calls diff --git a/LEGO1/mxvideoparamflags.h b/LEGO1/mxvideoparamflags.h index 49a4ecc1..50c9a1c9 100644 --- a/LEGO1/mxvideoparamflags.h +++ b/LEGO1/mxvideoparamflags.h @@ -1,7 +1,7 @@ #ifndef MXVIDEOPARAMFLAGS_H #define MXVIDEOPARAMFLAGS_H -#include +#include "mxbool.h" class MxVideoParamFlags { @@ -24,22 +24,22 @@ class MxVideoParamFlags __declspec(dllexport) MxVideoParamFlags(); - inline void EnableFullScreen(BOOL e) + inline void EnableFullScreen(MxBool e) { m_flags1 = (m_flags1 ^ (e << 0)) & FULL_SCREEN ^ m_flags1; } - inline void EnableFlipSurfaces(BOOL e) + inline void EnableFlipSurfaces(MxBool e) { m_flags1 = (m_flags1 ^ (e << 1)) & FLIP_SURFACES ^ m_flags1; } - inline void EnableBackBuffers(BOOL e) + inline void EnableBackBuffers(MxBool e) { m_flags1 = (m_flags1 ^ ((!e) << 2)) & BACK_BUFFERS ^ m_flags1; } - inline void SetUnknown3(BOOL e) + inline void SetUnknown3(MxBool e) { m_flags1 = (m_flags1 ^ (e << 7)) & UNKNOWN3 ^ m_flags1; } @@ -59,17 +59,17 @@ class MxVideoParamFlags m_flags1 = ((e << 5) ^ m_flags1) & ENABLE_16BIT ^ m_flags1; } - inline void EnableWideViewAngle(BOOL e) + inline void EnableWideViewAngle(MxBool e) { m_flags1 = (m_flags1 ^ (e << 6)) & WIDE_VIEW_ANGLE ^ m_flags1; } - inline void EnableUnknown1(BOOL e) + inline void EnableUnknown1(MxBool e) { m_flags2 = (m_flags2 ^ ((!e) << 0)) & UNKNOWN1 ^ m_flags2; } - inline void EnableUnknown2(BOOL e) + inline void EnableUnknown2(MxBool e) { m_flags2 = (m_flags2 ^ (e << 1)) & UNKNOWN2 ^ m_flags2; } diff --git a/README.md b/README.md index 0abe7eb5..40c9dfbc 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,10 @@ Simply place the compiled `ISLE.EXE` into LEGO Island's install folder (usually Ideally, this decompilation should be paired with version 1.1. It may work on 1.0 too, however this is not guaranteed. +## Contributing + +If you're interested in helping/contributing to this project, check out the [CONTRIBUTING](https://github.com/isledecomp/isle/blob/master/CONTRIBUTING.md) page. + ## Additional Information ### Which version of LEGO Island do I have? diff --git a/isle.mak b/isle.mak index 404cc4e9..164b8f58 100644 --- a/isle.mak +++ b/isle.mak @@ -68,19 +68,20 @@ CLEAN : -@erase "$(INTDIR)\mxtimer.obj" -@erase "$(INTDIR)\mxvideoparam.obj" -@erase "$(INTDIR)\mxvideoparamflags.obj" + -@erase "$(INTDIR)\vc40.pdb" -@erase ".\Release\LEGO1.DLL" -@erase ".\Release\LEGO1.EXP" -@erase ".\Release\LEGO1.LIB" - -@erase ".\Release\LEGO1.MAP" + -@erase ".\Release\LEGO1.PDB" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP=cl.exe # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -CPP_PROJ=/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\ - /Fp"$(INTDIR)/LEGO1.pch" /YX /Fo"$(INTDIR)/" /c +# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\ + /Fp"$(INTDIR)/LEGO1.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c CPP_OBJS=.\LEGO1\Release/ CPP_SBRS=.\. @@ -117,13 +118,13 @@ BSC32_SBRS= \ LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /pdb:"Release/LEGO1.PDB" /map:"Release/LEGO1.MAP" /machine:I386 /out:"Release/LEGO1.DLL" /implib:"Release/LEGO1.LIB" -# SUBTRACT LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /pdb:"Release/LEGO1.PDB" /debug /machine:I386 /out:"Release/LEGO1.DLL" /implib:"Release/LEGO1.LIB" +# SUBTRACT LINK32 /pdb:none /map LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no\ - /pdb:"Release/LEGO1.PDB" /map:"Release/LEGO1.MAP" /machine:I386\ - /out:"Release/LEGO1.DLL" /implib:"Release/LEGO1.LIB" + /pdb:"Release/LEGO1.PDB" /debug /machine:I386 /out:"Release/LEGO1.DLL"\ + /implib:"Release/LEGO1.LIB" LINK32_OBJS= \ "$(INTDIR)\dllmain.obj" \ "$(INTDIR)\legonavcontroller.obj" \ @@ -181,7 +182,6 @@ CLEAN : -@erase "$(INTDIR)\vc40.pdb" -@erase "$(OUTDIR)\LEGO1.exp" -@erase "$(OUTDIR)\LEGO1.lib" - -@erase "$(OUTDIR)\LEGO1.map" -@erase "$(OUTDIR)\LEGO1.pdb" -@erase ".\Debug\LEGO1.DLL" -@erase ".\Debug\LEGO1.ILK" @@ -230,13 +230,13 @@ BSC32_SBRS= \ LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /out:"Debug/LEGO1.DLL" -# SUBTRACT LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/LEGO1.DLL" +# SUBTRACT LINK32 /pdb:none /map LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:yes\ - /pdb:"$(OUTDIR)/LEGO1.pdb" /map:"$(INTDIR)/LEGO1.map" /debug /machine:I386\ - /out:"Debug/LEGO1.DLL" /implib:"$(OUTDIR)/LEGO1.lib" + /pdb:"$(OUTDIR)/LEGO1.pdb" /debug /machine:I386 /out:"Debug/LEGO1.DLL"\ + /implib:"$(OUTDIR)/LEGO1.lib" LINK32_OBJS= \ "$(INTDIR)\dllmain.obj" \ "$(INTDIR)\legonavcontroller.obj" \ @@ -280,17 +280,18 @@ CLEAN : -@erase "$(INTDIR)\isle.obj" -@erase "$(INTDIR)\isle.res" -@erase "$(INTDIR)\main.obj" - -@erase "$(INTDIR)\mxomnicreateparambase.obj" + -@erase "$(INTDIR)\vc40.pdb" -@erase ".\Release\ISLE.EXE" + -@erase ".\Release\ISLE.PDB" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP=cl.exe # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /W3 /GX /O2 /I "LEGO1" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "LEGO1" /D "WIN32" /D "NDEBUG" /D\ - "_WINDOWS" /Fp"$(INTDIR)/ISLE.pch" /YX /Fo"$(INTDIR)/" /c +# ADD CPP /nologo /W3 /GX /Zi /O2 /I "LEGO1" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /Zi /O2 /I "LEGO1" /D "WIN32" /D "NDEBUG" /D\ + "_WINDOWS" /Fp"$(INTDIR)/ISLE.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c CPP_OBJS=.\ISLE\Release/ CPP_SBRS=.\. @@ -328,19 +329,18 @@ BSC32_SBRS= \ LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib lego1.lib dsound.lib /nologo /subsystem:windows /pdb:"Release/ISLE.PDB" /machine:I386 /out:"Release/ISLE.EXE" /LIBPATH:"ISLE/ext" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib lego1.lib dsound.lib /nologo /subsystem:windows /pdb:"Release/ISLE.PDB" /debug /machine:I386 /out:"Release/ISLE.EXE" /LIBPATH:"ISLE/ext" # SUBTRACT LINK32 /pdb:none LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ odbccp32.lib winmm.lib lego1.lib dsound.lib /nologo /subsystem:windows\ - /incremental:no /pdb:"Release/ISLE.PDB" /machine:I386 /out:"Release/ISLE.EXE"\ - /LIBPATH:"ISLE/ext" + /incremental:no /pdb:"Release/ISLE.PDB" /debug /machine:I386\ + /out:"Release/ISLE.EXE" /LIBPATH:"ISLE/ext" LINK32_OBJS= \ "$(INTDIR)\define.obj" \ "$(INTDIR)\isle.obj" \ "$(INTDIR)\isle.res" \ "$(INTDIR)\main.obj" \ - "$(INTDIR)\mxomnicreateparambase.obj" \ ".\Release\LEGO1.LIB" ".\Release\ISLE.EXE" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -370,7 +370,6 @@ CLEAN : -@erase "$(INTDIR)\isle.obj" -@erase "$(INTDIR)\isle.res" -@erase "$(INTDIR)\main.obj" - -@erase "$(INTDIR)\mxomnicreateparambase.obj" -@erase "$(INTDIR)\vc40.idb" -@erase "$(INTDIR)\vc40.pdb" -@erase ".\Debug\ISLE.EXE" @@ -434,7 +433,6 @@ LINK32_OBJS= \ "$(INTDIR)\isle.obj" \ "$(INTDIR)\isle.res" \ "$(INTDIR)\main.obj" \ - "$(INTDIR)\mxomnicreateparambase.obj" \ ".\LEGO1\Debug\LEGO1.lib" ".\Debug\ISLE.EXE" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -905,30 +903,6 @@ SOURCE=.\ISLE\res\isle.rc !ENDIF -# End Source File -################################################################################ -# Begin Source File - -SOURCE=.\LEGO1\mxomnicreateparambase.cpp -DEP_CPP_MXOMNIC=\ - ".\LEGO1\mxbool.h"\ - ".\LEGO1\mxcore.h"\ - ".\LEGO1\mxomnicreateflags.h"\ - ".\LEGO1\mxomnicreateparam.h"\ - ".\LEGO1\mxomnicreateparambase.h"\ - ".\LEGO1\mxpalette.h"\ - ".\LEGO1\mxrect32.h"\ - ".\LEGO1\mxstring.h"\ - ".\LEGO1\mxvariabletable.h"\ - ".\LEGO1\mxvideoparam.h"\ - ".\LEGO1\mxvideoparamflags.h"\ - - -"$(INTDIR)\mxomnicreateparambase.obj" : $(SOURCE) $(DEP_CPP_MXOMNIC)\ - "$(INTDIR)" - $(CPP) $(CPP_PROJ) $(SOURCE) - - # End Source File ################################################################################ # Begin Source File @@ -1185,18 +1159,6 @@ SOURCE=.\LEGO1\mxomnicreateparam.h ################################################################################ # Begin Source File -SOURCE=.\LEGO1\mxomnicreateparambase.h - -!IF "$(CFG)" == "ISLE - Win32 Release" - -!ELSEIF "$(CFG)" == "ISLE - Win32 Debug" - -!ENDIF - -# End Source File -################################################################################ -# Begin Source File - SOURCE=.\LEGO1\mxpalette.h !IF "$(CFG)" == "ISLE - Win32 Release" diff --git a/tools/reccomp/cvdump.exe b/tools/reccomp/cvdump.exe new file mode 100644 index 00000000..8c1eff6e Binary files /dev/null and b/tools/reccomp/cvdump.exe differ diff --git a/tools/reccomp/reccomp.py b/tools/reccomp/reccomp.py new file mode 100755 index 00000000..dd601e53 --- /dev/null +++ b/tools/reccomp/reccomp.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 + +from capstone import * +import difflib +import struct +import subprocess +import os +import sys + +def print_usage(): + print('Usage: %s [options] \n' % sys.argv[0]) + print('\t-v, --verbose \t\t\tPrint assembly diff for specific function (original file\'s offset)') + sys.exit(1) + +positional_args = [] +verbose = None +skip = False + +for i, arg in enumerate(sys.argv): + if skip: + skip = False + continue + + if arg.startswith('-'): + # A flag rather than a positional arg + flag = arg[1:] + + if flag == 'v' or flag == '-verbose': + verbose = int(sys.argv[i + 1], 16) + skip = True + else: + print('Unknown flag: %s' % arg) + print_usage() + else: + positional_args.append(arg) + +if len(positional_args) != 5: + print_usage() + +original = positional_args[1] +if not os.path.isfile(original): + print('Invalid input: Original binary does not exist') + sys.exit(1) + +recomp = positional_args[2] +if not os.path.isfile(recomp): + print('Invalid input: Recompiled binary does not exist') + sys.exit(1) + +syms = positional_args[3] +if not os.path.isfile(syms): + print('Invalid input: Symbols PDB does not exist') + sys.exit(1) + +source = positional_args[4] +if not os.path.isdir(source): + print('Invalid input: Source directory does not exist') + sys.exit(1) + +# Declare a class that can automatically convert virtual executable addresses +# to file addresses +class Bin: + def __init__(self, filename): + self.file = open(filename, 'rb') + + #HACK: Strictly, we should be parsing the header, but we know where + # everything is in these two files so we just jump straight there + + # Read ImageBase + self.file.seek(0xB4) + self.imagebase = struct.unpack('i', self.file.read(4))[0] + + # Read .text VirtualAddress + self.file.seek(0x184) + self.textvirt = struct.unpack('i', self.file.read(4))[0] + + # Read .text PointerToRawData + self.file.seek(0x18C) + self.textraw = struct.unpack('i', self.file.read(4))[0] + + def __del__(self): + if self.file: + self.file.close() + + def get_addr(self, virt): + return virt - self.imagebase - self.textvirt + self.textraw + + def read(self, offset, size): + self.file.seek(self.get_addr(offset)) + return self.file.read(size) + +line_dump = None + +origfile = Bin(original) +recompfile = Bin(recomp) + +class RecompiledInfo: + addr = None + size = None + name = None + +print() + +def get_recompiled_address(filename, line): + global line_dump, sym_dump + + def get_wine_path(fn): + return subprocess.check_output(['winepath', '-w', fn]).decode('utf-8').strip() + + # Load source lines from PDB + if not line_dump: + call = [os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'cvdump.exe'), '-l', '-s'] + + if os.name != 'nt': + # Run cvdump through wine and convert path to Windows-friendly wine path + call.insert(0, 'wine') + call.append(get_wine_path(syms)) + else: + call.append(syms) + + line_dump = subprocess.check_output(call).decode('utf-8').split('\r\n') + + # Find requested filename/line in PDB + if os.name != 'nt': + # Convert filename to Wine path + filename = get_wine_path(filename) + + #print('Looking for ' + filename + ' line ' + str(line)) + + addr = None + found = False + + for i, s in enumerate(line_dump): + try: + sourcepath = s.split()[0] + if os.path.isfile(sourcepath) and os.path.samefile(sourcepath, filename): + lines = line_dump[i + 2].split() + if line == int(lines[0]): + # Found address + addr = int(lines[1], 16) + found = True + break + except IndexError: + pass + + if found: + # Find size of function + for i, s in enumerate(line_dump): + if 'S_GPROC32' in s: + if int(s[26:34], 16) == addr: + obj = RecompiledInfo() + obj.addr = addr + recompfile.imagebase + recompfile.textvirt + obj.size = int(s[41:49], 16) + obj.name = s[77:] + + return obj + +md = Cs(CS_ARCH_X86, CS_MODE_32) + +def parse_asm(file, addr, size): + asm = [] + data = file.read(addr, size) + for i in md.disasm(data, 0): + if i.mnemonic == 'call': + # Filter out "calls" because the offsets we're not currently trying to + # match offsets. As long as there's a call in the right place, it's + # probably accurate. + asm.append(i.mnemonic) + else: + asm.append("%s %s" % (i.mnemonic, i.op_str)) + return asm + +function_count = 0 +total_accuracy = 0 + +for subdir, dirs, files in os.walk(source): + for file in files: + srcfilename = os.path.join(os.path.abspath(subdir), file) + srcfile = open(srcfilename, 'r') + line_no = 0 + + while True: + try: + line = srcfile.readline() + line_no += 1 + + if not line: + break + + if line.startswith('// OFFSET:'): + par = line[10:].strip().split() + module = par[0] + addr = int(par[1], 16) + + find_open_bracket = line + while '{' not in find_open_bracket: + find_open_bracket = srcfile.readline() + line_no += 1 + + recinfo = get_recompiled_address(srcfilename, line_no) + if not recinfo: + print('Failed to find recompiled address of ' + hex(addr)) + continue + + origasm = parse_asm(origfile, addr, recinfo.size) + recompasm = parse_asm(recompfile, recinfo.addr, recinfo.size) + + diff = difflib.SequenceMatcher(None, origasm, recompasm) + ratio = diff.ratio() + print('%s (%s / %s) is %.2f%% similar to the original' % (recinfo.name, hex(addr), hex(recinfo.addr), ratio * 100)) + + function_count += 1 + total_accuracy += ratio + + if verbose == addr: + udiff = difflib.unified_diff(origasm, recompasm) + for line in udiff: + print(line) + print() + print() + + except UnicodeDecodeError: + break + +if function_count > 0: + print('\nTotal accuracy %.2f%% across %i functions' % (total_accuracy / function_count * 100, function_count))