diff --git a/Difficult_Rocket/client/__init__.py b/Difficult_Rocket/client/__init__.py index 479dc2b..fdf3bfc 100644 --- a/Difficult_Rocket/client/__init__.py +++ b/Difficult_Rocket/client/__init__.py @@ -15,7 +15,7 @@ import traceback from pathlib import Path from decimal import Decimal -from typing import Callable, Dict, List, TYPE_CHECKING +from typing import Callable, Dict, List, TYPE_CHECKING, Optional # third function import rtoml @@ -23,6 +23,7 @@ import pyglet # from pyglet import gl # from pyglet.gl import glClearColor # from pyglet.libs.win32 import _user32 +from pyglet.graphics import Group, Batch from pyglet.window import Window from pyglet.window import key, mouse @@ -37,10 +38,10 @@ from Difficult_Rocket.utils.translate import tr from Difficult_Rocket.runtime import DR_runtime from Difficult_Rocket.api.screen import BaseScreen from Difficult_Rocket.utils.thread import new_thread +from Difficult_Rocket.client.screen import DRDEBUGScreen from Difficult_Rocket.client.fps.fps_log import FpsLogger from Difficult_Rocket.client.guis.widgets import InputBox from Difficult_Rocket.exception.language import LanguageNotFound -from Difficult_Rocket.client.screen import DRScreen, DRDEBUGScreen logger = logging.getLogger('client') @@ -122,7 +123,36 @@ def pyglet_load_fonts_folder(folder) -> None: pyglet_load_fonts_folder(os.path.join(folder, obj)) +def _call_back(call_back: Callable) -> Callable: + """ + >>> def call_back(): + >>> pass + >>> @_call_back(call_back) + >>> def on_draw(self): + >>> pass + 用于在调用窗口函数后调用指定函数 的装饰器 + :param call_back: 需要调用的函数 + :return: 包装后的函数 + """ + def wrapper(func): + @functools.wraps(func) + def warp(self: "ClientWindow", *args, **kwargs): + result = func(self, *args, **kwargs) + call_back(self) + return result + return warp + return wrapper + + def _call_screen_after(func: Callable) -> Callable: + """ + >>> @_call_screen_after + >>> def on_draw(self): + >>> pass + 用于在调用窗口函数后调用子窗口函数 的装饰器 + :param func: 需要包装的函数 + :return: 包装后的函数 + """ @functools.wraps(func) def warped(self: "ClientWindow", *args, **kwargs): result = func(self, *args, **kwargs) @@ -141,6 +171,14 @@ def _call_screen_after(func: Callable) -> Callable: def _call_screen_before(func: Callable) -> Callable: + """ + >>> @_call_screen_before + >>> def on_draw(self): + >>> pass + 用于在调用窗口函数前调用子窗口函数 的装饰器 + :param func: 需要包装的函数 + :return: 包装后的函数 + """ @functools.wraps(func) def warped(self: "ClientWindow", *args, **kwargs): for title, a_screen in self.screen_list.items(): @@ -185,8 +223,9 @@ class ClientWindow(Window): self.SPF = Decimal('1') / self.FPS self.fps_log = FpsLogger(stable_fps=int(self.FPS)) # batch - self.part_batch = pyglet.graphics.Batch() - self.label_batch = pyglet.graphics.Batch() + self.part_batch = Batch() + self.label_batch = Batch() + self.main_group = Group(0) # frame self.frame = pyglet.gui.Frame(self, order=20) self.M_frame = pyglet.gui.MovableFrame(self, modifier=key.LCTRL) @@ -194,9 +233,10 @@ class ClientWindow(Window): # setup self.setup() # 命令显示 - self.command_group = pyglet.graphics.Group(0) + self.command_batch = Batch() + self.command_group = Group(1, parent=self.main_group) self.input_box = InputBox(x=50, y=30, width=300, - batch=self.label_batch, text='') # 实例化 + batch=self.command_batch, text='') # 实例化 self.input_box.push_handlers(self) self.input_box.set_handler('on_commit', self.on_input) self.set_handlers(self.input_box) @@ -215,9 +255,7 @@ class ClientWindow(Window): def setup(self): self.set_icon(pyglet.image.load('./textures/icon.png')) self.load_fonts() - # TODO 读取配置文件,加载不同的屏幕,解耦 self.screen_list['DR_debug'] = DRDEBUGScreen(self) - self.screen_list['DR_main'] = DRScreen(self) self.game.dispatch_event('on_client_start', game=self.game, client=self) def load_fonts(self) -> None: @@ -264,6 +302,10 @@ class ClientWindow(Window): now_FPS = pyglet.clock.get_frequency() self.fps_log.update_tick(now_FPS, decimal_tick) + def on_command_draw(self): + self.command_batch.draw() + + @_call_back(on_command_draw) @_call_screen_after def on_draw(self, *dt): while command := self.game.console.get_command(): @@ -306,10 +348,15 @@ class ClientWindow(Window): self.on_command(command_text) self.input_box.value = '' + def new_command(self): + self.game.console.new_command() + + @_call_back(new_command) @_call_screen_after def on_command(self, command: line.CommandText): - print(command.find('/')) + command.text = command.text.rstrip('\n') self.logger.info(tr().window.command.text().format(command)) + command.find('/') if command.find('stop'): # self.dispatch_event('on_exit') print("command stop!") @@ -335,8 +382,9 @@ class ClientWindow(Window): except LanguageNotFound: self.logger.info(tr().language_available().format(os.listdir('./configs/lang'))) self.save_info() - - # self.command_tree.parse(command.plain_command) + elif command.find('mods'): + for mod in self.game.mod_module: + self.logger.info(f"mod: {mod.name} id: {mod.mod_id} version: {mod.version}") @_call_screen_after def on_message(self, message: line.CommandText): diff --git a/Difficult_Rocket/client/screen.py b/Difficult_Rocket/client/screen.py index aced0d0..3d29f4f 100644 --- a/Difficult_Rocket/client/screen.py +++ b/Difficult_Rocket/client/screen.py @@ -7,24 +7,17 @@ import typing from pyglet.text import Label -from pyglet.graphics import Batch, Group from pyglet.clock import get_frequency +from pyglet.graphics import Batch, Group # Difficult Rocket function from Difficult_Rocket.api.types import Fonts -# from Difficult_Rocket.utils import translate from Difficult_Rocket.api.screen import BaseScreen -# from Difficult_Rocket.command.tree import CommandTree if typing.TYPE_CHECKING: from Difficult_Rocket.client import ClientWindow -class DRScreen(BaseScreen): - def __init__(self, main_window: "ClientWindow"): - super().__init__(main_window) - - class DRDEBUGScreen(BaseScreen): def __init__(self, main_window: "ClientWindow"): super().__init__(main_window) @@ -55,4 +48,3 @@ class DRDEBUGScreen(BaseScreen): def on_draw(self, *dt, window: "ClientWindow"): self.main_batch.draw() - # print(self.window_pointer.try_if_runs) diff --git a/Difficult_Rocket/command/api.py b/Difficult_Rocket/command/api.py index b9b770a..220724c 100644 --- a/Difficult_Rocket/command/api.py +++ b/Difficult_Rocket/command/api.py @@ -44,10 +44,13 @@ class CommandText: i += 1 def find(self, text: str) -> bool: - find = self.text.find(text) - if find != -1: - self.text = self.text[find + len(text):] - return True + startswith = self.text.startswith(text) + if startswith: + find = self.text.find(text) + if find != -1: + if not len(text) == len(self.text): + self.text = self.text[find + len(text):] if not self.text[find+len(text)] == ' ' else self.text[find + len(text) + 1:] + return True return False def re_find(self, text: str) -> Union[str, bool]: diff --git a/Difficult_Rocket/main.py b/Difficult_Rocket/main.py index 2b05854..3d74f74 100644 --- a/Difficult_Rocket/main.py +++ b/Difficult_Rocket/main.py @@ -65,6 +65,9 @@ class Console(Options): def get_command(self) -> Optional[str]: return self.caches.pop(0) if self.caches else None + def new_command(self) -> None: + return None + class Game(Options): name = 'MainGame' diff --git a/Difficult_Rocket/utils/tools.py b/Difficult_Rocket/utils/tools.py index 5609e81..e731e66 100644 --- a/Difficult_Rocket/utils/tools.py +++ b/Difficult_Rocket/utils/tools.py @@ -16,20 +16,19 @@ import sys import time import math import json +import rtoml import logging import configparser -from typing import Union +from pathlib import Path +from typing import Union, Optional from xml.etree import ElementTree - -import rtoml - from defusedxml.ElementTree import parse from Difficult_Rocket.exception.unsupport import NoMoreJson5 # logger -tools_logger = logging.getLogger('part-tools') +tools_logger = logging.getLogger('tools') """ file configs """ @@ -39,10 +38,12 @@ file_error = {FileNotFoundError: 'no {filetype} file was founded!:\n file name: Exception: 'get some {error_type} when read {filetype} file {filename}! \n file type: {} \n file name: {} \n stack: {stack}'} -def load_file(file_name: str, - stack: Union[str, list, dict, None] = None, - raise_error: bool = True, - encoding: str = 'utf-8') -> Union[dict, ElementTree.ElementTree]: +def load_file(file_name: Union[str, Path], + stack: Optional[Union[str, list, dict]] = None, + raise_error: Optional[bool] = True, + encoding: Optional[str] = 'utf-8') -> Union[dict, ElementTree.ElementTree]: + if isinstance(file_name, Path): + file_name = str(file_name) f_type = file_name[file_name.rfind('.') + 1:] # 从最后一个.到末尾 (截取文件格式) get_file = NotImplementedError('解析失败,请检查文件类型/文件内容/文件是否存在!') try: diff --git a/Difficult_Rocket/utils/translate.py b/Difficult_Rocket/utils/translate.py index e245a54..971584f 100644 --- a/Difficult_Rocket/utils/translate.py +++ b/Difficult_Rocket/utils/translate.py @@ -14,6 +14,7 @@ gitee: @shenjackyuanjie import os import inspect +from pathlib import Path from dataclasses import dataclass from typing import Union, Tuple, Any, List, Dict, Hashable, Optional @@ -153,15 +154,16 @@ class Tr: GOOD """ - def __init__(self, language: str = None, config: Optional[TranslateConfig] = None): + def __init__(self, language: str = None, config: Optional[TranslateConfig] = None, lang_path: Optional[Path] = None): """ 诶嘿,我抄的MCDR :param language: Tr 所使用的的语言 :param config: 配置 """ self.language_name = language if language is not None else DR_runtime.language - self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'configs/lang/{self.language_name}.toml') - self.default_translate: Dict = tools.load_file(f'configs/lang/{DR_status.default_language}.toml') + self.language_path = lang_path if lang_path is not None else Path('configs/lang') + self.translates: Dict[str, Union[str, Dict]] = tools.load_file(self.language_path / f'{self.language_name}.toml') + self.default_translate: Dict = tools.load_file(f'{self.language_path}/{DR_status.default_language}.toml') self.default_config = config.set('source', self) if config is not None else TranslateConfig(source=self) self.translates_cache = Translates(value=self.translates, config=self.default_config.copy()) @@ -185,11 +187,11 @@ class Tr: if lang == ' ' or lang == '': raise LanguageNotFound('Can not be empty') lang = lang or self.language_name - if not os.path.exists(f'./configs/lang/{lang}.toml'): - print(f"lang: {os.path.exists(f'./configs/lang/{lang}.toml')} language = {lang} {self.language_name=}") + if not os.path.exists(f'{self.language_path}/{lang}.toml'): + print(f"lang: {os.path.exists(f'{self.language_path}/{lang}.toml')} language = {lang} {self.language_name=}") raise LanguageNotFound(lang) - self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'configs/lang/{lang}.toml') - self.default_translate: Dict = tools.load_file(f'configs/lang/{DR_runtime.default_language}.toml') + self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'{self.language_path}/{lang}.toml') + self.default_translate: Dict = tools.load_file(f'{self.language_path}/{DR_runtime.default_language}.toml') self.translates_cache = Translates(value=self.translates, config=self.default_config.copy()) self.language_name = lang DR_runtime.language = self.language_name diff --git a/configs/lang/en-us.toml b/configs/lang/en-us.toml index 80ec430..11bfe76 100644 --- a/configs/lang/en-us.toml +++ b/configs/lang/en-us.toml @@ -75,14 +75,3 @@ input = "console" window = "window" command = "in game commands" require_DR_rs = "require DR_rs module" - -[client.sr1_render] -setup.start = "SR1 Renderer start loading" -setup.use_time = "SR1 Renderer loading has used: {} second" -xml.loading = "Loading XML file: {}" -xml.load_done = "XML file loaded" -xml.load_time = "XML file loading has used: {} second" -ship.load = "Loading ship: {}" -ship.load_time = "Ship loading has used: {} second" -ship.info = "Ship info:\n- Parts: {}\n- Weight: {}" -ship.render.done = "Ship render done" diff --git a/configs/lang/zh-CN.toml b/configs/lang/zh-CN.toml index 8ebfa76..b348ff3 100644 --- a/configs/lang/zh-CN.toml +++ b/configs/lang/zh-CN.toml @@ -75,15 +75,3 @@ input = "控制台" window = "窗口" command = "游戏内命令行" require_DR_rs = "需要 DR_rs 模块" - -[client.sr1_render] -setup.start = "SR1 渲染器开始载入" -setup.use_time = "SR1 渲染器载入消耗时间: {} 秒" -xml.loading = "正在加载XML文件: {}" -xml.load_done = "XML 文件加载完成" -xml.load_time = "XML 文件加载消耗时间: {} 秒" -ship.load = "正在加载飞船: {}" -ship.load_time = "飞船加载消耗时间: {} 秒" -#ship.info = "飞船信息:\n- 部件数量: {}\n- 部件重量: {}\n- 文件大小: {}" -ship.info = "飞船信息:\n- 部件数量: {}\n- 部件重量: {}" -ship.render.done = "飞船渲染完成" diff --git a/configs/main.toml b/configs/main.toml index 4f5eb27..3e89e77 100644 --- a/configs/main.toml +++ b/configs/main.toml @@ -7,8 +7,8 @@ fonts_folder = "libs/fonts" [window] style = "None" -width = 1021 -height = 1078 +width = 1041 +height = 1050 visible = true gui_scale = 1 caption = "Difficult Rocket v{DR_version}" diff --git a/docs/src/change_log/dr_game.md b/docs/src/change_log/dr_game.md index 94a7ada..14630c6 100644 --- a/docs/src/change_log/dr_game.md +++ b/docs/src/change_log/dr_game.md @@ -3,7 +3,24 @@ - 最新版本号 - DR game: 0.2.0.0 - - DR rs: 0.2.10.1 + - DR rs: 0.2.11.0 + +## DR game 0.1.2.0 + +### 修改 + +- 现在渲染飞船的时候不会再显示那个白色框了 + - 改为一个彩色的框 +- Now, the ship will not be displayed in the white box + - Change to a colored box + +## DR rs 0.2.11.0 + +### 添加 + +- `Python::data::PySR1Ship` + - `get_part_box(&self, part_id: i64) -> Option<(f64, f64), (f64, f64)>` + - 用于获取对应 id 的实际碰撞箱 ## DR game 0.2.0.0 diff --git a/docs/src/change_log/dr_sdk.md b/docs/src/change_log/dr_sdk.md index 1829b9d..821e925 100644 --- a/docs/src/change_log/dr_sdk.md +++ b/docs/src/change_log/dr_sdk.md @@ -11,6 +11,21 @@ - issue #33 (https://github.com/shenjackyuanjie/Difficult-Rocket/issues/33) - 修复了实际上并不会加载 `.otf` 格式的字体文件的问题 +### 修改 + +- 现在输入命令之后不会输出一个 `True`/`False` 了 + - (实际上是用来检测命令是不是用 `/` 开头的) + - Now, the command will not output a `True`/`False` + - (Actually used to detect whether the command starts with `/`) +- `CommandText` + - `find` + - 现在会先用 `str.startswith` 检测是否以要求的字符串开头 + - 实际上就是丐版 `re.match` + - 并且会在匹配上之后 如果匹配内容后面第一个字符是空格 则会截取掉空格 + - Now, it will first use `str.startswith` to detect whether it starts with the required string + - Actually a poor version of `re.match` + - And after matching, if the first character after the matching content is a space, the space will be intercepted + ## DR sdk 0.8.3.0 ### 删除 diff --git a/mods/dr_game/Difficult_Rocket_rs/__init__.py b/mods/dr_game/Difficult_Rocket_rs/__init__.py index 5413d29..ab367f7 100644 --- a/mods/dr_game/Difficult_Rocket_rs/__init__.py +++ b/mods/dr_game/Difficult_Rocket_rs/__init__.py @@ -121,9 +121,11 @@ if TYPE_CHECKING: @property def img_pos(self) -> Tuple[int, int, int, int]: ... """ -x -y +x +y 左下右上 """ + def get_part_box(self, part_id: int) -> Optional[Tuple[Tuple[int, int], Tuple[int, int]]]: ... class Console_rs: def __init__(self) -> None: ... def start(self) -> None: ... def stop(self) -> bool: ... def get_command(self) -> Optional[str]: ... + def new_command(self) -> bool: ... diff --git a/mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock b/mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock index f4569ed..d40428d 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock +++ b/mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" @@ -84,14 +84,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matrixmultiply" @@ -190,6 +190,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "nalgebra" version = "0.32.2" @@ -348,7 +357,7 @@ dependencies = [ "cfg-if", "indoc", "libc", - "memoffset", + "memoffset 0.8.0", "parking_lot", "pyo3-build-config", "pyo3-ffi", diff --git a/mods/dr_game/Difficult_Rocket_rs/src/setup.py b/mods/dr_game/Difficult_Rocket_rs/src/setup.py index a362c4d..3a3f63d 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/setup.py +++ b/mods/dr_game/Difficult_Rocket_rs/src/setup.py @@ -12,7 +12,7 @@ package_path = 'Difficult_Rocket_rs' setup( name='Difficult_Rocket_rs', - version="0.2.10.1", + version="0.2.11.0", author='shenjackyuanjie', author_email='3695888@qq.com', rust_extensions=[RustExtension(target="Difficult_Rocket_rs.Difficult_Rocket_rs", 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 bae2582..25031ab 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/lib.rs @@ -12,6 +12,7 @@ mod python; mod render; mod simulator; mod sr1_data; +mod translate; mod types; use pyo3::prelude::*; @@ -26,7 +27,7 @@ enum LoadState { } #[pyfunction] -fn get_version_str() -> String { "0.2.10.1".to_string() } +fn get_version_str() -> String { "0.2.11.0".to_string() } #[pyfunction] fn test_call(py_obj: &PyAny) -> PyResult { @@ -42,7 +43,6 @@ fn test_call(py_obj: &PyAny) -> PyResult { fn module_init(_py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(get_version_str, m)?)?; m.add_function(wrap_pyfunction!(test_call, m)?)?; - m.add_function(wrap_pyfunction!(simulator::simulation, m)?)?; m.add_function(wrap_pyfunction!(sr1_data::part_list::read_part_list_py, m)?)?; m.add_function(wrap_pyfunction!(sr1_data::ship::py_raw_ship_from_file, m)?)?; m.add_class::()?; diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/plugin.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/plugin.rs index 9796efe..849cc6c 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/plugin.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/plugin.rs @@ -12,6 +12,7 @@ /// 插件加载 /// +#[allow(unused)] pub mod plugin_trait { pub struct ModInfo { pub name: String, 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 487d791..8e88f87 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/python.rs @@ -12,6 +12,7 @@ pub mod data { use pyo3::prelude::*; use crate::sr1_data::part_list::RawPartList; + use crate::types::math::{Point2D, Rotatable}; use crate::types::sr1::{get_max_box, SR1PartData, SR1PartListTrait}; use crate::types::sr1::{SR1PartList, SR1PartType, SR1Ship}; @@ -142,96 +143,35 @@ pub mod data { } parts } + + fn get_part_box(&self, part_id: i64) -> Option<((f64, f64), (f64, f64))> { + let part_data = self.ship.parts.iter().find(|&x| x.id == part_id); + if let Some(part_data) = part_data { + let part_type = self.part_list.get_part_type(part_data.part_type_id.clone()).unwrap(); + // rotate + let radius = part_data.angle; + let ((x1, y1), (x2, y2)) = part_type.get_box(); + let mut p1 = Point2D::new(x1, y1); + let mut p2 = Point2D::new(x2, y2); + p1.rotate_radius_mut(radius); + p2.rotate_radius_mut(radius); + // transform + p1.add_mut(part_data.x * 2.0, part_data.y * 2.0); + p2.add_mut(part_data.x * 2.0, part_data.y * 2.0); + return Some(((p1.x, p1.y), (p2.x, p2.y))); + } + None + } } } pub mod translate { - use pyo3::prelude::*; - use pyo3::types::PyDict; - - #[pyclass] - #[pyo3(name = "TranslateConfig_rs")] - #[pyo3(text_signature = "(language, raise_error = False, replace_normal = False, add_error = False, is_result = False, keep_get = False)")] - pub struct PyTranslateConfig { - pub raise_error: bool, - pub replace_normal: bool, - pub add_error: bool, - pub is_result: bool, - pub keep_get: bool, - pub language: String, - } - - #[pymethods] - impl PyTranslateConfig { - #[new] - fn new(py_: Python, raise_error: bool, replace_normal: bool, language: Option) -> Self { - let dr_runtime = PyModule::import(py_, "Difficult_Rocket").unwrap().get_item("DR_runtime").unwrap(); - let default_language = dr_runtime.get_item("language").unwrap().extract::().unwrap(); - Self { - raise_error, - replace_normal, - add_error: false, - is_result: false, - keep_get: false, - language: language.unwrap_or(default_language), - } - } - - // fn set(&self, py_: Python, item: String, value: BoolString) -> &Self { - // match item.as_str() { - // "raise_error" => self, - // _ => self, - // } - // } - } - - #[pyclass] - pub struct PyTranslate { - pub data: Py, - pub get_list: Vec<(String, bool)>, - pub config: PyTranslateConfig, - } - - #[pymethods] - impl PyTranslate { - #[new] - fn py_new(py_: Python, data: &PyAny) -> Self { - let _ = data.is_instance_of::(); - Self { - data: data.into_py(py_), - get_list: Vec::new(), - config: PyTranslateConfig::new(py_, false, false, None), - } - } - } -} - -pub mod physics { - use pyo3::prelude::*; - - use crate::simulator::interface::PhysicsSpace; - - #[pyclass] - #[pyo3(name = "PhysicsSpace_rs")] - pub struct PyPhysicsSpace { - pub space: PhysicsSpace, - } - - #[pymethods] - impl PyPhysicsSpace { - #[new] - fn new(gravity: (f64, f64)) -> Self { - Self { - space: PhysicsSpace::new(gravity), - } - } - - fn tick_space(&mut self) { self.space.tick_space() } - } + use crate::translate; } pub mod console { use pyo3::prelude::*; + use std::io::{self, Write}; #[pyclass] #[pyo3(name = "Console_rs")] @@ -255,7 +195,7 @@ pub mod console { 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(); + let std_in = io::stdin(); loop { if let Ok(()) = stop_receiver.try_recv() { break; @@ -265,9 +205,10 @@ pub mod console { if !input.is_empty() { keyboard_input_sender.send(input).unwrap(); } - print!(">>"); } }); + print!("rs>"); + io::stdout().flush().unwrap(); self.stop_sender = Some(stop_sender); self.keyboard_input_receiver = Some(keyboard_input_receiver); } @@ -280,6 +221,12 @@ pub mod console { false } + fn new_command(&self) -> bool { + print!("rs>"); + io::stdout().flush().unwrap(); + true + } + fn get_command(&self) -> Option { // 获取输入 if let Some(receiver) = &self.keyboard_input_receiver { diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/simulator.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/simulator.rs index 4392c7a..67f4737 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/simulator.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/simulator.rs @@ -9,6 +9,7 @@ use pyo3::prelude::*; use rapier2d_f64::prelude::*; +#[allow(unused)] #[pyfunction] #[pyo3(name = "simulation")] pub fn simulation() -> () { @@ -63,73 +64,8 @@ pub fn simulation() -> () { } } -pub mod interface { +#[allow(unused)] +pub mod python { + use pyo3::prelude::*; use rapier2d_f64::prelude::*; - - pub struct PhysicsSpace { - pub rigid_body_set: RigidBodySet, - pub collider_set: ColliderSet, - pub gravity: Vector, - pub integration_parameters: IntegrationParameters, - pub physics_pipeline: PhysicsPipeline, - pub island_manager: IslandManager, - pub broad_phase: BroadPhase, - pub narrow_phase: NarrowPhase, - pub impulse_joint_set: ImpulseJointSet, - pub multibody_joint_set: MultibodyJointSet, - pub ccd_solver: CCDSolver, - pub physics_hooks: (), - pub event_handler: (), - } - - impl PhysicsSpace { - pub fn new(gravity: (f64, f64)) -> Self { - let rigid_body_set = RigidBodySet::new(); - let collider_set = ColliderSet::new(); - let gravity = vector![gravity.0, gravity.1]; - let integration_parameters = IntegrationParameters::default(); - let physics_pipeline = PhysicsPipeline::new(); - let island_manager = IslandManager::new(); - let broad_phase = BroadPhase::new(); - let narrow_phase = NarrowPhase::new(); - let impulse_joint_set = ImpulseJointSet::new(); - let multibody_joint_set = MultibodyJointSet::new(); - let ccd_solver = CCDSolver::new(); - let physics_hooks = (); - let event_handler = (); - Self { - rigid_body_set, - collider_set, - gravity, - integration_parameters, - physics_pipeline, - island_manager, - broad_phase, - narrow_phase, - impulse_joint_set, - multibody_joint_set, - ccd_solver, - physics_hooks, - event_handler, - } - } - - pub fn tick_space(&mut self) { - self.physics_pipeline.step( - &self.gravity, - &self.integration_parameters, - &mut self.island_manager, - &mut self.broad_phase, - &mut self.narrow_phase, - &mut self.rigid_body_set, - &mut self.collider_set, - &mut self.impulse_joint_set, - &mut self.multibody_joint_set, - &mut self.ccd_solver, - None, - &self.physics_hooks, - &self.event_handler, - ); - } - } } diff --git a/mods/dr_game/Difficult_Rocket_rs/src/src/translate.rs b/mods/dr_game/Difficult_Rocket_rs/src/src/translate.rs new file mode 100644 index 0000000..586097b --- /dev/null +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/translate.rs @@ -0,0 +1,16 @@ +/* + * ------------------------------- + * Difficult Rocket + * Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com + * All rights reserved + * ------------------------------- + */ + +use std::collections::HashMap; + +type TranslateMapper = HashMap>>; + +pub struct Translater { + pub data: TranslateMapper, + pub language: String, +} 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 ca77063..63b739a 100644 --- a/mods/dr_game/Difficult_Rocket_rs/src/src/types.rs +++ b/mods/dr_game/Difficult_Rocket_rs/src/src/types.rs @@ -197,9 +197,13 @@ pub mod sr1 { } impl SR1PartType { - pub fn get_box(&self) -> (f64, f64, f64, f64) { - let x = self.width as f64 / 2.0; - (-x, 0.0, x, self.height as f64) + pub fn get_box(&self) -> ((f64, f64), (f64, f64)) { + // -x, -y, x, y + // 居中 + ( + (-(self.width as f64 / 2.0), -(self.height as f64 / 2.0)), + (self.width as f64 / 2.0, self.height as f64 / 2.0), + ) } } @@ -777,14 +781,14 @@ pub mod sr1 { let mut max_box = (0_f64, 0_f64, 0_f64, 0_f64); for part in parts.iter() { let part_type = part_list.get_part_type(part.part_type_id.clone()).unwrap(); - let (x1, y1, x2, y2) = part_type.get_box(); + let ((x1, y1), (x2, y2)) = part_type.get_box(); // rotate let mut p1 = Point2D::new(x1, y1); let mut p2 = Point2D::new(x2, y2); p1.rotate_radius_mut(part.angle); p2.rotate_radius_mut(part.angle); - let p1 = p1.add(part.x, part.y); - let p2 = p2.add(part.x, part.y); + let p1 = p1.add(part.x * 2.0, part.y * 2.0); + let p2 = p2.add(part.x * 2.0, part.y * 2.0); let (x1, y1, x2, y2) = (p1.x, p1.y, p2.x, p2.y); // get max box max_box.0 = max_box.0.min(x1).min(part.x); @@ -835,6 +839,12 @@ pub mod math { #[inline] pub fn add(&self, x: f64, y: f64) -> Self { Point2D::new(self.x + x, self.y + y) } + + #[inline] + pub fn add_mut(&mut self, x: f64, y: f64) -> () { + self.x += x; + self.y += y; + } } impl Rotatable for Point2D { diff --git a/mods/dr_game/__init__.py b/mods/dr_game/__init__.py index 46adba8..a930e96 100644 --- a/mods/dr_game/__init__.py +++ b/mods/dr_game/__init__.py @@ -17,7 +17,7 @@ from Difficult_Rocket.api.mod import ModInfo from Difficult_Rocket.client import ClientWindow from Difficult_Rocket.api.types import Options, Version -DR_rust_version = Version("0.2.10.1") # DR_mod 的 Rust 编写部分的兼容版本 +DR_rust_version = Version("0.2.11.0") # DR_mod 的 Rust 编写部分的兼容版本 logger = logging.getLogger('client.dr_game') diff --git a/mods/dr_game/console.py b/mods/dr_game/console.py index 62f88f8..ede0559 100644 --- a/mods/dr_game/console.py +++ b/mods/dr_game/console.py @@ -22,3 +22,6 @@ class RustConsole(Console): def get_command(self) -> str: return self.console.get_command() + + def new_command(self) -> None: + self.console.new_command() diff --git a/mods/dr_game/lang/en-us.toml b/mods/dr_game/lang/en-us.toml new file mode 100644 index 0000000..8c8a105 --- /dev/null +++ b/mods/dr_game/lang/en-us.toml @@ -0,0 +1,12 @@ +[mod.info] +setup.start = "SR1 Renderer start loading" +setup.use_time = "SR1 Renderer loading has used: {} second" + +[sr1.ship] +xml.loading = "Loading XML file: {}" +xml.load_done = "XML file loaded" +xml.load_time = "XML file loading has used: {} second" +ship.load = "Loading ship: {}" +ship.load_time = "Ship loading has used: {} second" +ship.info = "Ship info:\n- Parts: {}\n- Weight: {}" +ship.render.done = "Ship render done" \ No newline at end of file diff --git a/mods/dr_game/lang/zh-CN.toml b/mods/dr_game/lang/zh-CN.toml new file mode 100644 index 0000000..a1baf37 --- /dev/null +++ b/mods/dr_game/lang/zh-CN.toml @@ -0,0 +1,13 @@ +[mod.info] +setup.start = "SR1 渲染器开始载入" +setup.use_time = "SR1 渲染器载入消耗时间: {} 秒" + +[sr1.ship] +xml.loading = "正在加载XML文件: {}" +xml.load_done = "XML 文件加载完成" +xml.load_time = "XML 文件加载消耗时间: {} 秒" +ship.load = "正在加载飞船: {}" +ship.load_time = "飞船加载消耗时间: {} 秒" +#ship.info = "飞船信息:\n- 部件数量: {}\n- 部件重量: {}\n- 文件大小: {}" +ship.info = "飞船信息:\n- 部件数量: {}\n- 部件重量: {}" +ship.render.done = "飞船渲染完成" diff --git a/mods/dr_game/sr1_ship.py b/mods/dr_game/sr1_ship.py index 2e973b1..3c56220 100644 --- a/mods/dr_game/sr1_ship.py +++ b/mods/dr_game/sr1_ship.py @@ -9,26 +9,24 @@ import time import random import logging import traceback -# from xml.etree import ElementTree + +from pathlib import Path from xml.etree.ElementTree import Element from typing import List, TYPE_CHECKING, Union, Dict, Optional, Generator - -# third party package from defusedxml.ElementTree import parse -# pyglet from pyglet.math import Vec4 from pyglet.text import Label -from pyglet.shapes import Line, Rectangle from pyglet.sprite import Sprite # from pyglet.image import Texture from pyglet.graphics import Batch, Group +from pyglet.shapes import Line, Rectangle from . import DR_mod_runtime # Difficult Rocket from Difficult_Rocket import DR_status -from Difficult_Rocket.utils.translate import tr +from Difficult_Rocket.utils.translate import Tr from Difficult_Rocket.api.types import Fonts, Options from Difficult_Rocket.command.line import CommandText from Difficult_Rocket.client.screen import BaseScreen @@ -41,6 +39,7 @@ if DR_mod_runtime.use_DR_rust: from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, SR1Ship_rs logger = logging.getLogger('client.dr_game_sr1_ship') +sr_tr = Tr(lang_path=Path('./mods/dr_game/lang')) def get_sr1_part(part_xml: Element) -> Optional[SR1PartData]: @@ -88,7 +87,7 @@ class SR1ShipRender(BaseScreen): def __init__(self, main_window: "ClientWindow"): super().__init__(main_window) - logger.info(tr().client.sr1_render.setup.start()) + logger.info(sr_tr().mod.info.setup.start()) load_start_time = time.time_ns() self.rendered = False self.focus = True @@ -124,15 +123,16 @@ class SR1ShipRender(BaseScreen): self.part_box_batch = Batch() self.part_batch = Batch() self.part_group = Group() - self.debug_label = Label(x=20, y=main_window.height - 20, font_size=DR_status.std_font_size, + self.debug_label = Label(x=20, y=main_window.height - 100, font_size=DR_status.std_font_size, text='SR1 render!', font_name=Fonts.微软等宽无线, width=main_window.width - 20, height=20, anchor_x='left', anchor_y='top') self.part_data: Dict[int, SR1PartData] = {} self.parts_sprite: Dict[int, Sprite] = {} self.part_box_dict: Dict[int, Rectangle] = {} + self.part_line_box: Dict[int, List[Line]] = {} load_end_time = time.time_ns() - logger.info(tr().client.sr1_render.setup.use_time().format( + logger.info(sr_tr().mod.info.setup.use_time().format( (load_end_time - load_start_time) / 1000000000)) if DR_mod_runtime.use_DR_rust: self.camera_rs = CenterCamera_rs(main_window, @@ -143,7 +143,7 @@ class SR1ShipRender(BaseScreen): def load_xml(self, file_path: str) -> bool: try: start_time = time.time_ns() - logger.info(tr().client.sr1_render.xml.loading().format(file_path)) + logger.info(sr_tr().sr1.ship.xml.loading().format(file_path)) cache_doc = parse(file_path) self.xml_doc = cache_doc self.xml_root = self.xml_doc.getroot() @@ -155,8 +155,8 @@ class SR1ShipRender(BaseScreen): print(self.rust_ship.img_pos) except Exception: traceback.print_exc() - logger.info(tr().client.sr1_render.xml.load_done()) - logger.info(tr().client.sr1_render.xml.load_time().format( + logger.info(sr_tr().sr1.ship.xml.load_done()) + logger.info(sr_tr().sr1.ship.xml.load_time().format( (time.time_ns() - start_time) / 1000000000)) return True except Exception as e: @@ -191,19 +191,26 @@ class SR1ShipRender(BaseScreen): cache_sprite.y = cache_sprite.y - cache_sprite.scale_y / 2 self.parts_sprite[part.id] = cache_sprite - part_width = 100 - part_height = 100 if DR_mod_runtime.use_DR_rust: - part_type = self.part_list_rs.get_part_type(part.p_type) - if part_type is not None: - part_width = part_type.width * 15 - part_height = part_type.height * 15 - part_box = Rectangle(x=render_x, y=render_y, - width=part_width, height=part_height, - batch=self.part_box_batch, group=self.part_group) - part_box.rotation = SR1Rotation.get_rotation(part.angle) - part_box.opacity = 50 - self.part_box_dict[part.id] = part_box + part_debug_box = self.rust_ship.get_part_box(part.id) + if part_debug_box: + # 线框 + part_line_box = [] + width = 4 + color = (random.randrange(0, 255), random.randrange(0, 255), random.randrange(0, 255), random.randrange(100, 200)) + part_line_box.append(Line(x=part_debug_box[0][0] * 30, y=part_debug_box[0][1] * 30, + x2=part_debug_box[0][0] * 30, y2=part_debug_box[1][1] * 30, + batch=self.part_box_batch, width=width, color=color)) + part_line_box.append(Line(x=part_debug_box[0][0] * 30, y=part_debug_box[1][1] * 30, + x2=part_debug_box[1][0] * 30, y2=part_debug_box[1][1] * 30, + batch=self.part_box_batch, width=width, color=color)) + part_line_box.append(Line(x=part_debug_box[1][0] * 30, y=part_debug_box[1][1] * 30, + x2=part_debug_box[1][0] * 30, y2=part_debug_box[0][1] * 30, + batch=self.part_box_batch, width=width, color=color)) + part_line_box.append(Line(x=part_debug_box[1][0] * 30, y=part_debug_box[0][1] * 30, + x2=part_debug_box[0][0] * 30, y2=part_debug_box[0][1] * 30, + batch=self.part_box_batch, width=width, color=color)) + self.part_line_box[part.id] = part_line_box # if not part_render: # 如果不渲染(渲染有毛病) # self.parts_sprite[part.id].visible = False count += 1 @@ -216,10 +223,11 @@ class SR1ShipRender(BaseScreen): def render_ship(self): if self.textures is None: self.load_textures() - logger.info(tr().client.sr1_render.ship.load().format(self.xml_name)) + logger.info(sr_tr().sr1.ship.ship.load().format(self.xml_name)) start_time = time.perf_counter_ns() self.part_data: Dict[int, SR1PartData] = {} self.parts_sprite: Dict[int, Sprite] = {} + self.part_line_box = {} self.camera_rs.zoom = 1.0 if DR_mod_runtime.use_DR_rust: self.camera_rs.dx = 0 @@ -243,10 +251,10 @@ class SR1ShipRender(BaseScreen): if DR_mod_runtime.use_DR_rust: for part in self.part_data: full_mass += self.part_list_rs.get_part_type(self.part_data[part].p_type).mass * 500 - logger.info(tr().client.sr1_render.ship.load_time().format( + logger.info(sr_tr().sr1.ship.ship.load_time().format( (time.perf_counter_ns() - start_time) / 1000000000)) - logger.info(tr().client.sr1_render.ship.info().format( - len(self.part_data), f'{full_mass}kg' if DR_mod_runtime.use_DR_rust else tr().game.require_DR_rs())) + logger.info(sr_tr().sr1.ship.ship.info().format( + len(self.part_data), f'{full_mass}kg' if DR_mod_runtime.use_DR_rust else sr_tr().game.require_DR_rs())) self.rendered = True def update_parts(self) -> bool: @@ -269,7 +277,7 @@ class SR1ShipRender(BaseScreen): next(self.gen_draw) except GeneratorExit: self.drawing = False - logger.info(tr().client.sr1_render.ship.render.done()) + logger.info(sr_tr().sr1.ship.ship.render.done()) if self.need_update_parts: self.update_parts() @@ -292,6 +300,7 @@ class SR1ShipRender(BaseScreen): self.debug_mouse_delta_line.draw() def on_resize(self, width: int, height: int, window: "ClientWindow"): + self.debug_label.y = height - 100 if not self.rendered: return self.debug_line.x = width / 2 @@ -348,22 +357,26 @@ class SR1ShipRender(BaseScreen): self.need_draw = True print('应该渲染飞船的') elif command.find('debug'): - print('sr ?') if command.find('delta'): - SR1ShipRender_Option.debug_d_pos = not SR1ShipRender_Option.debug_mouse_d_pos - self.debug_line.visible = SR1ShipRender_Option.debug_d_pos - self.debug_d_pos_label.visible = SR1ShipRender_Option.debug_d_pos - # print('sr1 delta') + # SR1ShipRender_Option.debug_d_pos = not SR1ShipRender_Option.debug_mouse_d_pos + self.debug_line.visible = not self.debug_line.visible + self.debug_d_pos_label.visible = not self.debug_d_pos_label.visible + SR1ShipRender_Option.debug_d_pos = self.debug_line.visible + logger.debug('sr1 delta') elif command.find('mouse'): if command.find('delta'): SR1ShipRender_Option.debug_mouse_pos = not SR1ShipRender_Option.debug_mouse_pos self.debug_mouse_line.visible = SR1ShipRender_Option.debug_mouse_pos self.debug_mouse_label.visible = SR1ShipRender_Option.debug_mouse_pos - # print('sr1 mouse delta') + logger.debug(f'sr1 mouse delta {SR1ShipRender_Option.debug_mouse_pos}') else: - SR1ShipRender_Option.debug_mouse_d_pos = not SR1ShipRender_Option.debug_mouse_d_pos - self.debug_mouse_delta_line.visible = SR1ShipRender_Option.debug_mouse_d_pos - # print('sr1 mouse') + self.debug_mouse_delta_line.visible = not self.debug_mouse_delta_line.visible + SR1ShipRender_Option.debug_mouse_d_pos = self.debug_mouse_delta_line.visible + logger.debug(f'sr1 mouse {SR1ShipRender_Option.debug_mouse_d_pos}') + elif command.find('ship'): + if self.rendered: + for index, sprite in self.parts_sprite.items(): + sprite.visible = not sprite.visible elif command.find('get_buf'): @@ -390,7 +403,6 @@ class SR1ShipRender(BaseScreen): return img_box = self.rust_ship.img_pos img_size = (img_box[2] - img_box[0] + 1000, img_box[3] - img_box[1] + 1000) - # img_center = (abs(img_box[0]), abs(img_box[1])) # 中心点是左上角坐标 img_center = (abs(img_box[0]), abs(img_box[3])) print(f"img_box: {img_box} img_size: {img_size} img_center: {img_center}") @@ -400,23 +412,6 @@ class SR1ShipRender(BaseScreen): traceback.print_exc() print('PIL not found') return - min_x = 0 - min_y = 0 - max_x = 0 - max_y = 0 - for part, sprite in self.parts_sprite.items(): - sprite_img = sprite.image - print(f"sprite_img: {sprite_img} {sprite_img.width} {sprite_img.height}") - # 碰撞箱是居中的 - # -x, -y, +x, +y - part_data = self.part_data[part] - bound_box = [-sprite_img.width / 2 + part_data.x, -sprite_img.height / 2 + part_data.y, - sprite_img.width / 2 + part_data.x, sprite_img.height / 2 + part_data.y] - min_x = min(min_x, bound_box[0]) - min_y = min(min_y, bound_box[1]) - max_x = max(max_x, bound_box[2]) - max_y = max(max_y, bound_box[3]) - print(f"min_x: {min_x} min_y: {min_y} max_x: {max_x} max_y: {max_y}") img = Image.new('RGBA', img_size) for part, sprite in self.parts_sprite.items(): sprite_img = sprite.image