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()