diff --git a/audit/history.jsonl b/audit/history.jsonl index 080d9401..e9700854 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -639,3 +639,4 @@ {"date": "2026-09-30", "unit": "EterLib/GrpScreen.cpp", "action": "port", "evidence": "verbatim; 2d draws -> UIRender commands, Show without the web-page rects; D3D8 shim gains TestCooperativeLevel/Reset/Present/GetVertexShader + ID3DXMesh; port.app_loop (3D line/bar draws, device not lost), port.login_flow (picking/projection)"} {"date": "2026-09-30", "unit": "EterLib/GrpDevice.cpp", "action": "port", "evidence": "verbatim except Create (recording device in place of Direct3DCreate8/detector/CreateDevice, EL3D_ConfirmDevice on its caps); RecordingDevice decodes declaration-only vertex shaders to stream-0 FVFs; GrpScreen Show uses the GrpDevice browser globals; port.app_loop (PT/PNT/PNT2 FVFs, max texture 4096), full ctest, live-client screenshot matches"} {"date": "2026-09-30", "unit": "EterLib/GrpDetector.cpp", "action": "port", "evidence": "verbatim; IDirect3D8 shim completed (adapter count/caps/format checks/CreateDevice) and implemented once as the host adapter behind Direct3DCreate8 (RecordingDevice.cpp), which CPythonGraphic::GetD3D also returns; GrpDevice::Create now verbatim but for the D3DX debug meshes; port.app_loop (800x600x32 HWVP D16 mode, ms_lpd3d, GetString), full ctest, live-client screenshot matches"} +{"date": "2026-09-30", "unit": "UserInterface/UserInterface.cpp", "action": "port", "evidence": "ApplicationSetErrorString/ApplicationStringTable_Initialize verbatim + port.app_loop; Main ADAPTED to PythonBoot; Win32 entry/launcher options N_A"} diff --git a/audit/port-map/UserInterface/UserInterface.cpp.json b/audit/port-map/UserInterface/UserInterface.cpp.json index e28e905a..e2295072 100644 --- a/audit/port-map/UserInterface/UserInterface.cpp.json +++ b/audit/port-map/UserInterface/UserInterface.cpp.json @@ -5,13 +5,28 @@ "contracts": [], "functions": { "ApplicationSetErrorString": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/UserInterface/UserInterface.cpp:ApplicationSetErrorString" + ], + "test": [ + "tests/port/port_app_loop_test.cpp (port.app_loop: ApplicationSetErrorString fills gs_szErrorString; ApplicationStringTable_GetStringz(IDS_APP_NAME))" + ] }, "CheckPythonLibraryFilenames": { - "status": "TODO" + "status": "N_A", + "note": "Win32 install check of lib\\\\*.pyc next to the exe. The embedded CPython 2.7 stdlib is installed by PythonHost::InstallStdLib, whose failure fails PythonBoot::Start." }, "ApplicationStringTable_Initialize": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/UserInterface/UserInterface.cpp:ApplicationStringTable_Initialize", + "src/platform/ScriptLib/PythonBoot.cpp:PythonBoot::Start" + ], + "test": [ + "tests/port/port_app_loop_test.cpp (port.app_loop: ApplicationSetErrorString fills gs_szErrorString; ApplicationStringTable_GetStringz(IDS_APP_NAME))" + ], + "note": "verbatim; PythonBoot::Start calls it before locale.cfg as WinMain does, with a NULL module handle (LoadString is the English STRINGTABLE switch)." }, "ApplicationStringTable_GetString": { "status": "ADAPTED", @@ -46,43 +61,65 @@ "test": "project/python_host_test.gd (godot --headless --path project --script python_host_test.gd) and the same check through MT_TEST_MODE=python in project/client_main.gd -> system.py stops at ImportError: No module named app, the same point as ctest port.python_launcher" }, "Main": { - "status": "TODO" + "status": "ADAPTED", + "impl": [ + "src/platform/ScriptLib/PythonBoot.cpp:PythonBoot::Start", + "src/platform/ScriptLib/PythonBoot.cpp:PythonBoot::RunMainScript", + "src/platform/UserInterface/UserInterface.cpp:PackSingletons" + ], + "note": "40250: Main seeds rand, opens the log, creates CLZO/CEterPackManager, PackInitialize(\"pack\"), locale, CPythonApplication, CPythonLauncher + exception sender, RunMainScript, then tears down. Port: the host owns the frame loop, so PythonBoot::Start does the setup (launcher, exception sender, singletons, CPythonApplication::Create pieces), PackSingletons/PackInitialize run from the host pack bootstrap, and RunMainScript runs system.py on a script fiber that parks in app.Loop(). Invariant: the same singletons exist and system.py runs with __COMMAND_LINE__ before the first frame.", + "test": [ + "tests/port/port_app_loop_test.cpp (port.app_loop: Start + RunMainScript reach app.Loop)", + "tests/port/port_login_flow_test.cpp" + ] }, "CreateMetin2GameMutex": { - "status": "TODO" + "status": "N_A", + "note": "Win32 named mutex; no caller in 40250." }, "DestroyMetin2GameMutex": { - "status": "TODO" + "status": "N_A", + "note": "Win32 named mutex; no caller in 40250." }, "__ErrorPythonLibraryIsNotExist": { - "status": "TODO" + "status": "N_A", + "note": "message box for CheckPythonLibraryFilenames (N_A); PythonBoot::Start returns the InstallStdLib error instead." }, "__IsTimeStampOption": { - "status": "TODO" + "status": "N_A", + "note": "WinMain launcher option (/timestamp -> build-stamp message box); the host has no Win32 command line." }, "__PrintTimeStamp": { - "status": "TODO" + "status": "N_A", + "note": "WinMain /timestamp message box with _MSC_VER build stamp; no gameplay semantics." }, "__IsLocaleOption": { - "status": "TODO" + "status": "N_A", + "note": "WinMain --locale writes locale.txt and quits (launcher diagnostics); the host has no Win32 command line." }, "__IsLocaleVersion": { - "status": "TODO" + "status": "N_A", + "note": "WinMain --perforce-revision writes .version and quits (patcher diagnostics)." }, "__IsOpenIDAuthKeyOption": { - "status": "TODO" + "status": "N_A", + "note": "USE_OPENID is not defined in the 40250 build; compiled out." }, "__IsOpenIDTestOption": { - "status": "TODO" + "status": "N_A", + "note": "USE_OPENID is not defined in the 40250 build; compiled out." }, "WinMain": { - "status": "TODO" + "status": "N_A", + "note": "Win32 entry: hackshield/XTrap/GameGuard/CheckLatestFiles/WebBrowser/COM and launcher options. The platform entry is the host (src/host, android) calling PythonBoot::Start (ApplicationStringTable_Initialize, locale.cfg + SetDefaultCodePage) then PythonBoot::RunMainScript." }, "GrannyError": { - "status": "TODO" + "status": "N_A", + "note": "never installed: 40250 Setup sets the Granny log callback Function to nullptr." }, "Setup": { - "status": "TODO" + "status": "N_A", + "note": "timeBeginPeriod (Win32 timer resolution) and a null Granny log callback, which is the GrannyRuntime default." } } } diff --git a/src/platform/ScriptLib/PythonBoot.cpp b/src/platform/ScriptLib/PythonBoot.cpp index fe34c2e1..864fd6dd 100644 --- a/src/platform/ScriptLib/PythonBoot.cpp +++ b/src/platform/ScriptLib/PythonBoot.cpp @@ -46,6 +46,7 @@ #include "UserInterface/PythonApplication.h" #include "EterBase/Timer.h" #include "PythonBoot.h" +#include "../UserInterface/UserInterface.h" #include "PythonHost.h" #include "../EterLib/UIRenderCommands.h" #include "../EterBase/LogBox.h" @@ -714,6 +715,8 @@ bool Start(const char* stdlib_path, std::string* error) }); #endif + // 40250 WinMain (UserInterface.cpp:524): ApplicationStringTable_Initialize(hInstance) before locale.cfg. + ApplicationStringTable_Initialize(NULL); // 40250 Main (UserInterface.cpp:410): if (LocaleService_LoadGlobal(hInstance)) SetDefaultCodePage(...). std::string locale_config = "locale.cfg"; if (const char* client = std::getenv("MT_40250_CLIENT")) diff --git a/src/platform/UserInterface/UserInterface.cpp b/src/platform/UserInterface/UserInterface.cpp index 3749c9b9..85d1f841 100644 --- a/src/platform/UserInterface/UserInterface.cpp +++ b/src/platform/UserInterface/UserInterface.cpp @@ -14,6 +14,7 @@ #include "MilesLib/SoundData.h" #include "UserInterface.h" +#include #include #include @@ -26,6 +27,15 @@ // 40250 UserInterface.cpp:49. bool __IS_TEST_SERVER_MODE__=false; +// 40250 UserInterface.cpp:73. WinMain shows the text in a message box after Main returns; here it stays readable +// for the host. +char gs_szErrorString[512] = ""; + +void ApplicationSetErrorString(const char* szErrorString) +{ + strcpy(gs_szErrorString, szErrorString); +} + // 40250 UserInterface.cpp:98. PORT: LoadString reads the executable's STRINGTABLE; the one the supplied English // client resolves is UserInterface.rc's LANG_ENGLISH, SUBLANG_ENGLISH_US section (ids from resource.h). namespace @@ -45,12 +55,22 @@ const char* LoadAppString(DWORD dwID) return ""; } -std::map gs_kMap_dwID_stLocale; } // namespace +struct ApplicationStringTable +{ + HINSTANCE m_hInstance; + std::map m_kMap_dwID_stLocale; +} gs_kAppStrTable; + +void ApplicationStringTable_Initialize(HINSTANCE hInstance) +{ + gs_kAppStrTable.m_hInstance=hInstance; +} + const std::string& ApplicationStringTable_GetString(DWORD dwID) { - std::string& rstLocale=gs_kMap_dwID_stLocale[dwID]; + std::string& rstLocale=gs_kAppStrTable.m_kMap_dwID_stLocale[dwID]; rstLocale=LoadAppString(dwID); return rstLocale; diff --git a/src/platform/UserInterface/UserInterface.h b/src/platform/UserInterface/UserInterface.h index f439b488..6a7814bf 100644 --- a/src/platform/UserInterface/UserInterface.h +++ b/src/platform/UserInterface/UserInterface.h @@ -10,3 +10,10 @@ bool PackInitialize(const char * c_pszFolder); // The two function-static singletons 40250 Main() creates before PackInitialize("pack") // (`static CLZO lzo; static CEterPackManager EterPackManager;`), created on first use and alive until exit. void PackSingletons(); + +// 40250: ApplicationStringTable_Initialize (WinMain, before LocaleService_LoadConfig). LoadString has no module +// here, so the handle is only stored. +void ApplicationStringTable_Initialize(HINSTANCE hInstance); + +// gs_szErrorString (40250 UserInterface.cpp:73), set by ApplicationSetErrorString (UserInterface/StdAfx.h); WinMain shows it after Main. +extern char gs_szErrorString[512]; diff --git a/src/port/UserInterface/StdAfx.h b/src/port/UserInterface/StdAfx.h index d9d313f5..e5ac6a27 100644 --- a/src/port/UserInterface/StdAfx.h +++ b/src/port/UserInterface/StdAfx.h @@ -76,3 +76,5 @@ extern const std::string& ApplicationStringTable_GetString(DWORD dwID, LPCSTR sz extern const char* ApplicationStringTable_GetStringz(DWORD dwID); extern const char* ApplicationStringTable_GetStringz(DWORD dwID, LPCSTR szKey); + +extern void ApplicationSetErrorString(const char* szErrorString); diff --git a/tests/port/port_app_loop_test.cpp b/tests/port/port_app_loop_test.cpp index 598c9024..7e28dcdb 100644 --- a/tests/port/port_app_loop_test.cpp +++ b/tests/port/port_app_loop_test.cpp @@ -18,6 +18,7 @@ #include "ScriptLib/StdAfx.h" #include "../../src/platform/ScriptLib/PythonBoot.h" #include "../../src/platform/ScriptLib/PythonHost.h" +#include "UserInterface/StdAfx.h" // ApplicationSetErrorString, ApplicationStringTable_GetStringz #include "../../src/platform/UserInterface/UserInterface.h" #include "../../src/platform/EterLib/UIRenderCommands.h" #include "../../src/platform/EterLib/RenderCommands3D.h" @@ -327,6 +328,13 @@ int main(int argc, char** argv) GraphicBaseAccess::DetectorString(&modes); CHECK(modes.find("800x600x32 HWVP") != std::string::npos); } + // 40250 UserInterface.cpp: CheckLatestFiles hands WinMain its message through ApplicationSetErrorString; + // the string table keeps the (DWORD) text per id. + CHECK(gs_szErrorString[0] == '\0'); + ApplicationSetErrorString("File 'a' is not latest version."); + CHECK(std::string(gs_szErrorString) == "File 'a' is not latest version."); + gs_szErrorString[0] = '\0'; + CHECK(std::string(ApplicationStringTable_GetStringz(1)) == "Metin 2"); { CScreen screen; CHECK(!screen.IsLostDevice() && screen.RestoreDevice());