port: UserInterface.cpp entry unit — ApplicationSetErrorString/StringTable_Initialize verbatim, Main ADAPTED to PythonBoot, Win32 entry N_A

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-30 15:08:00 +09:00
co-authored by Claude Opus 5.5
parent fd4d9a39df
commit b497fce393
7 changed files with 96 additions and 18 deletions
+1
View File
@@ -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/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/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": "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"}
@@ -5,13 +5,28 @@
"contracts": [], "contracts": [],
"functions": { "functions": {
"ApplicationSetErrorString": { "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": { "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": { "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": { "ApplicationStringTable_GetString": {
"status": "ADAPTED", "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" "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": { "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": { "CreateMetin2GameMutex": {
"status": "TODO" "status": "N_A",
"note": "Win32 named mutex; no caller in 40250."
}, },
"DestroyMetin2GameMutex": { "DestroyMetin2GameMutex": {
"status": "TODO" "status": "N_A",
"note": "Win32 named mutex; no caller in 40250."
}, },
"__ErrorPythonLibraryIsNotExist": { "__ErrorPythonLibraryIsNotExist": {
"status": "TODO" "status": "N_A",
"note": "message box for CheckPythonLibraryFilenames (N_A); PythonBoot::Start returns the InstallStdLib error instead."
}, },
"__IsTimeStampOption": { "__IsTimeStampOption": {
"status": "TODO" "status": "N_A",
"note": "WinMain launcher option (/timestamp -> build-stamp message box); the host has no Win32 command line."
}, },
"__PrintTimeStamp": { "__PrintTimeStamp": {
"status": "TODO" "status": "N_A",
"note": "WinMain /timestamp message box with _MSC_VER build stamp; no gameplay semantics."
}, },
"__IsLocaleOption": { "__IsLocaleOption": {
"status": "TODO" "status": "N_A",
"note": "WinMain --locale writes locale.txt and quits (launcher diagnostics); the host has no Win32 command line."
}, },
"__IsLocaleVersion": { "__IsLocaleVersion": {
"status": "TODO" "status": "N_A",
"note": "WinMain --perforce-revision writes <exe>.version and quits (patcher diagnostics)."
}, },
"__IsOpenIDAuthKeyOption": { "__IsOpenIDAuthKeyOption": {
"status": "TODO" "status": "N_A",
"note": "USE_OPENID is not defined in the 40250 build; compiled out."
}, },
"__IsOpenIDTestOption": { "__IsOpenIDTestOption": {
"status": "TODO" "status": "N_A",
"note": "USE_OPENID is not defined in the 40250 build; compiled out."
}, },
"WinMain": { "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": { "GrannyError": {
"status": "TODO" "status": "N_A",
"note": "never installed: 40250 Setup sets the Granny log callback Function to nullptr."
}, },
"Setup": { "Setup": {
"status": "TODO" "status": "N_A",
"note": "timeBeginPeriod (Win32 timer resolution) and a null Granny log callback, which is the GrannyRuntime default."
} }
} }
} }
+3
View File
@@ -46,6 +46,7 @@
#include "UserInterface/PythonApplication.h" #include "UserInterface/PythonApplication.h"
#include "EterBase/Timer.h" #include "EterBase/Timer.h"
#include "PythonBoot.h" #include "PythonBoot.h"
#include "../UserInterface/UserInterface.h"
#include "PythonHost.h" #include "PythonHost.h"
#include "../EterLib/UIRenderCommands.h" #include "../EterLib/UIRenderCommands.h"
#include "../EterBase/LogBox.h" #include "../EterBase/LogBox.h"
@@ -714,6 +715,8 @@ bool Start(const char* stdlib_path, std::string* error)
}); });
#endif #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(...). // 40250 Main (UserInterface.cpp:410): if (LocaleService_LoadGlobal(hInstance)) SetDefaultCodePage(...).
std::string locale_config = "locale.cfg"; std::string locale_config = "locale.cfg";
if (const char* client = std::getenv("MT_40250_CLIENT")) if (const char* client = std::getenv("MT_40250_CLIENT"))
+22 -2
View File
@@ -14,6 +14,7 @@
#include "MilesLib/SoundData.h" #include "MilesLib/SoundData.h"
#include "UserInterface.h" #include "UserInterface.h"
#include <cstring>
#include <map> #include <map>
#include <string> #include <string>
@@ -26,6 +27,15 @@
// 40250 UserInterface.cpp:49. // 40250 UserInterface.cpp:49.
bool __IS_TEST_SERVER_MODE__=false; 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 // 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). // client resolves is UserInterface.rc's LANG_ENGLISH, SUBLANG_ENGLISH_US section (ids from resource.h).
namespace namespace
@@ -45,12 +55,22 @@ const char* LoadAppString(DWORD dwID)
return ""; return "";
} }
std::map<DWORD, std::string> gs_kMap_dwID_stLocale;
} // namespace } // namespace
struct ApplicationStringTable
{
HINSTANCE m_hInstance;
std::map<DWORD, std::string> m_kMap_dwID_stLocale;
} gs_kAppStrTable;
void ApplicationStringTable_Initialize(HINSTANCE hInstance)
{
gs_kAppStrTable.m_hInstance=hInstance;
}
const std::string& ApplicationStringTable_GetString(DWORD dwID) 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); rstLocale=LoadAppString(dwID);
return rstLocale; return rstLocale;
@@ -10,3 +10,10 @@ bool PackInitialize(const char * c_pszFolder);
// The two function-static singletons 40250 Main() creates before PackInitialize("pack") // 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. // (`static CLZO lzo; static CEterPackManager EterPackManager;`), created on first use and alive until exit.
void PackSingletons(); 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];
+2
View File
@@ -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);
extern const char* ApplicationStringTable_GetStringz(DWORD dwID, LPCSTR szKey); extern const char* ApplicationStringTable_GetStringz(DWORD dwID, LPCSTR szKey);
extern void ApplicationSetErrorString(const char* szErrorString);
+8
View File
@@ -18,6 +18,7 @@
#include "ScriptLib/StdAfx.h" #include "ScriptLib/StdAfx.h"
#include "../../src/platform/ScriptLib/PythonBoot.h" #include "../../src/platform/ScriptLib/PythonBoot.h"
#include "../../src/platform/ScriptLib/PythonHost.h" #include "../../src/platform/ScriptLib/PythonHost.h"
#include "UserInterface/StdAfx.h" // ApplicationSetErrorString, ApplicationStringTable_GetStringz
#include "../../src/platform/UserInterface/UserInterface.h" #include "../../src/platform/UserInterface/UserInterface.h"
#include "../../src/platform/EterLib/UIRenderCommands.h" #include "../../src/platform/EterLib/UIRenderCommands.h"
#include "../../src/platform/EterLib/RenderCommands3D.h" #include "../../src/platform/EterLib/RenderCommands3D.h"
@@ -327,6 +328,13 @@ int main(int argc, char** argv)
GraphicBaseAccess::DetectorString(&modes); GraphicBaseAccess::DetectorString(&modes);
CHECK(modes.find("800x600x32 HWVP") != std::string::npos); 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; CScreen screen;
CHECK(!screen.IsLostDevice() && screen.RestoreDevice()); CHECK(!screen.IsLostDevice() && screen.RestoreDevice());