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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5590714b16
commit
141206cb69
@@ -3,9 +3,18 @@
|
||||
#include "UserInterface/MarkManager.h"
|
||||
#include "GameLib/GameUtil.h"
|
||||
#include "EterLib/Camera.h"
|
||||
#include "EterBase/Timer.h"
|
||||
#include "EterLib/ResourceManager.h"
|
||||
#include "../PlatformStub.h"
|
||||
#include "../EterLib/UIRenderCommands.h"
|
||||
#include "../ScriptLib/PythonBoot.h"
|
||||
|
||||
// 2V0-d link surface. The application event loop and UI rendering are implemented in 2V0-f.
|
||||
// 2V0-d link surface; 2V0-f adds the application lifecycle (Create/Loop/Process/Exit) that
|
||||
// prototype.RunApp() drives. The rest of the members still wait for the game slices (2V1-2V3).
|
||||
//
|
||||
// PORT: there is no CPythonApplication object yet (its members are the whole game: background,
|
||||
// network stream, player, ...), so these functions only use the singletons PythonBoot owns
|
||||
// (UI::CWindowManager, CTimer, CResourceManager) and never touch a data member.
|
||||
CPythonApplication* CPythonApplication::ms_pInstance = nullptr;
|
||||
|
||||
void CPythonApplication::ShowWebPage(const char*, const RECT&) { MT_PLATFORM_STUB(); }
|
||||
@@ -13,21 +22,84 @@ void CPythonApplication::MoveWebPage(const RECT&) { MT_PLATFORM_STUB(); }
|
||||
void CPythonApplication::HideWebPage() { MT_PLATFORM_STUB(); }
|
||||
bool CPythonApplication::IsWebPageMode() { MT_PLATFORM_STUB(); return false; }
|
||||
void CPythonApplication::GetInfo(UINT, std::string* out) { MT_PLATFORM_STUB(); if (out) out->clear(); }
|
||||
void CPythonApplication::Loop() { MT_PLATFORM_STUB(); }
|
||||
void CPythonApplication::Exit() { MT_PLATFORM_STUB(); }
|
||||
void CPythonApplication::Abort() { MT_PLATFORM_STUB(); }
|
||||
// In 40250, Loop() is: while (1) { if (IsMessage()) { if (!MessageProcess()) break; } else { if (!Process()) break; } }
|
||||
// PORT: Godot owns the message pump and forwards input to the window manager between frames
|
||||
// (PythonBoot::UIMouseMove & co.), so the loop here only waits for the host's next frame. It runs
|
||||
// on PythonBoot's script thread; WM_QUIT is PythonBoot::AppRequestQuit.
|
||||
void CPythonApplication::Loop()
|
||||
{
|
||||
while (PythonBoot::AppLoopWait())
|
||||
{
|
||||
if (!Process())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// In 40250 this is PostQuitMessage(0).
|
||||
void CPythonApplication::Exit() { PythonBoot::AppRequestQuit(); }
|
||||
|
||||
// 40250 also writes a TraceError banner first; the caller (system.py) has already logged the reason.
|
||||
void CPythonApplication::Abort()
|
||||
{
|
||||
TraceError("============================================================================================================");
|
||||
TraceError("Abort!!!!\n\n");
|
||||
PythonBoot::AppRequestQuit();
|
||||
}
|
||||
void CPythonApplication::SetMinFog(float) { MT_PLATFORM_STUB(); }
|
||||
void CPythonApplication::SetFrameSkip(bool) { MT_PLATFORM_STUB(); }
|
||||
bool CPythonApplication::Create(PyObject*, const char*, int, int, int) {
|
||||
MT_PLATFORM_STUB();
|
||||
// appCreate returns NULL on failure. Give Python the exception that
|
||||
// prototype.RunApp expects rather than a SystemError with no exception set.
|
||||
PyErr_SetString(PyExc_RuntimeError, "CREATE_DEVICE");
|
||||
return false;
|
||||
// PORT: 40250 creates the Win32 window, the D3D8 device, cursors, sound, keyboard, the net device,
|
||||
// fonts and the IME here. The Godot window and its canvas are the device on this platform and they
|
||||
// already exist when the host starts the script, so the window size is the canvas size
|
||||
// (PythonBoot::SetUISize) rather than the width/height passed from metin2.cfg. What remains of
|
||||
// Create belongs to the subsystems that are not ported yet (sound 2V4, net 2V1, game render 2V3).
|
||||
bool CPythonApplication::Create(PyObject*, const char*, int, int, int)
|
||||
{
|
||||
unsigned width = 0, height = 0;
|
||||
UIRenderGetSize(&width, &height);
|
||||
if (!width || !height)
|
||||
{
|
||||
// appCreate returns NULL on failure; RunApp turns this into the original LogBox.
|
||||
TraceError("CreateDevice: GraphicDevice create failed");
|
||||
PyErr_SetString(PyExc_RuntimeError, "CREATE_DEVICE");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void CPythonApplication::UpdateGame() { MT_PLATFORM_STUB(); }
|
||||
void CPythonApplication::RenderGame() { MT_PLATFORM_STUB(); }
|
||||
bool CPythonApplication::Process() { MT_PLATFORM_STUB(); return false; }
|
||||
|
||||
// 40250 PythonApplication.cpp:399. Kept in order: timer, network (2V1), input polling (Godot pushes
|
||||
// input instead), camera (2V3), resource GC, mouse/UI update, then the render block's interface pass.
|
||||
// PORT: the frame-skip bookkeeping and the game render pass are left out; the Godot frame clock
|
||||
// decides when this runs, and RenderGame belongs to 2V3.
|
||||
bool CPythonApplication::Process()
|
||||
{
|
||||
ELTimer_SetFrameMSec();
|
||||
|
||||
CTimer& rkTimer=CTimer::Instance();
|
||||
rkTimer.Advance();
|
||||
|
||||
CResourceManager::Instance().Update();
|
||||
|
||||
OnUIUpdate();
|
||||
|
||||
UIRenderBeginFrame();
|
||||
OnUIRender();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 40250 PythonApplicationEvent.cpp:15-25
|
||||
void CPythonApplication::OnUIUpdate()
|
||||
{
|
||||
UI::CWindowManager& rkUIMgr=UI::CWindowManager::Instance();
|
||||
rkUIMgr.Update();
|
||||
}
|
||||
|
||||
void CPythonApplication::OnUIRender()
|
||||
{
|
||||
UI::CWindowManager& rkUIMgr=UI::CWindowManager::Instance();
|
||||
rkUIMgr.Render();
|
||||
}
|
||||
BOOL CPythonApplication::SetCursorNum(int) { MT_PLATFORM_STUB(); return FALSE; }
|
||||
void CPythonApplication::SetCursorVisible(BOOL, bool) { MT_PLATFORM_STUB(); }
|
||||
BOOL CPythonApplication::GetCursorVisible() { MT_PLATFORM_STUB(); return FALSE; }
|
||||
|
||||
Reference in New Issue
Block a user