Files
mtgodot-poc/project/client_main.gd
T
shenleiandClaude Opus 5.5 a49942a1a1 client_main: default route switches to port (MT_PORT_PATH)
Without MT_PORT_PATH the app runs 40250 system.py on the Python UI and
3D surfaces; MT_PORT_PATH=legacy keeps the GDScript AppFlow. The
smoke/playable live tests stay on legacy, MT_TEST_MODE=python_ui remains
a port alias, and an unset switch falls back to legacy (with a warning)
when the Python host or the 40250 pack is missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:51:55 +09:00

115 lines
5.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# client_main —— 打包客户端的入口场景根(main_scene = res://client_main.tscn)。
#
# 默认走 port 路由(PORT-PLAN §2 总开关):40250 system.py 在内嵌解释器里跑,界面画在
# python_ui_surface.gd、RenderGame 的 3D 绘制画在 python_3d_surface.gd。
# MT_PORT_PATH=legacy 回到旧的 GDScript AppFlow(登录 → 选人 → 进游戏 串场控制器);
# MT_TEST_MODE=smoke/playable 是 AppFlow 的真服测试,固定走 legacy。
# 资源目录由 AssetRoot 决定:默认 res://../assets(开发树),打包后设环境变量
# MT_ASSETS 指向真实资源目录即可(见 project/asset_root.gd)。
extends Node
const AppFlow = preload("res://app_flow.gd")
const LiveSmokeTest = preload("res://live_smoke_test.gd")
const PackageRenderTest = preload("res://package_render_test.gd")
const PlayableLiveTest = preload("res://playable_live_test.gd")
const ForestMapRenderTest = preload("res://forest_map_render_test.gd")
const NetTrace = preload("res://net_trace.gd")
func _ready() -> void:
if OS.get_environment("MT_TEST_MODE") == "particle_exit":
add_child(preload("res://particle_exit_test.gd").new())
return
# MT_TEST_MODE=render:包内离线渲染自检,不起 AppFlow、不连服务器。
# 导出模板不接受 --script,这是导出包里唯一能跑离线渲染回归的入口。
if OS.get_environment("MT_TEST_MODE") == "render":
AssetPack.ensure()
var t := PackageRenderTest.new()
t.name = "PackageRenderTest"
add_child(t)
return
# MT_TEST_MODE=python:在 app 进程里起内嵌解释器跑 system.py(PORT-PLAN 批次 2P step 4)。
# 导出模板不接受 --script,这是在真机 APK/IPA 里跑这条检查的唯一入口。
if OS.get_environment("MT_TEST_MODE") == "python":
AssetPack.ensure()
var fail: int = preload("res://python_host_check.gd").new().run()
if fail == 0:
print("PASS: python_host_check (app 进程内 system.py)")
else:
printerr("%d check(s) failed" % fail)
get_tree().quit(1 if fail else 0)
return
if OS.get_environment("MT_TEST_MODE") == "forest_render":
var forest := ForestMapRenderTest.new()
forest.name = "ForestMapRenderTest"
add_child(forest)
return
# port 路由:40250 system.py 的界面直接画在 Godot Canvas 上(PORT-PLAN 2V0-f),
# Logo → 登录 → 选人 → 进游戏,RenderGame 的 3D 绘制由 python_3d_surface.gd 画出(2V2-e),
# 方向键/鼠标点地走动走 40250 原路径(2V3);app.Exit() 退出进程。
# MT_TEST_MODE=python_ui 是切换默认值之前的入口,保留为 MT_PORT_PATH=port 的别名。
var mode := OS.get_environment("MT_TEST_MODE")
var route := OS.get_environment("MT_PORT_PATH")
if mode == "python_ui":
route = "port"
elif mode == "smoke" or mode == "playable":
route = "legacy"
if route != "legacy":
if route != "" and route != "port":
push_warning("[client] 未知的 MT_PORT_PATH=%s,按 port 处理" % route)
if _start_port_route(route != ""):
return
_start_legacy_route()
# Returns false when the port route cannot start and the default (unset MT_PORT_PATH) should fall
# back to legacy; an explicit MT_PORT_PATH=port quits with the error instead.
func _start_port_route(explicit: bool) -> bool:
AssetPack.ensure()
if not explicit and not (ClassDB.class_exists("Metin2PythonHost") and AssetRoot.pack_ready()):
push_warning("[client] port 路由缺 Metin2PythonHost 或 40250 Client/pack(%s),退回 legacy AppFlow" % AssetRoot.client_path())
return false
var surface: Control = preload("res://python_ui_surface.gd").new()
surface.name = "PythonUISurface"
add_child(surface)
# The UI surface runs CPythonApplication::Process in its _process; the 3D surface reads that
# frame's draws after it, so it comes second in the tree.
var world: Node3D = preload("res://python_3d_surface.gd").new()
world.name = "Python3DSurface"
add_child(world)
var err: String = surface.run_app()
if err != "":
printerr("port: " + err)
get_tree().quit(1)
return true
func _start_legacy_route() -> void:
# 打包 app 从 Finder/open 启动时没有 shell 环境;40250 服务器使用 classic
# DH2/CTR 协议,因此默认固定到 classic,同时保留 MT_PROTOCOL 覆盖能力。
if OS.get_environment("MT_PROTOCOL").is_empty():
OS.set_environment("MT_PROTOCOL", "classic")
# 移动端:APK/IPA 里没有资源 —— 挂载外部的 assets.zip(adb push / ios-deploy 上传)。
AssetPack.ensure()
var root := AssetRoot.path()
if not AssetRoot.available():
push_warning("[client] 资源目录不存在:%s —— MT_ASSETS 环境变量 / assets.zip(adb push 到 files/)" % root)
var af := AppFlow.new()
af.name = "AppFlow"
add_child(af)
af.start(root)
# 主角 vid 生命周期取证(见 net_trace.gd):排在 AppFlow 之后,保证每帧
# 在 client 派发完信号之后再读 main_vid。
if af.client != null:
var trace := NetTrace.new()
trace.name = "NetTrace"
add_child(trace)
trace.setup(af.client)
if OS.get_environment("MT_TEST_MODE") == "smoke":
var smoke := LiveSmokeTest.new()
smoke.name = "LiveSmokeTest"
add_child(smoke)
smoke.setup(af, af.client)
if OS.get_environment("MT_TEST_MODE") == "playable":
var playable := PlayableLiveTest.new()
playable.name = "PlayableLiveTest"
add_child(playable)
playable.setup(af, af.client)