# python_host_check —— 在 app 进程里把内嵌解释器起来并跑 system.py(docs/PORT-PLAN.md 批次 2P step 4)。 # # 和 ctest 的 `port.python_launcher` 跑的是同一条序列,区别只有一个:那边是独立可执行文件,这边在 # Godot 进程里,由 GDScript 发起 —— step 4 要验的就是这个差别。2V0 把 C++ 模块注册上之前, # system.py 停在第一个 import(`No module named app`),这就是当前的验收结果。 # # 真机上通常没有 40250 的 Client/pack(APK 里只有 python27.zip),所以分两段:解释器 + 标准库这一段 # 不需要 pack,任何平台都跑;system.py 这一段需要 pack,没有就跳过并说清楚。 # # 桌面:python_host_test.gd(--script);真机:MT_TEST_MODE=python 从 client_main.gd 进来。 extends RefCounted # 2V0 之前 system.py 必然停在这里;2V0 之后这一行要跟着改。 const EXPECTED_STOP := "No module named app" var fail := 0 func _ck(ok: bool, message: String) -> void: if not ok: fail += 1 printerr("FAIL: " + message) else: print("ok: " + message) # 返回失败数;0 表示落在预期的停止点上(或按上面的规则跳过)。 func run() -> int: if not ClassDB.class_exists("Metin2PythonHost"): printerr("FAIL: Metin2PythonHost extension is not registered") return 1 if not FileAccess.file_exists("res://python27.zip"): print("SKIP: python_host_check(没有 res://python27.zip,需要 -DMTGODOT_EMBED_PYTHON=ON 的构建)") return 0 # 40250 Main() 先注册 pack,再造 CPythonLauncher —— system.py 是从 pack 里读出来的。 var has_pack := AssetRoot.pack_ready() var start_error: String = Metin2PythonHost.start("") _ck(start_error == "", "解释器在 app 进程里起来了:" + start_error) if start_error != "": return fail _ck(Metin2PythonHost.is_running(), "is_running() 为真") _ck(Metin2PythonHost.start("") == "", "重复 start() 是空操作") # 标准库真的在 sys.path 上(真机是沙盒里那份 python27.zip),codec 注册表也重建过。 _ck(Metin2PythonHost.run_line("import os, string, types, codecs") == "", "标准库可 import") _ck(Metin2PythonHost.run_line("assert u'\\xe4'.encode('cp1252') == '\\xe4'") == "", "codec 注册表可用") _ck(Metin2PythonHost.run_line("import sys; assert sys.path") == "", "sys.path 非空") if has_pack: # RunMainScript:initpack() + __DEBUG__ + __COMMAND_LINE__ + RunFile("system.py")。 var err: String = Metin2PythonHost.run_main_script("") print("system.py -> %s" % err) _ck(err.contains(EXPECTED_STOP), "system.py 停在预期的 '%s'(2V0 之后这里会往前走)" % EXPECTED_STOP) else: print("SKIP: system.py 这一段(没有 40250 Client/pack:%s)" % AssetRoot.client_path()) Metin2PythonHost.stop() _ck(not Metin2PythonHost.is_running(), "stop() 之后 is_running() 为假") return fail