Files
mtgodot-poc/extension/src/platform/ScriptLib/PythonBoot.h
T
shenleiandClaude Opus 5.5 141206cb69 2V0-f: run the real system.py app loop in Godot
- system.py runs app.Loop() on the script fiber; each UIUpdate is one
  CPythonApplication::Process(). Logo -> Login, popup ESC/click and
  app.Exit teardown (launcher cleared first, as in 40250 Main) work.
- Image commands are base-texture quads with UVs (a .sub shares its parent
  texture); ImageInstance/ExpandedImageInstance OnRender and SetRenderingRect
  ported verbatim, so scale/rotation/rendering rect are drawn.
- CGraphicBase::GetColor / grp.GenerateColor ported (ThinBoard background).
- port.app_loop test, python_host_test app-loop checks, MT_TEST_MODE=python_ui.
- TODO: .fnt/CGraphicText font pipeline, ExpandedImage blend modes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 13:38:13 +09:00

63 lines
3.2 KiB
C++

#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 <string>
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();
// 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();
// 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);
// 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);
void UIMouseMove(int x, int y);
void UIMouseButton(int button, bool pressed, int x, int y);
void UIKey(int key, bool pressed);
// While IsAppLooping(), UIUpdate is AppFrame() and UIRender keeps the commands that Process() drew.
void UIUpdate();
void UIRender();
// 40250 Main() calls Clear() and lets the launcher leave scope.
void Stop();
}