env.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. """环境注入: L_GameEnvManager / FileUtils / LuaBridgeCtl / gameEnviroment / 杂项全局函数。
  2. Task 5 契约: EnvData + install_env; 不引入 python.eval, FileUtils 走 AP_* 直挂。
  3. """
  4. from __future__ import annotations
  5. import os
  6. from typing import Any
  7. SWITCHES_DEFAULT: dict[int, int] = {2: 1} # Modules_Index_Enable_Check_Heart_Beat=1(心跳开)
  8. class EnvData:
  9. """游戏环境数据: 登录态/账号/渠道/签名等。data 透传给 L_GameEnvManager.GetEnvDataByKey; switches / settings 独立 dict。"""
  10. def __init__(self, data: dict[str, Any]) -> None:
  11. self.data: dict[str, Any] = dict(data)
  12. self.switches: dict[int, int] = dict(SWITCHES_DEFAULT)
  13. self.settings: dict[int, list[Any]] = {}
  14. def _safe_join(abs_state: str, rel: str) -> str:
  15. """join 后必须仍在 abs_state 内(防 rel 形如 ../escape)。返回 abspath。"""
  16. p = os.path.abspath(os.path.join(abs_state, rel))
  17. if os.path.commonpath([p, abs_state]) != abs_state:
  18. raise ValueError(f"path escape: {rel!r} not under state_dir")
  19. return p
  20. def install_env(lua: Any, env: EnvData, state_dir: str) -> None:
  21. """注入环境: L_GameEnvManager / LuaBridgeCtl / FileUtils / gameEnviroment / 杂项全局。"""
  22. os.makedirs(state_dir, exist_ok=True)
  23. abs_state = os.path.abspath(state_dir)
  24. g = lua.globals()
  25. g["_PY_ENV"] = env
  26. g["_PY_STATE_DIR"] = state_dir
  27. # Lupa 不翻译 KeyError -> nil, 暴露 get/switch helper 规避
  28. def _get_env_key(k: str) -> Any:
  29. return env.data.get(k)
  30. def _get_switch(i: int) -> int:
  31. return env.switches.get(int(i), 0)
  32. def _set_switch(i: int, v: int) -> None:
  33. env.switches[int(i)] = int(v)
  34. def _get_setting(i: int) -> Any:
  35. return env.settings.get(int(i))
  36. def _set_setting(i: int, v: Any) -> None:
  37. env.settings[int(i)] = v
  38. g["AP_getEnvKey"] = _get_env_key
  39. g["AP_getSwitch"] = _get_switch
  40. g["AP_setSwitch"] = _set_switch
  41. g["AP_getSetting"] = _get_setting
  42. g["AP_setSetting"] = _set_setting
  43. # Lua 侧: env manager / bridge ctl / 杂项全局
  44. # 冒号定义使 self 显式, 兼容游戏里 L_GameEnvManager:GetEnvDataByKey(...) / LuaBridgeCtl:Inst():...
  45. lua.execute(r"""
  46. L_GameEnvManager = {}
  47. function L_GameEnvManager:GetEnvDataByKey(k) return AP_getEnvKey(k) end
  48. LuaBridgeCtl = {}
  49. function LuaBridgeCtl:Inst() return self end
  50. function LuaBridgeCtl:GetModulesSwitch(i) return AP_getSwitch(i) end
  51. function LuaBridgeCtl:SetModulesSwitch(i, v) AP_setSwitch(i, v) end
  52. function release_print(...) end
  53. releasePrint = release_print
  54. function GET_STRING(id) return "" end
  55. function JUMPTO(...) end
  56. function GET_SETTING(i) return AP_getSetting(i) end
  57. function CHECK_SETTING(i)
  58. local s = AP_getSetting(i)
  59. return s ~= nil and s[1] == 1 or false
  60. end
  61. function CHANGE_SETTING(i, v) AP_setSetting(i, v) end
  62. """)
  63. # FileUtils: Python 静态方法暴露为 Lua 全局, cc.FileUtils Lua 薄壳包一层
  64. class _FU:
  65. @staticmethod
  66. def getInstance() -> "type[_FU]": # noqa: N802
  67. return _FU
  68. @staticmethod
  69. def getWritablePath() -> str: # noqa: N802
  70. return abs_state + os.sep
  71. @staticmethod
  72. def writeStringToFile(s: str, rel: str) -> None: # noqa: N802
  73. p = _safe_join(abs_state, rel)
  74. os.makedirs(os.path.dirname(p), exist_ok=True)
  75. with open(p, "w", encoding="utf-8") as f:
  76. f.write(s)
  77. @staticmethod
  78. def isFileExist(rel: str) -> bool: # noqa: N802
  79. try:
  80. return os.path.exists(_safe_join(abs_state, rel))
  81. except ValueError:
  82. return False
  83. g["AP_writeStringToFile"] = _FU.writeStringToFile
  84. g["AP_isFileExist"] = _FU.isFileExist
  85. g["AP_getWritablePath"] = _FU.getWritablePath
  86. lua.execute("""
  87. cc = cc or {}
  88. cc.FileUtils = {getInstance = function() return cc.FileUtils end}
  89. function cc.FileUtils:writeStringToFile(s, rel) AP_writeStringToFile(s, rel) end
  90. function cc.FileUtils:isFileExist(rel) return AP_isFileExist(rel) end
  91. function cc.FileUtils:getWritablePath() return AP_getWritablePath() end
  92. """)
  93. # gameEnviroment(小写 e) - 全局 C++ 单例, 最小面
  94. lua.execute(r"""
  95. gameEnviroment = gameEnviroment or {__netClient = nil}
  96. function gameEnviroment:Inst() return self end
  97. function gameEnviroment:SetNetClient(nc) self.__netClient = nc end
  98. function gameEnviroment:GetNetClient() return self.__netClient end
  99. function gameEnviroment.SetLoginAccount(a) end
  100. function gameEnviroment.GetDownloadRootURL() return "" end
  101. """)