import sys import os import builtins import time import _thread import gc import socket import struct import warnings # === GLOBAL WARNING SUPPRESSION & METADATA SHIM (very early) === try: import importlib.metadata _orig_metadata_version = importlib.metadata.version _orig_metadata_distribution = importlib.metadata.distribution _KNOWN_VERSIONS = { "werkzeug": "3.1.9", "flask": "3.1.3", "marshmallow": "3.20.0", "requests": "2.34.2", "urllib3": "2.8.0", "protobuf": "7.36.2", "click": "8.5.0", "jinja2": "3.1.6", "itsdangerous": "2.2.0", "blinker": "1.9.0", "markupsafe": "3.0.4", "dataclasses-json": "0.6.7", "dataclasses_json": "0.6.7", "packaging": "26.3" } class _ShimedDistribution: def __init__(self, name, version): self.name = name self.version = version self.metadata = {"Name": name, "Version": version} def _safe_metadata_version(name): try: return _orig_metadata_version(name) except Exception: clean = name.lower().replace("-", "_") return _KNOWN_VERSIONS.get(name.lower(), _KNOWN_VERSIONS.get(clean, "1.0.0")) def _safe_metadata_distribution(name): try: return _orig_metadata_distribution(name) except Exception: ver = _safe_metadata_version(name) return _ShimedDistribution(name, ver) importlib.metadata.version = _safe_metadata_version importlib.metadata.distribution = _safe_metadata_distribution except Exception: pass warnings.filterwarnings("ignore", message=".*default.*deprecated.*") warnings.filterwarnings("ignore", message=".*metadata.*deprecated.*") warnings.filterwarnings("ignore", module="marshmallow.*") warnings.filterwarnings("ignore", module="dataclasses_json.*") try: from marshmallow.warnings import RemovedInMarshmallow4Warning warnings.filterwarnings("ignore", category=RemovedInMarshmallow4Warning) warnings.simplefilter("ignore", category=RemovedInMarshmallow4Warning) print("[Shim] Global warning suppression activated") except Exception: pass _active_server_instance = None # --- 1. Stream Redirector for Android UI --- class AndroidLogStream: def __init__(self, activity_context, original_stream): self.activity_context = activity_context self.original_stream = original_stream self.buffer = "" self._in_write = False def write(self, message): if self._in_write: if self.original_stream: try: self.original_stream.write(message) except Exception: pass return self._in_write = True try: if self.original_stream: try: self.original_stream.write(message) except Exception: pass self.buffer += message while "\n" in self.buffer: line, self.buffer = self.buffer.split("\n", 1) clean_line = line.strip() if clean_line and self.activity_context: try: self.activity_context.onServerLog(clean_line) except Exception: pass finally: self._in_write = False def flush(self): if self.original_stream: try: self.original_stream.flush() except Exception: pass if self.buffer.strip() and self.activity_context: try: self.activity_context.onServerLog(self.buffer.strip()) self.buffer = "" except Exception: pass # --- 2. Headless Input Mock --- def _mock_input(prompt=""): if prompt: print(f"[CLI]: {prompt}") time.sleep(2) return "" builtins.input = _mock_input # --- 3. Minimal Marshmallow Info --- try: import marshmallow print(f"[Shim] marshmallow {marshmallow.__version__}") except Exception: print("[Shim] marshmallow not available") # --- 3.1 Persistent Template & SafeDict Protection --- DEFAULT_PERSISTENT = { "send_hotfix": True, "scene": { "plane_id": 20313, "x": 40748, "y": 192819, "z": 439218, "calyx_x": 40748, "calyx_y": 192810, "calyx_z": 441000, "map_layer": 2, "calyx_group_id": 186, "calyx_inst_id": 300001, "calyx_entity_id": 1337, "calyx_prop_id": 808 }, "avatar": { "tb_gender": "Female", "tb_path": "Elation", "march_path": "Preservation", "skin": { "1001": 1100101, "1310": 1131001, "1415": 1141501, "1407": 1140701, "1501": 1150101 }, "lineup": [ 1511, 1502, 1506, 1503 ], "global_passive": [ { "name": "Castorice Global Passive", "id": 140703, "active": True }, { "name": "SW999 Global Passsive", "id": 150602, "active": True }, { "name": "Aha Global Passive", "id": 151104, "active": True } ], "ex_rank": [ { "name": "JingYuan", "avatar_id": 1204, "active": True }, { "name": "DanHeng IL", "avatar_id": 1213, "active": True }, { "name": "Acheron", "avatar_id": 1308, "active": True } ], "buff": [ 1000121 ], "leader": 0 }, "key": "" } class SafeDict(dict): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for k, v in list(self.items()): if isinstance(v, dict) and not isinstance(v, SafeDict): self[k] = SafeDict(v) def __getitem__(self, key): import copy if key not in self: if key == 'avatar': self['avatar'] = SafeDict(copy.deepcopy(DEFAULT_PERSISTENT['avatar'])) return self['avatar'] elif key == 'scene': self['scene'] = SafeDict(copy.deepcopy(DEFAULT_PERSISTENT['scene'])) return self['scene'] elif key == 'skin': self['skin'] = SafeDict(copy.deepcopy(DEFAULT_PERSISTENT['avatar']['skin'])) return self['skin'] elif key == 'lineup': self['lineup'] = copy.deepcopy(DEFAULT_PERSISTENT['avatar']['lineup']) return self['lineup'] elif key == 'buff': self['buff'] = copy.deepcopy(DEFAULT_PERSISTENT['avatar']['buff']) return self['buff'] elif key == 'global_passive': self['global_passive'] = copy.deepcopy(DEFAULT_PERSISTENT['avatar']['global_passive']) return self['global_passive'] elif key == 'ex_rank': self['ex_rank'] = copy.deepcopy(DEFAULT_PERSISTENT['avatar']['ex_rank']) return self['ex_rank'] elif key == 'tb_gender': return 'Female' elif key == 'tb_path': return 'Elation' elif key == 'march_path': return 'Preservation' elif key == 'leader': return 0 elif key == 'send_hotfix': return True elif key == 'key': return '' val = super().__getitem__(key) if isinstance(val, dict) and not isinstance(val, SafeDict): val = SafeDict(val) self[key] = val return val def _sanitize_persistent_file(persistent_file): try: import json, os, copy os.makedirs(os.path.dirname(os.path.abspath(persistent_file)), exist_ok=True) data = {} if os.path.exists(persistent_file): try: with open(persistent_file, "r", encoding="utf-8") as f: data = json.load(f) except Exception: data = {} modified = False if not isinstance(data, dict): data = {} modified = True for k, v in DEFAULT_PERSISTENT.items(): if k not in data: data[k] = copy.deepcopy(v) modified = True elif isinstance(v, dict) and isinstance(data[k], dict): for sub_k, sub_v in v.items(): if sub_k not in data[k]: data[k][sub_k] = copy.deepcopy(sub_v) modified = True if modified or not os.path.exists(persistent_file): with open(persistent_file, "w", encoding="utf-8") as f: json.dump(data, f, indent=4) print("[Patch] persistent.json validated and auto-healed with complete avatar/scene defaults") except Exception as e: print(f"[Patch Warning] sanitize persistent: {e}") # --- 4. Shutdown Logic --- def kill_server_process(): global _active_server_instance print("[Shutdown]: Force-stopping server execution...") try: import dispatch.dispatchserver as _ds if hasattr(_ds, 'DispatchServer') and hasattr(_ds.DispatchServer, 'stop'): _ds.DispatchServer.stop() except Exception: pass try: import game.gameserver as _gs if hasattr(_gs, 'GameServer') and hasattr(_gs.GameServer, 'stop'): _gs.GameServer.stop() except Exception: pass if _active_server_instance is not None: try: if hasattr(_active_server_instance, 'shutdown'): _active_server_instance.shutdown() if hasattr(_active_server_instance, 'server_close'): _active_server_instance.server_close() except Exception: pass try: sock = getattr(_active_server_instance, 'socket', None) if sock: sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0)) sock.close() except Exception: pass _active_server_instance = None try: for obj in gc.get_objects(): if isinstance(obj, socket.socket): try: obj.shutdown(socket.SHUT_RDWR) obj.close() except Exception: pass except Exception: pass try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.close() except Exception: pass time.sleep(1.2) for _ in range(5): try: _thread.interrupt_main() time.sleep(0.2) except Exception: pass # --- 5. Main Execution Entrypoint --- def run_server(ppsr_path, activity_context=None): if activity_context is not None: sys.stdout = AndroidLogStream(activity_context, sys.__stdout__) sys.stderr = AndroidLogStream(activity_context, sys.__stderr__) # Extra safety - re-apply on every start try: warnings.filterwarnings("ignore", category=RemovedInMarshmallow4Warning) except Exception: pass ppsr_dir = os.path.dirname(os.path.abspath(ppsr_path)) misc_dir = os.path.join(ppsr_dir, "misc") pkg_zip = os.path.join(ppsr_dir, "packages.zip") if os.path.exists(ppsr_dir): os.chdir(ppsr_dir) print(f"Working directory locked: {os.getcwd()}") for path in [ppsr_dir, misc_dir, pkg_zip]: if os.path.exists(path) and path not in sys.path: sys.path.insert(0, path) warnings.filterwarnings("ignore", message=".*default.*deprecated.*") warnings.filterwarnings("ignore", message=".*metadata.*deprecated.*") warnings.filterwarnings("ignore", module="marshmallow.*") warnings.filterwarnings("ignore", module="dataclasses_json.*") # Verify and auto-recover critical packages if needed for pkg_name in ["requests", "werkzeug", "flask"]: try: __import__(pkg_name) except ImportError: print(f"[Shim] Package '{pkg_name}' missing, attempting auto-install...") try: import package_fetcher package_fetcher.install_package(pkg_name, ppsr_dir) except Exception as ex: print(f"[Shim Warning] Fallback failed for {pkg_name}: {ex}") # --- Werkzeug Patch --- try: import werkzeug.serving if hasattr(werkzeug.serving, "ThreadedWSGIServer"): try: werkzeug.serving.ThreadedWSGIServer._server_version = "Werkzeug/3.1.9" except Exception: pass _orig_make_server = werkzeug.serving.make_server def _patched_make_server(*args, **kwargs): global _active_server_instance kwargs.pop('options', None) server = _orig_make_server(*args, **kwargs) try: server._server_version = "Werkzeug/3.1.9" except Exception: pass try: if hasattr(server, 'socket') and server.socket: server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except Exception: pass _active_server_instance = server print("[Server] Server instance patched and ready") return server werkzeug.serving.make_server = _patched_make_server print("[Patch] Werkzeug make_server patched successfully") except Exception as e: print(f"[Patch Warning] Werkzeug patch: {e}") # --- Persistent & Avatar Auto-healing Patch --- _persistent_file = os.path.join(misc_dir, "persistent.json") _sanitize_persistent_file(_persistent_file) try: import game.services.manager as _mgr_mod _orig_load_persistent = _mgr_mod.Manager.load_persistent @classmethod def _patched_load_persistent(cls): _orig_load_persistent() if hasattr(cls, 'persistent') and isinstance(cls.persistent, dict): cls.persistent = SafeDict(cls.persistent) _mgr_mod.Manager.load_persistent = _patched_load_persistent if hasattr(_mgr_mod.Manager, 'persistent') and isinstance(_mgr_mod.Manager.persistent, dict): _mgr_mod.Manager.persistent = SafeDict(_mgr_mod.Manager.persistent) print("[Patch] Manager.load_persistent patched with SafeDict avatar protection") except Exception as e: print(f"[Patch Warning] Manager persistent patch: {e}") try: import game.router as _router_mod _orig_router_handle = _router_mod.handle def _safe_router_handle(data): try: return _orig_router_handle(data) except Exception as e: import traceback print(f"[Router Warning] Handled exception in router.handle: {e}") traceback.print_exc() return b'' _router_mod.handle = _safe_router_handle print("[Patch] game.router.handle wrapped with crash-guard") except Exception as e: print(f"[Patch Warning] Router crash-guard: {e}") print(f"Loading bytecode target: {ppsr_path}...") with open(ppsr_path, "rb") as f: code_bytes = f.read() try: import marshal code_obj = marshal.loads(code_bytes[16:]) except Exception: code_obj = compile(code_bytes, ppsr_path, "exec") main_globals = { "__name__": "__main__", "__file__": ppsr_path, "__doc__": None, "sys": sys, "os": os, "input": _mock_input } try: exec(code_obj, main_globals) except KeyboardInterrupt: print("[System]: Server loop interrupted cleanly.") except Exception as e: print(f"[System]: Server terminated: {e}")