From 7324b6cb7985148709334f860811ec32102227da Mon Sep 17 00:00:00 2001 From: shenjack-mac <3695888@qq.com> Date: Sun, 14 May 2023 15:49:27 +0800 Subject: [PATCH 1/6] use mod console --- Difficult_Rocket/client/__init__.py | 8 ++++++-- mods/dr_game/sr1_ship.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Difficult_Rocket/client/__init__.py b/Difficult_Rocket/client/__init__.py index 14568ae..259438b 100644 --- a/Difficult_Rocket/client/__init__.py +++ b/Difficult_Rocket/client/__init__.py @@ -211,7 +211,7 @@ class ClientWindow(Window): def start_game(self) -> None: self.set_icon(pyglet.image.load('./textures/icon.png')) self.run_input = True - self.read_input() + # self.read_input() try: pyglet.app.event_loop.run(1 / self.main_config['runtime']['fps']) except KeyboardInterrupt: @@ -314,6 +314,7 @@ class ClientWindow(Window): self.logger.info(tr().window.command.text().format(command)) if command.re_match('stop'): # self.dispatch_event('on_exit') + print("command stop!") pyglet.app.platform_event_loop.stop() self.dispatch_event('on_close', 'command') # source = command elif command.re_match('fps'): @@ -439,10 +440,13 @@ class ClientWindow(Window): self.game.dispatch_event('on_close', game=self.game, client=self, source=source) self.logger.info(tr().window.game.stop_get().format(tr().game[source]())) self.logger.info(tr().window.game.stop()) - self.fps_log.check_list = False + # self.fps_log.check_list = False DR_runtime.running = False if self.run_input: self.run_input = False self.save_info() super().on_close() self.logger.info(tr().window.game.end()) + + +ClientWindow.register_event_type("on_command") diff --git a/mods/dr_game/sr1_ship.py b/mods/dr_game/sr1_ship.py index 6a46b49..454d2bf 100644 --- a/mods/dr_game/sr1_ship.py +++ b/mods/dr_game/sr1_ship.py @@ -36,7 +36,7 @@ if TYPE_CHECKING: from Difficult_Rocket.client import ClientWindow if DR_mod_runtime.use_DR_rust: - from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs + from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, Console_rs logger = logging.getLogger('client') @@ -135,6 +135,7 @@ class SR1ShipRender(BaseScreen): min_zoom=(1 / 2) ** 10, max_zoom=10) self.rust_parts = None self.part_list_rs = SR1PartList_rs('configs/PartList.xml', 'default_part_list') + self.console = Console_rs() def load_xml(self, file_path: str) -> bool: try: @@ -270,6 +271,11 @@ class SR1ShipRender(BaseScreen): self.debug_mouse_label.draw() if SR1ShipRender_Option.debug_mouse_d_pos: self.debug_mouse_delta_line.draw() + if DR_mod_runtime.use_DR_rust: + read_input = self.console.get_command() + if read_input: + print(f"Rust console: |{read_input}|") + window.dispatch_event("on_command", CommandText(read_input)) def on_resize(self, width: int, height: int, window: "ClientWindow"): if not self.rendered: @@ -381,6 +387,9 @@ class SR1ShipRender(BaseScreen): if self.load_xml(path): # 加载成功一个就停下 break self.render_ship() + + def on_close(self, window: "ClientWindow"): + self.console.stop_console() if __name__ == '__main__': -- 2.45.2 From 41197b65f78c855a6fe133b943f893f97be681c6 Mon Sep 17 00:00:00 2001 From: shenjack-mac <3695888@qq.com> Date: Sun, 14 May 2023 18:44:25 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=88=91=E4=B9=9F=E4=B8=8D=E6=B8=85?= =?UTF-8?q?=E6=A5=9A=E6=94=B9=E4=BA=86=E5=95=A5=EF=BC=8C=E4=BD=86=E6=98=AF?= =?UTF-8?q?=E5=8F=8D=E6=AD=A3=E6=88=91=E4=B8=8D=E7=AE=A1=EF=BC=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Difficult_Rocket/main.py | 128 +++++++++++++++++- mods/dr_game/Difficult_Rocket_rs/__init__.py | 3 +- .../Difficult_Rocket_rs/src/src/python.rs | 36 +++-- mods/dr_game/__init__.py | 11 +- mods/dr_game/console.py | 24 ++++ 5 files changed, 183 insertions(+), 19 deletions(-) create mode 100644 mods/dr_game/console.py diff --git a/Difficult_Rocket/main.py b/Difficult_Rocket/main.py index 1318e7b..50ca58d 100644 --- a/Difficult_Rocket/main.py +++ b/Difficult_Rocket/main.py @@ -22,7 +22,7 @@ import multiprocessing from io import StringIO from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, List, Optional, Dict, TypeVar if __name__ == '__main__': # been start will not run this sys.path.append('/bin/libs') @@ -31,9 +31,13 @@ if __name__ == '__main__': # been start will not run this from Difficult_Rocket import client, server, DR_option, DR_runtime if TYPE_CHECKING: from Difficult_Rocket.api.mod import ModInfo -from Difficult_Rocket.crash import write_info_to_cache +else: + ModInfo = TypeVar('ModInfo') from Difficult_Rocket.utils import tools from Difficult_Rocket.utils.translate import tr +from Difficult_Rocket.crash import write_info_to_cache +from Difficult_Rocket.api.types import Options +from Difficult_Rocket.utils.thread import new_thread class Game: @@ -114,7 +118,7 @@ class Game: module.append(mod_class) self.logger.info(tr().main.mod.load.info().format(mod_class.mod_id, mod_class.version)) except ImportError as e: - self.logger.warning(tr().main.mod.load.faild().format(mod, e)) + self.logger.warning(tr().main.mod.load.faild.info().format(mod, e)) self.logger.info(tr().main.mod.load.done()) self.loaded_mods = module mod_list = [] @@ -163,3 +167,121 @@ class Game: def start(self) -> None: self._start() + + +class Console(Options): + name = 'python stdin console' + + running: bool = False + + @new_thread('python console', daemon=True, log_thread=True) + def main(self): + while self.running: + try: + get_str = input('>>>') + except (EOFError, KeyboardInterrupt): + get_str = 'stop' + self.caches.append(get_str) + if get_str == 'stop': + self.running = False + break + + def start(self): + self.running = True + self.caches: List[str] = [] + self.main() + + def stop(self): + self.running = False + + def get_command(self) -> str: + return self.caches.pop(0) + + +class MainGame(Options): + name = 'MainGame' + + client: client.Client + server: server.Server + console: Console + + main_config: Dict + logger: logging.Logger + + mod_module: List["ModInfo"] + + def init_logger(self) -> None: + ... + + def init_console(self) -> None: + self.console = Console() + self.console.start() + + def init_mods(self) -> None: + """验证/加载 mod""" + mods = [] + mod_path = Path(DR_runtime.mod_path) + if not mod_path.exists(): + self.logger.info(tr().main.mod.find.faild.no_mod_folder()) + return + # 寻找有效 mod + paths = mod_path.iterdir() + sys.path.append(DR_runtime.mod_path) + for mod_path in paths: + try: + if mod_path.name == '__pycache__': + continue + self.logger.info(tr().main.mod.find.start().format(mod_path)) + if mod_path.is_dir(): + if importlib.util.find_spec(mod_path.name) is not None: + mods.append(mod_path.name) + else: + self.logger.warning(tr().main.mod.load.faild.info().format(mod_path.name, tr().main.mod.find.faild.no_spec())) + elif mod_path.suffix in ('.pyz', '.zip', '.pyd', '.py'): + if importlib.util.find_spec(mod_path.name) is not None: + mods.append(mod_path.name) + except ImportError as e: + self.logger.warning(tr().main.mod.find.faild().format(mod_path, e)) + self.logger.info(tr().main.mod.find.done()) + # 加载有效 mod + module = [] + for mod in mods: + try: + self.logger.info(tr().main.mod.load.start().format(mod)) + mod_module = importlib.import_module(mod) + if not hasattr(mod_module, "mod_class"): + self.logger.warning(tr().main.mod.load.faild.info().format(mod, tr().main.mod.load.faild.no_mod_class())) + del mod_module # 释放内存 + continue + mod_class: type(ModInfo) = mod_module.mod_class + mod_class = mod_class() + module.append(mod_class) + self.logger.info(tr().main.mod.load.info().format(mod_class.mod_id, mod_class.version)) + except ImportError as e: + self.logger.warning(tr().main.mod.load.faild.info().format(mod, e)) + self.logger.info(tr().main.mod.load.done()) + self.mod_module = module + mod_list = [] + for mod in module: + mod_list.append((mod.mod_id, mod.version)) + # 调用 on_load + self.dispatch_event('on_load', game=self) + DR_runtime.DR_Mod_List = mod_list + + def dispatch_event(self, event_name: str, *args, **kwargs) -> None: + """向 mod 分发事件""" + for mod in self.mod_module: + if hasattr(mod, event_name): + try: + getattr(mod, event_name)(*args, **kwargs) + except Exception as e: + self.logger.error(tr().main.mod.event.error().format(event_name, e, mod.mod_id)) + + def init(self, **kwargs) -> None: + ... + + def load_file(self) -> bool: + """加载文件""" + self.init_logger() + self.init_mods() + return True diff --git a/mods/dr_game/Difficult_Rocket_rs/__init__.py b/mods/dr_game/Difficult_Rocket_rs/__init__.py index f1d1832..94c6dd5 100644 --- a/mods/dr_game/Difficult_Rocket_rs/__init__.py +++ b/mods/dr_game/Difficult_Rocket_rs/__init__.py @@ -104,5 +104,6 @@ if TYPE_CHECKING: class Console_rs: def __init__(self) -> None: ... - def stop_console(self) -> None: ... + def start(self) -> None: ... + def stop(self) -> bool: ... def get_command(self) -> Optional[str]: ... diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs index 4564c46..56494b8 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs @@ -176,15 +176,21 @@ pub mod console { #[pyo3(name = "Console_rs")] pub struct PyConsole { /// 向子线程发送结束信号 - pub stop_sender: std::sync::mpsc::Sender<()>, - /// - pub keyboard_input_receiver: std::sync::mpsc::Receiver, + pub stop_sender: Option>, + pub keyboard_input_receiver: Option>, } #[pymethods] impl PyConsole { #[new] fn new() -> Self { + Self { + stop_sender: None, + keyboard_input_receiver: None, + } + } + + fn start(&mut self) { let (stop_sender, stop_receiver) = std::sync::mpsc::channel(); let (keyboard_input_sender, keyboard_input_receiver) = std::sync::mpsc::channel(); std::thread::spawn(move || { @@ -194,27 +200,31 @@ pub mod console { break; } let mut input = String::new(); - print!(">>"); let _ = std_in.read_line(&mut input); if !input.is_empty() { keyboard_input_sender.send(input).unwrap(); } + print!(">>"); } }); - - Self { - stop_sender, - keyboard_input_receiver, - } + self.stop_sender = Some(stop_sender); + self.keyboard_input_receiver = Some(keyboard_input_receiver); } - fn stop_console(&self) { self.stop_sender.send(()).unwrap(); } + fn stop(&self) -> bool { + if let (Some(sender)) = &self.stop_sender { + sender.send(()).unwrap(); + return true; + } + false + } fn get_command(&self) -> Option { // 获取输入 - if let Ok(string) = self.keyboard_input_receiver.try_recv() { - println!("rust recv input: {}", string); - return Some(string); + if let (Some(receiver)) = &self.keyboard_input_receiver { + if let Ok(string) = receiver.try_recv() { + return Some(string); + } } None } diff --git a/mods/dr_game/__init__.py b/mods/dr_game/__init__.py index 79ab6f6..19ad067 100644 --- a/mods/dr_game/__init__.py +++ b/mods/dr_game/__init__.py @@ -9,9 +9,8 @@ import traceback from typing import Optional - from libs.MCDR.version import Version -from Difficult_Rocket.main import Game +from Difficult_Rocket.main import Game, Console from Difficult_Rocket.api.mod import ModInfo from Difficult_Rocket.api.types import Options from Difficult_Rocket.client import ClientWindow @@ -68,6 +67,14 @@ class DR_mod(ModInfo): def on_load(self, game: Game, old_self: Optional["DR_mod"] = None) -> bool: if not DR_mod_runtime.DR_rust_available: return False + from .console import RustConsole + + def init_console(self) -> None: + self.console = RustConsole() + self.console.start() + + game.init_console = init_console # 替换掉原来的 init_console 函数 + if old_self: game.client.window.add_sub_screen("SR1_ship", old_self.screen) else: diff --git a/mods/dr_game/console.py b/mods/dr_game/console.py new file mode 100644 index 0000000..62f88f8 --- /dev/null +++ b/mods/dr_game/console.py @@ -0,0 +1,24 @@ +from . import DR_mod_runtime +from Difficult_Rocket.main import Console + +if DR_mod_runtime.use_DR_rust: + from .Difficult_Rocket_rs import Console_rs + + +class RustConsole(Console): + name = 'Rust stdin Console' + + running: bool = False + console: Console_rs + + def start(self): + self.console.start() + + def stop(self): + return self.console.stop() + + def init(self, **kwargs) -> None: + self.console = Console_rs() + + def get_command(self) -> str: + return self.console.get_command() -- 2.45.2 From 0cb5b54eb71505104fc6db0ef08e6d3dd6740fc0 Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Sun, 14 May 2023 20:23:20 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E5=AE=8C=E5=96=84=20MainGame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Difficult_Rocket/__init__.py | 1 + Difficult_Rocket/main.py | 47 +++++++++++++++---- Difficult_Rocket/utils/options.py | 11 +++-- configs/logger.toml | 1 - .../Difficult_Rocket_rs/src/src/lib.rs | 12 ++--- .../Difficult_Rocket_rs/src/src/python.rs | 4 +- mods/dr_game/__init__.py | 2 +- 7 files changed, 56 insertions(+), 22 deletions(-) diff --git a/Difficult_Rocket/__init__.py b/Difficult_Rocket/__init__.py index f654bda..fefefe9 100644 --- a/Difficult_Rocket/__init__.py +++ b/Difficult_Rocket/__init__.py @@ -5,6 +5,7 @@ # ------------------------------- import sys +import time import importlib import traceback import contextlib diff --git a/Difficult_Rocket/main.py b/Difficult_Rocket/main.py index 50ca58d..77081c0 100644 --- a/Difficult_Rocket/main.py +++ b/Difficult_Rocket/main.py @@ -15,6 +15,7 @@ import os import sys import time import logging +import traceback import importlib import importlib.util import logging.config @@ -28,16 +29,16 @@ if __name__ == '__main__': # been start will not run this sys.path.append('/bin/libs') sys.path.append('/bin') -from Difficult_Rocket import client, server, DR_option, DR_runtime if TYPE_CHECKING: from Difficult_Rocket.api.mod import ModInfo else: ModInfo = TypeVar('ModInfo') from Difficult_Rocket.utils import tools -from Difficult_Rocket.utils.translate import tr -from Difficult_Rocket.crash import write_info_to_cache from Difficult_Rocket.api.types import Options +from Difficult_Rocket.utils.translate import tr from Difficult_Rocket.utils.thread import new_thread +from Difficult_Rocket.crash import write_info_to_cache +from Difficult_Rocket import client, server, DR_option, DR_runtime class Game: @@ -206,12 +207,23 @@ class MainGame(Options): console: Console main_config: Dict + logging_config: Dict logger: logging.Logger mod_module: List["ModInfo"] def init_logger(self) -> None: - ... + log_path = self.logging_config['handlers']['file']['filename'] + log_path = Path(f"logs/{log_path.format(time.strftime('%Y-%m-%d %H-%M-%S' , time.gmtime(DR_runtime.start_time_ns)))}") + mkdir = False + if not log_path.exists(): + log_path.mkdir(parents=True) + mkdir = True + self.logging_config['handlers']['file']['filename'] = log_path.name + logging.config.dictConfig(self.logging_config) + self.logger = logging.getLogger('main') + if mkdir: + self.logger.info(tr().main.logger.mkdir()) def init_console(self) -> None: self.console = Console() @@ -274,14 +286,33 @@ class MainGame(Options): if hasattr(mod, event_name): try: getattr(mod, event_name)(*args, **kwargs) - except Exception as e: - self.logger.error(tr().main.mod.event.error().format(event_name, e, mod.mod_id)) + except Exception: + error = traceback.format_exc() + self.logger.error(tr().main.mod.event.error().format(event_name, error, mod.mod_id)) - def init(self, **kwargs) -> None: - ... + def log_env(self) -> None: + cache_steam = StringIO() + write_info_to_cache(cache_steam) + text = cache_steam.getvalue() + self.logger.info(text) + self.flush_option() + self.logger.info(self.as_markdown()) + + def setup(self) -> None: + self.client = client.Client(game=self, net_mode='local') + self.server = server.Server(net_mode='local') + + def init(self, **kwargs) -> bool: + self.load_file() + self.setup() + self.log_env() + return True def load_file(self) -> bool: """加载文件""" + self.logging_config = tools.load_file('configs/logger.toml') self.init_logger() self.init_mods() + self.init_console() return True + diff --git a/Difficult_Rocket/utils/options.py b/Difficult_Rocket/utils/options.py index b8586e9..8ec927b 100644 --- a/Difficult_Rocket/utils/options.py +++ b/Difficult_Rocket/utils/options.py @@ -66,9 +66,10 @@ class Options: if option not in self.cached_options: raise OptionNameNotDefined(f"option: {option} with value: {value} is not defined") setattr(self, option, value) + run_load_file = True if hasattr(self, 'init'): - self.init(**kwargs) - if hasattr(self, 'load_file'): + run_load_file = not self.init(**kwargs) # 默认 False/None + if hasattr(self, 'load_file') and run_load_file: try: self.load_file() except Exception: @@ -78,8 +79,10 @@ class Options: if TYPE_CHECKING: _options: Dict[str, Union[Callable, object]] = {} - def init(self, **kwargs) -> None: - """ 如果子类定义了这个函数,则会在 __init__ 之后调用这个函数 """ + def init(self, **kwargs) -> bool: + """ 如果子类定义了这个函数,则会在 __init__ 之后调用这个函数 + 返回值为 True 则不会调用 load_file 函数 + """ def load_file(self) -> bool: """如果子类定义了这个函数,则会在 __init__ 和 init 之后再调用这个函数 diff --git a/configs/logger.toml b/configs/logger.toml index 927a7cd..5a65de0 100644 --- a/configs/logger.toml +++ b/configs/logger.toml @@ -27,7 +27,6 @@ level = "DEBUG" [handlers.file] class = "logging.FileHandler" filename = "{} DR.log" -datefmt = "%Y-%m-%d %H:%M:%S" encoding = "utf-8" formatter = "file" level = "DEBUG" diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs index 861fd2e..c40b0b5 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs @@ -19,15 +19,15 @@ use pyo3::prelude::*; // const MOD_PATH: String = String::from("mods"); enum LoadState { - init, - wait_start, - pre_start, - running, - clean, + Init, + WaitStart, + PreStart, + Running, + Clean, } #[pyfunction] -fn get_version_str() -> String { "0.2.7.0".to_string() } +fn get_version_str() -> String { "0.2.8.0".to_string() } #[pyfunction] fn test_call(py_obj: &PyAny) -> PyResult { diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs index 56494b8..32cccc2 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs @@ -212,7 +212,7 @@ pub mod console { } fn stop(&self) -> bool { - if let (Some(sender)) = &self.stop_sender { + if let Some(sender) = &self.stop_sender { sender.send(()).unwrap(); return true; } @@ -221,7 +221,7 @@ pub mod console { fn get_command(&self) -> Option { // 获取输入 - if let (Some(receiver)) = &self.keyboard_input_receiver { + if let Some(receiver) = &self.keyboard_input_receiver { if let Ok(string) = receiver.try_recv() { return Some(string); } diff --git a/mods/dr_game/__init__.py b/mods/dr_game/__init__.py index 19ad067..48fee02 100644 --- a/mods/dr_game/__init__.py +++ b/mods/dr_game/__init__.py @@ -15,7 +15,7 @@ from Difficult_Rocket.api.mod import ModInfo from Difficult_Rocket.api.types import Options from Difficult_Rocket.client import ClientWindow -DR_rust_version = Version("0.2.7.0") # DR_mod 的 Rust 编写部分的兼容版本 +DR_rust_version = Version("0.2.8.0") # DR_mod 的 Rust 编写部分的兼容版本 class _DR_mod_runtime(Options): -- 2.45.2 From 2d558889f4f90368d5cc0babf4af733299335c9d Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Sun, 14 May 2023 20:42:18 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E9=87=8D=E6=9E=84=20Game=20obj?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Difficult_Rocket/main.py | 167 +++--------------- Difficult_Rocket/utils/options.py | 3 +- .../Difficult_Rocket_rs/src/src/lib.rs | 1 + mods/dr_game/__init__.py | 6 +- mods/dr_game/sr1_ship.py | 11 +- 5 files changed, 33 insertions(+), 155 deletions(-) diff --git a/Difficult_Rocket/main.py b/Difficult_Rocket/main.py index 77081c0..7f86288 100644 --- a/Difficult_Rocket/main.py +++ b/Difficult_Rocket/main.py @@ -11,7 +11,6 @@ github: @shenjackyuanjie gitee: @shenjackyuanjie """ -import os import sys import time import logging @@ -41,135 +40,6 @@ from Difficult_Rocket.crash import write_info_to_cache from Difficult_Rocket import client, server, DR_option, DR_runtime -class Game: - def __init__(self): - # basic config - self.on_python_v_info = sys.version_info - self.on_python_v = sys.version.split(' ')[0] - self.start_time = time.strftime('%Y-%m-%d %H-%M-%S', time.gmtime(time.time())) - # lang_config - self.language = tools.load_file('configs/main.toml', 'runtime')['language'] - DR_option.language = self.language - # logging config - log_config = tools.load_file('configs/logger.toml') - file_name = log_config['handlers']['file']['filename'] - del log_config['handlers']['file']['datefmt'] - log_config['handlers']['file']['filename'] = f'logs/{file_name.format(self.start_time)}' - try: - logging.config.dictConfig(log_config) - self.logger = logging.getLogger('main') - except ValueError: # it should be no 'logs/' folder - os.mkdir('logs') - logging.config.dictConfig(log_config) - self.logger = logging.getLogger('main') - self.logger.info(tr().main.logger.mkdir()) - self.logger.info(tr().language_set_to()) - self.logger.info(tr().main.logger.created()) - # version check - self.log_env() - self.python_version_check() - self.loaded_mods = [] - # self.client = client.Client - # self.server = server.Server - self.setup() - - def log_env(self) -> None: - cache_steam = StringIO() - write_info_to_cache(cache_steam) - text = cache_steam.getvalue() - self.logger.info(text) - - def load_mods(self) -> None: - mods = [] - mod_path = Path(DR_runtime.mod_path) - if not mod_path.exists(): - self.logger.info(tr().main.mod.find.faild.no_mod_folder()) - return - # 寻找有效 mod - paths = mod_path.iterdir() - sys.path.append(DR_runtime.mod_path) - for mod_path in paths: - try: - if mod_path.name == '__pycache__': - continue - self.logger.info(tr().main.mod.find.start().format(mod_path)) - if mod_path.is_dir(): - if importlib.util.find_spec(mod_path.name) is not None: - mods.append(mod_path.name) - else: - self.logger.warning(tr().main.mod.load.faild.info().format(mod_path.name, tr().main.mod.find.faild.no_spec())) - elif mod_path.suffix in ('.pyz', '.zip', '.pyd', '.py'): - if importlib.util.find_spec(mod_path.name) is not None: - mods.append(mod_path.name) - except ImportError as e: - self.logger.warning(tr().main.mod.find.faild().format(mod_path, e)) - self.logger.info(tr().main.mod.find.done()) - # 加载有效 mod - module = [] - for mod in mods: - try: - self.logger.info(tr().main.mod.load.start().format(mod)) - mod_module = importlib.import_module(mod) - if not hasattr(mod_module, "mod_class"): - self.logger.warning(tr().main.mod.load.faild.info().format(mod, tr().main.mod.load.faild.no_mod_class())) - del mod_module # 释放内存 - continue - mod_class: type(ModInfo) = mod_module.mod_class - mod_class = mod_class() - module.append(mod_class) - self.logger.info(tr().main.mod.load.info().format(mod_class.mod_id, mod_class.version)) - except ImportError as e: - self.logger.warning(tr().main.mod.load.faild.info().format(mod, e)) - self.logger.info(tr().main.mod.load.done()) - self.loaded_mods = module - mod_list = [] - for mod in module: - mod_list.append((mod.mod_id, mod.version)) - # 调用 on_load - self.dispatch_event('on_load', game=self) - DR_runtime.DR_Mod_List = mod_list - - def dispatch_event(self, event_name: str, *args, **kwargs) -> None: - for mod in self.loaded_mods: - if hasattr(mod, event_name): - try: - getattr(mod, event_name)(*args, **kwargs) - except Exception as e: - self.logger.error(tr().main.mod.event.error().format(event_name, e, mod.mod_id)) - - def setup(self) -> None: - self.load_mods() - self.client = client.Client(game=self, net_mode='local') - self.server = server.Server(net_mode='local') - - def python_version_check(self) -> None: # best 3.8+ and write at 3.8.10 - self.logger.info(f"{tr().main.version.now_on()} {self.on_python_v}") - if self.on_python_v_info[0] == 2: - self.logger.critical(tr().main.version.need3p()) - raise SystemError(tr().main.version.need3p()) - elif self.on_python_v_info[1] < 8: - warning = tools.name_handler(tr.main.version.best38p()) - self.logger.warning(warning) - - # @new_thread('main') - def _start(self): - self.server.run() - if DR_option.use_multiprocess: - try: - game_process = multiprocessing.Process(target=self.client.start, name='pyglet app') - game_process.start() - game_process.join() - except Exception: - return -1 - else: - return 1 - else: - self.client.start() - - def start(self) -> None: - self._start() - - class Console(Options): name = 'python stdin console' @@ -199,12 +69,13 @@ class Console(Options): return self.caches.pop(0) -class MainGame(Options): +class Game(Options): name = 'MainGame' client: client.Client server: server.Server console: Console + console_class: Console = Console main_config: Dict logging_config: Dict @@ -214,23 +85,20 @@ class MainGame(Options): def init_logger(self) -> None: log_path = self.logging_config['handlers']['file']['filename'] - log_path = Path(f"logs/{log_path.format(time.strftime('%Y-%m-%d %H-%M-%S' , time.gmtime(DR_runtime.start_time_ns)))}") + log_path = Path(f"logs/{log_path.format(time.strftime('%Y-%m-%d %H-%M-%S' , time.gmtime(DR_runtime.start_time_ns / 1000_000_000)))}") mkdir = False - if not log_path.exists(): + if not Path("logs/").exists(): log_path.mkdir(parents=True) mkdir = True - self.logging_config['handlers']['file']['filename'] = log_path.name + self.logging_config['handlers']['file']['filename'] = str(log_path.absolute()) logging.config.dictConfig(self.logging_config) self.logger = logging.getLogger('main') if mkdir: self.logger.info(tr().main.logger.mkdir()) - def init_console(self) -> None: - self.console = Console() - self.console.start() - def init_mods(self) -> None: """验证/加载 mod""" + print(self) mods = [] mod_path = Path(DR_runtime.mod_path) if not mod_path.exists(): @@ -280,6 +148,24 @@ class MainGame(Options): self.dispatch_event('on_load', game=self) DR_runtime.DR_Mod_List = mod_list + def init_console(self) -> None: + self.console = Console() + self.console.start() + + def start(self): + self.server.run() + if DR_option.use_multiprocess: + try: + game_process = multiprocessing.Process(target=self.client.start, name='pyglet app') + game_process.start() + game_process.join() + except Exception: + return -1 + else: + return 1 + else: + self.client.start() + def dispatch_event(self, event_name: str, *args, **kwargs) -> None: """向 mod 分发事件""" for mod in self.mod_module: @@ -296,7 +182,10 @@ class MainGame(Options): text = cache_steam.getvalue() self.logger.info(text) self.flush_option() - self.logger.info(self.as_markdown()) + config_cache = self.logging_config.copy() + self.logging_config = {"logging_config": "too long to show"} + self.logger.info(f"\n{self.as_markdown()}") + self.logging_config = config_cache def setup(self) -> None: self.client = client.Client(game=self, net_mode='local') diff --git a/Difficult_Rocket/utils/options.py b/Difficult_Rocket/utils/options.py index 8ec927b..1be17c2 100644 --- a/Difficult_Rocket/utils/options.py +++ b/Difficult_Rocket/utils/options.py @@ -68,7 +68,8 @@ class Options: setattr(self, option, value) run_load_file = True if hasattr(self, 'init'): - run_load_file = not self.init(**kwargs) # 默认 False/None + run_load_file = self.init(**kwargs) # 默认 False/None + run_load_file = not run_load_file if hasattr(self, 'load_file') and run_load_file: try: self.load_file() diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs index c40b0b5..97c570f 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs @@ -18,6 +18,7 @@ use pyo3::prelude::*; // const MOD_PATH: String = String::from("mods"); +#[allow(unused)] enum LoadState { Init, WaitStart, diff --git a/mods/dr_game/__init__.py b/mods/dr_game/__init__.py index 48fee02..712c039 100644 --- a/mods/dr_game/__init__.py +++ b/mods/dr_game/__init__.py @@ -69,11 +69,7 @@ class DR_mod(ModInfo): return False from .console import RustConsole - def init_console(self) -> None: - self.console = RustConsole() - self.console.start() - - game.init_console = init_console # 替换掉原来的 init_console 函数 + game.console_class = RustConsole # 替换掉原来的 console 类 if old_self: game.client.window.add_sub_screen("SR1_ship", old_self.screen) diff --git a/mods/dr_game/sr1_ship.py b/mods/dr_game/sr1_ship.py index 454d2bf..6a46b49 100644 --- a/mods/dr_game/sr1_ship.py +++ b/mods/dr_game/sr1_ship.py @@ -36,7 +36,7 @@ if TYPE_CHECKING: from Difficult_Rocket.client import ClientWindow if DR_mod_runtime.use_DR_rust: - from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, Console_rs + from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs logger = logging.getLogger('client') @@ -135,7 +135,6 @@ class SR1ShipRender(BaseScreen): min_zoom=(1 / 2) ** 10, max_zoom=10) self.rust_parts = None self.part_list_rs = SR1PartList_rs('configs/PartList.xml', 'default_part_list') - self.console = Console_rs() def load_xml(self, file_path: str) -> bool: try: @@ -271,11 +270,6 @@ class SR1ShipRender(BaseScreen): self.debug_mouse_label.draw() if SR1ShipRender_Option.debug_mouse_d_pos: self.debug_mouse_delta_line.draw() - if DR_mod_runtime.use_DR_rust: - read_input = self.console.get_command() - if read_input: - print(f"Rust console: |{read_input}|") - window.dispatch_event("on_command", CommandText(read_input)) def on_resize(self, width: int, height: int, window: "ClientWindow"): if not self.rendered: @@ -387,9 +381,6 @@ class SR1ShipRender(BaseScreen): if self.load_xml(path): # 加载成功一个就停下 break self.render_ship() - - def on_close(self, window: "ClientWindow"): - self.console.stop_console() if __name__ == '__main__': -- 2.45.2 From 1ca49485f0c81ddd01ea8c4bb944abdfdfe8f408 Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Sun, 14 May 2023 20:56:19 +0800 Subject: [PATCH 5/6] Add CommandText.find --- Difficult_Rocket/client/__init__.py | 40 ++++++++--------------------- Difficult_Rocket/command/api.py | 9 ++++++- Difficult_Rocket/main.py | 2 +- docs/src/update_logs.md | 11 ++++++++ 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Difficult_Rocket/client/__init__.py b/Difficult_Rocket/client/__init__.py index 259438b..16a28d2 100644 --- a/Difficult_Rocket/client/__init__.py +++ b/Difficult_Rocket/client/__init__.py @@ -210,8 +210,6 @@ class ClientWindow(Window): def start_game(self) -> None: self.set_icon(pyglet.image.load('./textures/icon.png')) - self.run_input = True - # self.read_input() try: pyglet.app.event_loop.run(1 / self.main_config['runtime']['fps']) except KeyboardInterrupt: @@ -221,22 +219,6 @@ class ClientWindow(Window): self.dispatch_event("on_close") sys.exit(0) - @new_thread('window read_input', daemon=True) - def read_input(self): - self.logger.debug('read_input start') - while self.run_input: - try: - get = input(">") - except (EOFError, KeyboardInterrupt): - self.run_input = False - break - if get in ('', ' ', '\n', '\r'): - continue - if get == 'stop': - self.run_input = False - self.command_list.append(get) - self.logger.debug('read_input end') - @new_thread('window save_info') def save_info(self): self.logger.info(tr().client.config.save.start()) @@ -266,10 +248,8 @@ class ClientWindow(Window): @_call_screen_after def on_draw(self, *dt): - if self.command_list: - for command in self.command_list: - self.on_command(line.CommandText(command)) - self.command_list.pop(0) + while command := self.game.console.get_command(): + self.on_command(line.CommandText(command)) pyglet.gl.glClearColor(0.1, 0, 0, 0.0) self.clear() self.draw_update(float(self.SPF)) @@ -310,26 +290,26 @@ class ClientWindow(Window): @_call_screen_after def on_command(self, command: line.CommandText): - print(command.re_match('/')) + print(command.find('/')) self.logger.info(tr().window.command.text().format(command)) - if command.re_match('stop'): + if command.find('stop'): # self.dispatch_event('on_exit') print("command stop!") pyglet.app.platform_event_loop.stop() self.dispatch_event('on_close', 'command') # source = command - elif command.re_match('fps'): - if command.re_match('log'): + elif command.find('fps'): + if command.find('log'): self.logger.debug(self.fps_log.fps_list) - elif command.re_match('max'): + elif command.find('max'): self.logger.info(self.fps_log.max_fps) self.command.push_line(self.fps_log.max_fps, block_line=True) - elif command.re_match('min'): + elif command.find('min'): self.logger.info(self.fps_log.min_fps) self.command.push_line(self.fps_log.min_fps, block_line=True) - elif command.re_match('default'): + elif command.find('default'): self.set_size(int(self.main_config['window_default']['width']), int(self.main_config['window_default']['height'])) - elif command.re_match('lang'): + elif command.find('lang'): try: lang = command.text[5:] tr._language = lang diff --git a/Difficult_Rocket/command/api.py b/Difficult_Rocket/command/api.py index 0ddbf27..b9b770a 100644 --- a/Difficult_Rocket/command/api.py +++ b/Difficult_Rocket/command/api.py @@ -43,7 +43,14 @@ class CommandText: break i += 1 - def find(self, text: str) -> Union[str, bool]: + def find(self, text: str) -> bool: + find = self.text.find(text) + if find != -1: + self.text = self.text[find + len(text):] + return True + return False + + def re_find(self, text: str) -> Union[str, bool]: return finding.group() if (finding := re.match(text, self.text)) else False def re_match(self, text: str) -> bool: diff --git a/Difficult_Rocket/main.py b/Difficult_Rocket/main.py index 7f86288..383117c 100644 --- a/Difficult_Rocket/main.py +++ b/Difficult_Rocket/main.py @@ -149,7 +149,7 @@ class Game(Options): DR_runtime.DR_Mod_List = mod_list def init_console(self) -> None: - self.console = Console() + self.console = self.console_class() self.console.start() def start(self): diff --git a/docs/src/update_logs.md b/docs/src/update_logs.md index f299b20..c41eab8 100644 --- a/docs/src/update_logs.md +++ b/docs/src/update_logs.md @@ -114,6 +114,13 @@ - 修改 返回值 类型+类型注释 - Modify the return value type + type annotation - `List[Union[List[Tuple[str, Any, Any]], int, Any]]:` -> `Tuple[List[Tuple[str, Union[Any, Type], Type]], int, int, int]` +- `Difficult_Roocket.main.Game` + - 使用 `Options` 完全重构 + - 分离 `init mods` `init console` `init logger` `load_file` + - Completely refactored using `Options` + - Separate `init mods` `init console` `init logger` `load_file` +- `Difficult_Rocket.command.api.CommandText` + - `find` -> `re_find` ### Add @@ -122,6 +129,10 @@ - 用于方便的用人类可读的 Markdown 格式 直接输出一个已经实例化的 `Options` 类的所有字段 - Add `as_markdown` method - Used to easily output all fields of an instantiated `Options` class in a human-readable Markdown format +- `Difficult_Rocket.command.api.CommandText` + - 添加基于 `str.find` 的 `find(text: str) -> bool` 方法 + - Add method `find(text: str)` based on `str.find` + ### Docs -- 2.45.2 From e46caea2937e6d5fd920bc84d5176d03bd1d38fe Mon Sep 17 00:00:00 2001 From: shenjack <3695888@qq.com> Date: Sun, 14 May 2023 20:59:04 +0800 Subject: [PATCH 6/6] docs update [build skip] [build rs skip] --- docs/src/update_logs.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/update_logs.md b/docs/src/update_logs.md index c41eab8..3725763 100644 --- a/docs/src/update_logs.md +++ b/docs/src/update_logs.md @@ -59,6 +59,9 @@ - `get_box(&self, part_type: &SR1PartType) -> (f64, f64, f64, f64)` - `types::SR1Ship` - `from_file` +- 添加了 `Console_rs` + - 用于使用 Rust 多线程读取 stdin + - Use Rust mutithread to read stdin ### Remove -- 2.45.2