#pragma once // Starting the script layer inside a host process (docs/PORT-PLAN.md 批次 2P step 4). // // 40250 runs the interpreter on Main()'s stack (UserInterface/UserInterface.cpp:419-434): construct // CPythonLauncher, Create(), RunMainScript(), Clear(), all inside one WinMain. Godot owns the process // here and calls in from GDScript, so the launcher has to outlive the call that starts it — that split // (Start / RunMainScript / Stop) is the only difference from the original control flow. // // It lives under platform/ScriptLib rather than platform/UserInterface because it is only buildable // with the embedded interpreter, and that is the directory both port_logic and port_platform drop when // `mtpython` is absent (extension/src/port/CMakeLists.txt). // // godot-free, like everything else under platform/: extension/src/python_host_node.cpp is what GDScript // talks to. #include namespace PythonBoot { // PythonHost::Configure() -> CPythonLauncher -> Create() -> PythonHost::InstallStdLib(stdlib_path). // An empty stdlib_path means PythonHost::DefaultStdLibPath(). Starting twice is a no-op that succeeds. // On failure *error is set and the interpreter is shut down again, so the next attempt starts clean. // The packs must already be registered (platform/PackBackend.h), as 40250 registers them in Main() // before the launcher exists. bool Start(const char* stdlib_path, std::string* error); bool IsRunning(); // The SDL native client supplies an OS cursor; the Godot host keeps its software cursor. void SetHostHardwareCursorEnabled(bool enabled); bool HostHardwareCursorEnabled(); int CursorShape(); bool CursorVisible(); // 40250: RunMainScript(CPythonLauncher&, const char*) — the module initializers, __DEBUG__, // __COMMAND_LINE__ and RunFile("system.py"). 2V0-e registers temporary observable gameplay modules; // they are replaced by the real modules in later 2V slices. // False leaves *error set to what the launcher reported through LogBox (platform/EterBase/LogBox.h). // // PORT: system.py runs on a script thread. RunMainScript returns once prototype.RunApp() has reached // app.Loop() (IsAppLooping) or the script has ended; from then on every AppFrame() runs exactly one // CPythonApplication::Process() while the host thread waits, so the two never run concurrently. bool RunMainScript(const char* lpCmdLine, std::string* error); bool IsAppLooping(); bool AppFrame(); // Native CPythonBackground map selection, in the local coordinate frame of RenderGame. std::string CurrentMapName(); // Used by the platform CPythonApplication: Loop() calls AppLoopWait() before each Process() and stops // when it returns false; Exit()/Abort() call AppRequestQuit() (40250: PostQuitMessage). bool AppLoopWait(); void AppRequestQuit(); // CPythonLauncher::RunLine, with the reported text handed back rather than only shown. The host's own // check uses it to prove the interpreter and the standard library work in-process on a device that has // no 40250 packs, which is where RunMainScript cannot run at all. bool RunLine(const char* source, std::string* error); // str(expression) evaluated in __main__ (a host/test helper; 40250 has no counterpart). bool Evaluate(const char* expression, std::string* result, std::string* error); // Forward physical Godot input to the original 40250 window manager. Coordinates // are viewport pixels; SetUISize also establishes its logical resolution. void SetUISize(int width, int height); // Mobile safe area: the 40250 windows are laid out width - 2 * inset wide and drawn inset pixels // right of the screen edge (clear of rounded corners and cutouts) while the 3D world keeps the whole // screen. Input coordinates stay screen pixels. Takes effect at the next SetUISize; 0 = off. void SetUISafeInset(int inset); void UIMouseMove(int x, int y); void UIMouseButton(int button, bool pressed, int x, int y); void UIMouseWheel(int nLen); void UIKey(int key, bool pressed); // Mobile touch & joystick controls void SetMoveDirection(float angleDeg, bool moving); void SetAttackKey(bool pressed); void UseLocalQuickSlot(int localSlotIndex); bool TryAssignAttachedObjectToLocalQuickSlot(int localSlotIndex); // PORT: auto hunt (CPythonPlayer::AutoHunt_*, window in AutoHuntScript.inc): start/stop, the settings // window, and whether it runs / a character is in the world to run it. void AutoHuntToggle(); void AutoHuntOpenSettings(); bool AutoHuntIsEnabled(); bool AutoHuntAvailable(); // The skill or inventory item in the local quick slot: its UI texture name, the icon's (su, sv, eu, ev) // inside it and the item count (0 for a skill). bool LocalQuickSlotIcon(int localSlotIndex, std::string* texture, float uv[4], int* count); // Touch gestures: a Win32 WM_LBUTTONDBLCLK (40250 CPythonApplication::OnMouseLeftButtonDoubleClick), // whether an icon hangs on the cursor (CWindowManager::IsAttaching) and mouseController.DeattachObject(). void UIMouseDoubleClick(int x, int y); bool UIIsAttaching(); void UIDeattachObject(); // Turns the camera around the player immediately, without CCamera::Drag's decaying velocity. void CameraRotateBy(float rollDeg, float pitchDeg); bool IsPointInsideActiveUI(int x, int y); // Touch hosts: hide 40250's on-screen login keypad (the system keyboard types instead). // Also drops the mouse arrow: touch hosts run 40250's hardware-cursor mode with no OS cursor, so // mouseModule draws only the attached icon. void SetTouchInput(bool touch); bool TouchInput(); // An EditLine has focus (40250 ui.EditLine.OnSetFocus -> ime.EnableCaptureInput). bool TextInputFocused(); // (x, y) hits the focused window, i.e. the tap landed on the focused EditLine. bool IsPointInsideFocusedWindow(int x, int y); struct PlayerStatusInfo { int level = 1; int hp = 0; int max_hp = 0; int sp = 0; int max_sp = 0; int exp = 0; int max_exp = 0; std::string name; }; PlayerStatusInfo GetPlayerStatusInfo(); // WM_CHAR (a Unicode code point) and WM_KEYDOWN (a Win32 VK code) for CPythonIME and OnIMEKeyDown. void UIChar(unsigned codepoint); void UIIMEKeyDown(int vkey); // While IsAppLooping(), UIUpdate is AppFrame() and UIRender keeps the commands that Process() drew. void UIUpdate(); void UIRender(); // Completed native frame duration, including Vulkan rendering and presentation, for auto sight range. void SetNativeRenderFrameTime(float milliseconds); bool IsSoftwareCursorVisible(); // 40250 Main() calls Clear() and lets the launcher leave scope. void Stop(); }