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/client/__init__.py b/Difficult_Rocket/client/__init__.py index 14568ae..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,25 +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 @@ -439,10 +420,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/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 1318e7b..383117c 100644 --- a/Difficult_Rocket/main.py +++ b/Difficult_Rocket/main.py @@ -11,10 +11,10 @@ github: @shenjackyuanjie gitee: @shenjackyuanjie """ -import os import sys import time import logging +import traceback import importlib import importlib.util import logging.config @@ -22,59 +22,83 @@ 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') sys.path.append('/bin') -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.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: - 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') +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 Game(Options): + name = 'MainGame' + + client: client.Client + server: server.Server + console: Console + console_class: 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 / 1000_000_000)))}") + mkdir = False + if not Path("logs/").exists(): + log_path.mkdir(parents=True) + mkdir = True + 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()) - 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: + def init_mods(self) -> None: + """验证/加载 mod""" + print(self) mods = [] mod_path = Path(DR_runtime.mod_path) if not mod_path.exists(): @@ -114,9 +138,9 @@ 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 + self.mod_module = module mod_list = [] for mod in module: mod_list.append((mod.mod_id, mod.version)) @@ -124,30 +148,11 @@ class Game: 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 init_console(self) -> None: + self.console = self.console_class() + self.console.start() - 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): + def start(self): self.server.run() if DR_option.use_multiprocess: try: @@ -161,5 +166,42 @@ class Game: else: self.client.start() - def start(self) -> None: - self._start() + 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: + error = traceback.format_exc() + self.logger.error(tr().main.mod.event.error().format(event_name, error, mod.mod_id)) + + 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() + 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') + 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..1be17c2 100644 --- a/Difficult_Rocket/utils/options.py +++ b/Difficult_Rocket/utils/options.py @@ -66,9 +66,11 @@ 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 = 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() except Exception: @@ -78,8 +80,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/docs/src/update_logs.md b/docs/src/update_logs.md index f299b20..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 @@ -114,6 +117,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 +132,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 diff --git a/mods/dr_game/Difficult_Rocket_rs/__init__.py b/mods/dr_game/Difficult_Rocket_rs/__init__.py index 8b601e1..94c6dd5 100644 --- a/mods/dr_game/Difficult_Rocket_rs/__init__.py +++ b/mods/dr_game/Difficult_Rocket_rs/__init__.py @@ -101,3 +101,9 @@ if TYPE_CHECKING: @property def img_pos(self) -> Tuple[int, int, int, int]: ... """ -x -y +x +y 左下右上 """ + + class Console_rs: + def __init__(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/lib.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs index 4eef625..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,16 +18,17 @@ use pyo3::prelude::*; // const MOD_PATH: String = String::from("mods"); +#[allow(unused)] 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 { @@ -52,6 +53,7 @@ fn module_init(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; Ok(()) } 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 a543772..32cccc2 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs @@ -12,7 +12,6 @@ pub mod data { use pyo3::prelude::*; use crate::sr1_data::part_list::RawPartList; - use crate::sr1_data::ship::RawShip; use crate::types::sr1::{get_max_box, SR1PartData, SR1PartListTrait}; use crate::types::sr1::{SR1PartList, SR1PartType, SR1Ship}; @@ -167,3 +166,67 @@ pub mod translate { } } } + +pub mod console { + use std::println; + + use pyo3::prelude::*; + + #[pyclass] + #[pyo3(name = "Console_rs")] + pub struct PyConsole { + /// 向子线程发送结束信号 + 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 || { + let std_in = std::io::stdin(); + loop { + if let Ok(()) = stop_receiver.try_recv() { + break; + } + let mut input = String::new(); + let _ = std_in.read_line(&mut input); + if !input.is_empty() { + keyboard_input_sender.send(input).unwrap(); + } + print!(">>"); + } + }); + self.stop_sender = Some(stop_sender); + self.keyboard_input_receiver = Some(keyboard_input_receiver); + } + + fn stop(&self) -> bool { + if let Some(sender) = &self.stop_sender { + sender.send(()).unwrap(); + return true; + } + false + } + + fn get_command(&self) -> Option { + // 获取输入 + 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/Difficult_Rocket_rs/src/src/types.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/types.rs index 6bfe573..6348930 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/types.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/types.rs @@ -138,10 +138,10 @@ pub mod sr1 { impl Damage { pub fn to_raw_damage(&self) -> RawDamage { RawDamage { - disconnect: self.disconnect.to_owned(), - explode: self.explode.to_owned(), - explosion_power: Some(self.explosion_power.to_owned()), - explosion_size: Some(self.explosion_size.to_owned()), + disconnect: self.disconnect, + explode: self.explode, + explosion_power: Some(self.explosion_power), + explosion_size: Some(self.explosion_size), } } } @@ -225,10 +225,10 @@ pub mod sr1 { if cache.is_none() { let mut map = HashMap::new(); for part in self.types.iter() { - map.insert(part.id.to_owned(), part.to_owned()); + map.insert(part.id.clone(), part.clone()); } - *cache = Some(map); - self.cache.replace(cache.to_owned()); + *cache = Some(map.clone()); + self.cache.replace(cache.clone()); } cache.to_owned().unwrap() } @@ -237,7 +237,7 @@ pub mod sr1 { pub fn get_part_type(&self, type_name: String) -> Option { let cache = self.get_cache(); match cache.get(&type_name) { - Some(part) => Some(part.to_owned()), + Some(part) => Some(part.clone()), None => None, } } @@ -294,18 +294,18 @@ pub mod sr1 { fn to_raw_part_type(&self) -> RawPartType { let tank: Option = match &self.attr { - Some(attr) => match attr { + Some(attr) => match attr.to_owned() { SR1PartTypeAttr::Tank { fuel, dry_mass, fuel_type } => Some(Tank { - fuel: fuel.to_owned(), - dry_mass: dry_mass.to_owned(), - fuel_type: Some(fuel_type.to_owned()), + fuel, + dry_mass, + fuel_type: Some(fuel_type), }), _ => None, }, _ => None, }; let engine: Option = match &self.attr { - Some(attr) => match attr { + Some(attr) => match attr.to_owned() { SR1PartTypeAttr::Engine { power, consumption, @@ -314,39 +314,33 @@ pub mod sr1 { fuel_type, throttle_exponential, } => Some(Engine { - power: power.to_owned(), - consumption: consumption.to_owned(), - throttle_exponential: Some(throttle_exponential.to_owned()), - size: size.to_owned(), - turn: turn.to_owned(), - fuel_type: Some(fuel_type.to_owned()), + power, + consumption, + throttle_exponential: Some(throttle_exponential), + size, + turn, + fuel_type: Some(fuel_type), }), _ => None, }, _ => None, }; let rcs: Option = match &self.attr { - Some(attr) => match attr { - SR1PartTypeAttr::Rcs { power, consumption, size } => Some(Rcs { - power: power.to_owned(), - consumption: consumption.to_owned(), - size: size.to_owned(), - }), + Some(attr) => match attr.to_owned() { + SR1PartTypeAttr::Rcs { power, consumption, size } => Some(Rcs { power, consumption, size }), _ => None, }, _ => None, }; let solar: Option = match &self.attr { - Some(attr) => match attr { - SR1PartTypeAttr::Solar { charge_rate } => Some(Solar { - charge_rate: charge_rate.to_owned(), - }), + Some(attr) => match attr.to_owned() { + SR1PartTypeAttr::Solar { charge_rate } => Some(Solar { charge_rate }), _ => None, }, _ => None, }; let lander: Option = match &self.attr { - Some(attr) => match attr { + Some(attr) => match attr.to_owned() { SR1PartTypeAttr::Lander { max_angle, min_length, @@ -355,12 +349,12 @@ pub mod sr1 { length_speed, width, } => Some(Lander { - max_angle: max_angle.to_owned(), - min_length: min_length.to_owned(), - max_length: max_length.to_owned(), - angle_speed: Some(angle_speed.to_owned()), - length_speed: Some(length_speed.to_owned()), - width: width.to_owned(), + max_angle, + min_length, + max_length, + angle_speed: Some(angle_speed), + length_speed: Some(length_speed), + width, }), _ => None, }, @@ -382,19 +376,19 @@ pub mod sr1 { description: self.description.clone(), sprite: self.sprite.clone(), r#type: self.p_type.clone(), - mass: self.mass.to_owned(), - width: self.width.to_owned(), - height: self.height.to_owned(), - friction: Some(self.friction.to_owned()), + mass: self.mass, + width: self.width, + height: self.height, + friction: Some(self.friction), category: Some(self.category.clone()), - ignore_editor_intersections: Some(self.ignore_editor_intersections.to_owned()), - disable_editor_rotation: Some(self.disable_editor_rotation.to_owned()), - can_explode: Some(self.can_explode.to_owned()), - cover_height: Some(self.cover_height.to_owned()), - sandbox_only: Some(self.sandbox_only.to_owned()), - drag: Some(self.drag.to_owned()), - hidden: Some(self.hidden.to_owned()), - buoyancy: Some(self.buoyancy.to_owned()), + ignore_editor_intersections: Some(self.ignore_editor_intersections), + disable_editor_rotation: Some(self.disable_editor_rotation), + can_explode: Some(self.can_explode), + cover_height: Some(self.cover_height), + sandbox_only: Some(self.sandbox_only), + drag: Some(self.drag), + hidden: Some(self.hidden), + buoyancy: Some(self.buoyancy), damage: Some(self.damage.to_raw_damage()), tank, engine, @@ -422,36 +416,6 @@ pub mod sr1 { } else { (None, None) }; - // let pod = match &self.attr { - // SR1PartDataAttr::Pod { - // name, - // throttle, - // current_stage, - // steps, - // } => Some({ - // let mut actives = Vec::new(); - // for step in steps { - // let mut steps_ = Vec::new(); - // for active in step { - // steps_.push(RawActivate { - // id: active.0, - // moved: bool_to_i8(active.1), - // }); - // } - // actives.push(RawStep { activates: steps_ }); - // } - // let stages = RawStaging { - // current_stage: *current_stage, - // steps: actives, - // }; - // RawPod { - // name: name.clone(), - // throttle: *throttle, - // stages, - // } - // }), - // _ => None, - // }; let pod = match (&self.attr.name, &self.attr.throttle, &self.attr.current_stage, &self.attr.steps) { (Some(name), Some(throttle), Some(current_stage), Some(steps)) => Some({ let mut actives = Vec::new(); @@ -482,25 +446,25 @@ pub mod sr1 { engine, pod, part_type_id: self.part_type_id.clone(), - id: self.id.to_owned(), - x: self.x.to_owned(), - y: self.y.to_owned(), - editor_angle: self.editor_angle.to_owned(), - angle: self.angle.to_owned(), - angle_v: self.angle_v.to_owned(), - flip_x: Some(bool_to_i8(self.flip_x.to_owned())), - flip_y: Some(bool_to_i8(self.flip_y.to_owned())), - chute_x: self.attr.chute_x.to_owned(), - chute_y: self.attr.chute_y.to_owned(), - chute_height: self.attr.chute_height.to_owned(), - extension: self.attr.extension.to_owned(), - inflate: option_bool_to_option_i8(self.attr.inflate.to_owned()), - inflation: option_bool_to_option_i8(self.attr.inflation.to_owned()), - exploded: Some(bool_to_i8(self.explode.to_owned())), - rope: option_bool_to_option_i8(self.attr.rope.to_owned()), - chute_angle: self.attr.chute_angle.to_owned(), - activated: Some(bool_to_i8(self.active.to_owned())), - deployed: option_bool_to_option_i8(self.attr.deployed.to_owned()), + id: self.id, + x: self.x, + y: self.y, + editor_angle: self.editor_angle, + angle: self.angle, + angle_v: self.angle_v, + flip_x: Some(bool_to_i8(self.flip_x)), + flip_y: Some(bool_to_i8(self.flip_y)), + chute_x: self.attr.chute_x, + chute_y: self.attr.chute_y, + chute_height: self.attr.chute_height, + extension: self.attr.extension, + inflate: option_bool_to_option_i8(self.attr.inflate), + inflation: option_bool_to_option_i8(self.attr.inflation), + exploded: Some(bool_to_i8(self.explode)), + rope: option_bool_to_option_i8(self.attr.rope), + chute_angle: self.attr.chute_angle, + activated: Some(bool_to_i8(self.active)), + deployed: option_bool_to_option_i8(self.attr.deployed), } } } @@ -528,11 +492,11 @@ pub mod sr1 { impl SR1PartData { pub fn get_box(&self, part_type: &SR1PartType) -> (f64, f64, f64, f64) { - let width = part_type.width.to_owned(); - let height = part_type.height.to_owned(); - let radius = self.angle.to_owned(); + let width = part_type.width; + let height = part_type.height; + let radius = self.angle; let mut shape = Shape::new_width_height(width as f64, height as f64, Some(radius)); - shape.move_xy(Some(self.x.to_owned()), Some(self.y.to_owned())); + shape.move_xy(Some(self.x), Some(self.y)); let mut pos_box = (0_f64, 0_f64, 0_f64, 0_f64); match shape.bounds[0] { Edge::OneTimeLine(line) => { @@ -652,15 +616,15 @@ pub mod sr1 { }; let (name, throttle, current_stage, steps) = if let Some(pod) = &raw_data.pod { ( - Some(pod.name.to_owned()), - Some(pod.throttle.to_owned()), - Some(pod.stages.current_stage.to_owned()), + Some(pod.name.clone()), + Some(pod.throttle), + Some(pod.stages.current_stage), Some({ let mut steps = Vec::new(); for step in &pod.stages.steps { let mut step_vec = Vec::new(); for act in &step.activates { - step_vec.push((act.id.to_owned(), i8_to_bool(act.moved.to_owned()))); + step_vec.push((act.id, i8_to_bool(act.moved))); } steps.push(step_vec); } @@ -676,15 +640,15 @@ pub mod sr1 { throttle, current_stage, steps, - extension: raw_data.extension.to_owned(), - chute_x: raw_data.chute_x.to_owned(), - chute_y: raw_data.chute_y.to_owned(), - chute_height: raw_data.chute_height.to_owned(), - chute_angle: raw_data.chute_angle.to_owned(), - inflate: option_i8_to_option_bool(raw_data.inflate.to_owned()), - inflation: option_i8_to_option_bool(raw_data.inflation.to_owned()), - deployed: option_i8_to_option_bool(raw_data.deployed.to_owned()), - rope: option_i8_to_option_bool(raw_data.rope.to_owned()), + extension: raw_data.extension, + chute_x: raw_data.chute_x, + chute_y: raw_data.chute_y, + chute_height: raw_data.chute_height, + chute_angle: raw_data.chute_angle, + inflate: option_i8_to_option_bool(raw_data.inflate), + inflation: option_i8_to_option_bool(raw_data.inflation), + deployed: option_i8_to_option_bool(raw_data.deployed), + rope: option_i8_to_option_bool(raw_data.rope), part_type: Cell::new(part_type), }; if guess & results.part_type.get().is_none() { @@ -715,6 +679,30 @@ pub mod sr1 { let ship: RawShip = RawShip::from_file(file_name).unwrap(); Some(ship.to_sr_ship(ship_name)) } + + pub fn parse_part_list_to_part(&mut self, part_list: SR1PartList) { + // parse parts + for part in self.parts.iter_mut() { + let part_type_id = part.part_type_id.clone(); + if let Some(part_type) = part_list.get_part_type(part_type_id) { + part.part_type = part_type.p_type; + } else { + part.part_type = SR1PartTypeEnum::strut; + } + } + for disconnects in self.disconnected.iter_mut() { + for (parts, _) in disconnects.iter_mut() { + for part in parts.iter_mut() { + let part_type_id = part.part_type_id.clone(); + if let Some(part_type) = part_list.get_part_type(part_type_id) { + part.part_type = part_type.p_type; + } else { + part.part_type = SR1PartTypeEnum::strut; + } + } + } + } + } } impl SR1ShipTrait for SR1Ship { @@ -761,8 +749,8 @@ pub mod sr1 { parts: RawParts { parts }, connects: connections, version: 1, - lift_off: bool_to_i8(self.lift_off.to_owned()), - touch_ground: bool_to_i8(self.touch_ground.to_owned()), + lift_off: bool_to_i8(self.lift_off), + touch_ground: bool_to_i8(self.touch_ground), disconnected, } } @@ -800,8 +788,8 @@ pub mod math { #[inline] pub fn distance(&self, other: &Point2D) -> f64 { - let dx = (other.x.to_owned() - self.x.to_owned()).powf(2.0); - let dy = (other.y.to_owned() - self.y.to_owned()).powf(2.0); + let dx = (other.x - self.x).powf(2.0); + let dy = (other.y - self.y).powf(2.0); (dx + dy).powf(0.5) } diff --git a/mods/dr_game/__init__.py b/mods/dr_game/__init__.py index 79ab6f6..712c039 100644 --- a/mods/dr_game/__init__.py +++ b/mods/dr_game/__init__.py @@ -9,14 +9,13 @@ 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 -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): @@ -68,6 +67,10 @@ 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 + + game.console_class = RustConsole # 替换掉原来的 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()