first part for phy simluation #34

Merged
shenjackyuanjie merged 19 commits from dr_game/phy_simluation into main 2023-06-22 02:11:47 +08:00
25 changed files with 296 additions and 294 deletions

View File

@ -15,7 +15,7 @@ import traceback
from pathlib import Path from pathlib import Path
from decimal import Decimal from decimal import Decimal
from typing import Callable, Dict, List, TYPE_CHECKING from typing import Callable, Dict, List, TYPE_CHECKING, Optional
# third function # third function
import rtoml import rtoml
@ -23,6 +23,7 @@ import pyglet
# from pyglet import gl # from pyglet import gl
# from pyglet.gl import glClearColor # from pyglet.gl import glClearColor
# from pyglet.libs.win32 import _user32 # from pyglet.libs.win32 import _user32
from pyglet.graphics import Group, Batch
from pyglet.window import Window from pyglet.window import Window
from pyglet.window import key, mouse 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.runtime import DR_runtime
from Difficult_Rocket.api.screen import BaseScreen from Difficult_Rocket.api.screen import BaseScreen
from Difficult_Rocket.utils.thread import new_thread 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.fps.fps_log import FpsLogger
from Difficult_Rocket.client.guis.widgets import InputBox from Difficult_Rocket.client.guis.widgets import InputBox
from Difficult_Rocket.exception.language import LanguageNotFound from Difficult_Rocket.exception.language import LanguageNotFound
from Difficult_Rocket.client.screen import DRScreen, DRDEBUGScreen
logger = logging.getLogger('client') logger = logging.getLogger('client')
@ -122,7 +123,36 @@ def pyglet_load_fonts_folder(folder) -> None:
pyglet_load_fonts_folder(os.path.join(folder, obj)) 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: def _call_screen_after(func: Callable) -> Callable:
"""
>>> @_call_screen_after
>>> def on_draw(self):
>>> pass
用于在调用窗口函数后调用子窗口函数 的装饰器
:param func: 需要包装的函数
:return: 包装后的函数
"""
@functools.wraps(func) @functools.wraps(func)
def warped(self: "ClientWindow", *args, **kwargs): def warped(self: "ClientWindow", *args, **kwargs):
result = func(self, *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: def _call_screen_before(func: Callable) -> Callable:
"""
>>> @_call_screen_before
>>> def on_draw(self):
>>> pass
用于在调用窗口函数前调用子窗口函数 的装饰器
:param func: 需要包装的函数
:return: 包装后的函数
"""
@functools.wraps(func) @functools.wraps(func)
def warped(self: "ClientWindow", *args, **kwargs): def warped(self: "ClientWindow", *args, **kwargs):
for title, a_screen in self.screen_list.items(): for title, a_screen in self.screen_list.items():
@ -185,8 +223,9 @@ class ClientWindow(Window):
self.SPF = Decimal('1') / self.FPS self.SPF = Decimal('1') / self.FPS
self.fps_log = FpsLogger(stable_fps=int(self.FPS)) self.fps_log = FpsLogger(stable_fps=int(self.FPS))
# batch # batch
self.part_batch = pyglet.graphics.Batch() self.part_batch = Batch()
self.label_batch = pyglet.graphics.Batch() self.label_batch = Batch()
self.main_group = Group(0)
# frame # frame
self.frame = pyglet.gui.Frame(self, order=20) self.frame = pyglet.gui.Frame(self, order=20)
self.M_frame = pyglet.gui.MovableFrame(self, modifier=key.LCTRL) self.M_frame = pyglet.gui.MovableFrame(self, modifier=key.LCTRL)
@ -194,9 +233,10 @@ class ClientWindow(Window):
# setup # setup
self.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, 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.push_handlers(self)
self.input_box.set_handler('on_commit', self.on_input) self.input_box.set_handler('on_commit', self.on_input)
self.set_handlers(self.input_box) self.set_handlers(self.input_box)
@ -215,9 +255,7 @@ class ClientWindow(Window):
def setup(self): def setup(self):
self.set_icon(pyglet.image.load('./textures/icon.png')) self.set_icon(pyglet.image.load('./textures/icon.png'))
self.load_fonts() self.load_fonts()
# TODO 读取配置文件,加载不同的屏幕,解耦
self.screen_list['DR_debug'] = DRDEBUGScreen(self) 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) self.game.dispatch_event('on_client_start', game=self.game, client=self)
def load_fonts(self) -> None: def load_fonts(self) -> None:
@ -264,6 +302,10 @@ class ClientWindow(Window):
now_FPS = pyglet.clock.get_frequency() now_FPS = pyglet.clock.get_frequency()
self.fps_log.update_tick(now_FPS, decimal_tick) 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 @_call_screen_after
def on_draw(self, *dt): def on_draw(self, *dt):
while command := self.game.console.get_command(): while command := self.game.console.get_command():
@ -306,10 +348,15 @@ class ClientWindow(Window):
self.on_command(command_text) self.on_command(command_text)
self.input_box.value = '' self.input_box.value = ''
def new_command(self):
self.game.console.new_command()
@_call_back(new_command)
@_call_screen_after @_call_screen_after
def on_command(self, command: line.CommandText): 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)) self.logger.info(tr().window.command.text().format(command))
command.find('/')
if command.find('stop'): if command.find('stop'):
# self.dispatch_event('on_exit') # self.dispatch_event('on_exit')
print("command stop!") print("command stop!")
@ -335,8 +382,9 @@ class ClientWindow(Window):
except LanguageNotFound: except LanguageNotFound:
self.logger.info(tr().language_available().format(os.listdir('./configs/lang'))) self.logger.info(tr().language_available().format(os.listdir('./configs/lang')))
self.save_info() self.save_info()
elif command.find('mods'):
# self.command_tree.parse(command.plain_command) for mod in self.game.mod_module:
self.logger.info(f"mod: {mod.name} id: {mod.mod_id} version: {mod.version}")
@_call_screen_after @_call_screen_after
def on_message(self, message: line.CommandText): def on_message(self, message: line.CommandText):

View File

@ -7,24 +7,17 @@
import typing import typing
from pyglet.text import Label from pyglet.text import Label
from pyglet.graphics import Batch, Group
from pyglet.clock import get_frequency from pyglet.clock import get_frequency
from pyglet.graphics import Batch, Group
# Difficult Rocket function # Difficult Rocket function
from Difficult_Rocket.api.types import Fonts from Difficult_Rocket.api.types import Fonts
# from Difficult_Rocket.utils import translate
from Difficult_Rocket.api.screen import BaseScreen from Difficult_Rocket.api.screen import BaseScreen
# from Difficult_Rocket.command.tree import CommandTree
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from Difficult_Rocket.client import ClientWindow from Difficult_Rocket.client import ClientWindow
class DRScreen(BaseScreen):
def __init__(self, main_window: "ClientWindow"):
super().__init__(main_window)
class DRDEBUGScreen(BaseScreen): class DRDEBUGScreen(BaseScreen):
def __init__(self, main_window: "ClientWindow"): def __init__(self, main_window: "ClientWindow"):
super().__init__(main_window) super().__init__(main_window)
@ -55,4 +48,3 @@ class DRDEBUGScreen(BaseScreen):
def on_draw(self, *dt, window: "ClientWindow"): def on_draw(self, *dt, window: "ClientWindow"):
self.main_batch.draw() self.main_batch.draw()
# print(self.window_pointer.try_if_runs)

View File

@ -44,10 +44,13 @@ class CommandText:
i += 1 i += 1
def find(self, text: str) -> bool: def find(self, text: str) -> bool:
find = self.text.find(text) startswith = self.text.startswith(text)
if find != -1: if startswith:
self.text = self.text[find + len(text):] find = self.text.find(text)
return True 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 return False
def re_find(self, text: str) -> Union[str, bool]: def re_find(self, text: str) -> Union[str, bool]:

View File

@ -65,6 +65,9 @@ class Console(Options):
def get_command(self) -> Optional[str]: def get_command(self) -> Optional[str]:
return self.caches.pop(0) if self.caches else None return self.caches.pop(0) if self.caches else None
def new_command(self) -> None:
return None
class Game(Options): class Game(Options):
name = 'MainGame' name = 'MainGame'

View File

@ -16,20 +16,19 @@ import sys
import time import time
import math import math
import json import json
import rtoml
import logging import logging
import configparser import configparser
from typing import Union from pathlib import Path
from typing import Union, Optional
from xml.etree import ElementTree from xml.etree import ElementTree
import rtoml
from defusedxml.ElementTree import parse from defusedxml.ElementTree import parse
from Difficult_Rocket.exception.unsupport import NoMoreJson5 from Difficult_Rocket.exception.unsupport import NoMoreJson5
# logger # logger
tools_logger = logging.getLogger('part-tools') tools_logger = logging.getLogger('tools')
""" """
file configs 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}'} 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, def load_file(file_name: Union[str, Path],
stack: Union[str, list, dict, None] = None, stack: Optional[Union[str, list, dict]] = None,
raise_error: bool = True, raise_error: Optional[bool] = True,
encoding: str = 'utf-8') -> Union[dict, ElementTree.ElementTree]: 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:] # 从最后一个.到末尾 (截取文件格式) f_type = file_name[file_name.rfind('.') + 1:] # 从最后一个.到末尾 (截取文件格式)
get_file = NotImplementedError('解析失败,请检查文件类型/文件内容/文件是否存在!') get_file = NotImplementedError('解析失败,请检查文件类型/文件内容/文件是否存在!')
try: try:

View File

@ -14,6 +14,7 @@ gitee: @shenjackyuanjie
import os import os
import inspect import inspect
from pathlib import Path
from dataclasses import dataclass from dataclasses import dataclass
from typing import Union, Tuple, Any, List, Dict, Hashable, Optional from typing import Union, Tuple, Any, List, Dict, Hashable, Optional
@ -153,15 +154,16 @@ class Tr:
GOOD 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 诶嘿我抄的MCDR
:param language: Tr 所使用的的语言 :param language: Tr 所使用的的语言
:param config: 配置 :param config: 配置
""" """
self.language_name = language if language is not None else DR_runtime.language 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.language_path = lang_path if lang_path is not None else Path('configs/lang')
self.default_translate: Dict = tools.load_file(f'configs/lang/{DR_status.default_language}.toml') 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.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()) self.translates_cache = Translates(value=self.translates, config=self.default_config.copy())
@ -185,11 +187,11 @@ class Tr:
if lang == ' ' or lang == '': if lang == ' ' or lang == '':
raise LanguageNotFound('Can not be empty') raise LanguageNotFound('Can not be empty')
lang = lang or self.language_name lang = lang or self.language_name
if not os.path.exists(f'./configs/lang/{lang}.toml'): if not os.path.exists(f'{self.language_path}/{lang}.toml'):
print(f"lang: {os.path.exists(f'./configs/lang/{lang}.toml')} language = {lang} {self.language_name=}") print(f"lang: {os.path.exists(f'{self.language_path}/{lang}.toml')} language = {lang} {self.language_name=}")
raise LanguageNotFound(lang) raise LanguageNotFound(lang)
self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'configs/lang/{lang}.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'configs/lang/{DR_runtime.default_language}.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.translates_cache = Translates(value=self.translates, config=self.default_config.copy())
self.language_name = lang self.language_name = lang
DR_runtime.language = self.language_name DR_runtime.language = self.language_name

View File

@ -75,14 +75,3 @@ input = "console"
window = "window" window = "window"
command = "in game commands" command = "in game commands"
require_DR_rs = "require DR_rs module" 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"

View File

@ -75,15 +75,3 @@ input = "控制台"
window = "窗口" window = "窗口"
command = "游戏内命令行" command = "游戏内命令行"
require_DR_rs = "需要 DR_rs 模块" 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 = "飞船渲染完成"

View File

@ -7,8 +7,8 @@ fonts_folder = "libs/fonts"
[window] [window]
style = "None" style = "None"
width = 1021 width = 1041
height = 1078 height = 1050
visible = true visible = true
gui_scale = 1 gui_scale = 1
caption = "Difficult Rocket v{DR_version}" caption = "Difficult Rocket v{DR_version}"

View File

@ -3,7 +3,24 @@
- 最新版本号 - 最新版本号
- DR game: 0.2.0.0 - 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 ## DR game 0.2.0.0

View File

@ -11,6 +11,21 @@
- issue #33 (https://github.com/shenjackyuanjie/Difficult-Rocket/issues/33) - issue #33 (https://github.com/shenjackyuanjie/Difficult-Rocket/issues/33)
- 修复了实际上并不会加载 `.otf` 格式的字体文件的问题 - 修复了实际上并不会加载 `.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 ## DR sdk 0.8.3.0
### 删除 ### 删除

View File

@ -121,9 +121,11 @@ if TYPE_CHECKING:
@property @property
def img_pos(self) -> Tuple[int, int, int, int]: ... def img_pos(self) -> Tuple[int, int, int, int]: ...
""" -x -y +x +y 左下右上 """ """ -x -y +x +y 左下右上 """
def get_part_box(self, part_id: int) -> Optional[Tuple[Tuple[int, int], Tuple[int, int]]]: ...
class Console_rs: class Console_rs:
def __init__(self) -> None: ... def __init__(self) -> None: ...
def start(self) -> None: ... def start(self) -> None: ...
def stop(self) -> bool: ... def stop(self) -> bool: ...
def get_command(self) -> Optional[str]: ... def get_command(self) -> Optional[str]: ...
def new_command(self) -> bool: ...

View File

@ -13,9 +13,9 @@ dependencies = [
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.2" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
@ -84,14 +84,14 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.14" version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if", "cfg-if",
"crossbeam-utils", "crossbeam-utils",
"memoffset", "memoffset 0.9.0",
"scopeguard", "scopeguard",
] ]
@ -107,9 +107,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.15" version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -167,9 +167,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.18" version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]] [[package]]
name = "matrixmultiply" name = "matrixmultiply"
@ -190,6 +190,15 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "nalgebra" name = "nalgebra"
version = "0.32.2" version = "0.32.2"
@ -348,7 +357,7 @@ dependencies = [
"cfg-if", "cfg-if",
"indoc", "indoc",
"libc", "libc",
"memoffset", "memoffset 0.8.0",
"parking_lot", "parking_lot",
"pyo3-build-config", "pyo3-build-config",
"pyo3-ffi", "pyo3-ffi",

View File

@ -12,7 +12,7 @@ package_path = 'Difficult_Rocket_rs'
setup( setup(
name='Difficult_Rocket_rs', name='Difficult_Rocket_rs',
version="0.2.10.1", version="0.2.11.0",
author='shenjackyuanjie', author='shenjackyuanjie',
author_email='3695888@qq.com', author_email='3695888@qq.com',
rust_extensions=[RustExtension(target="Difficult_Rocket_rs.Difficult_Rocket_rs", rust_extensions=[RustExtension(target="Difficult_Rocket_rs.Difficult_Rocket_rs",

View File

@ -12,6 +12,7 @@ mod python;
mod render; mod render;
mod simulator; mod simulator;
mod sr1_data; mod sr1_data;
mod translate;
mod types; mod types;
use pyo3::prelude::*; use pyo3::prelude::*;
@ -26,7 +27,7 @@ enum LoadState {
} }
#[pyfunction] #[pyfunction]
fn get_version_str() -> String { "0.2.10.1".to_string() } fn get_version_str() -> String { "0.2.11.0".to_string() }
#[pyfunction] #[pyfunction]
fn test_call(py_obj: &PyAny) -> PyResult<bool> { fn test_call(py_obj: &PyAny) -> PyResult<bool> {
@ -42,7 +43,6 @@ fn test_call(py_obj: &PyAny) -> PyResult<bool> {
fn module_init(_py: Python<'_>, m: &PyModule) -> PyResult<()> { fn module_init(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(get_version_str, m)?)?; m.add_function(wrap_pyfunction!(get_version_str, m)?)?;
m.add_function(wrap_pyfunction!(test_call, 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::part_list::read_part_list_py, m)?)?;
m.add_function(wrap_pyfunction!(sr1_data::ship::py_raw_ship_from_file, m)?)?; m.add_function(wrap_pyfunction!(sr1_data::ship::py_raw_ship_from_file, m)?)?;
m.add_class::<render::camera::CameraRs>()?; m.add_class::<render::camera::CameraRs>()?;

View File

@ -12,6 +12,7 @@
/// 插件加载 /// 插件加载
/// ///
#[allow(unused)]
pub mod plugin_trait { pub mod plugin_trait {
pub struct ModInfo { pub struct ModInfo {
pub name: String, pub name: String,

View File

@ -12,6 +12,7 @@ pub mod data {
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::sr1_data::part_list::RawPartList; 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::{get_max_box, SR1PartData, SR1PartListTrait};
use crate::types::sr1::{SR1PartList, SR1PartType, SR1Ship}; use crate::types::sr1::{SR1PartList, SR1PartType, SR1Ship};
@ -142,96 +143,35 @@ pub mod data {
} }
parts 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 { pub mod translate {
use pyo3::prelude::*; use crate::translate;
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<String>) -> 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::<String>().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<PyAny>,
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::<PyDict>();
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() }
}
} }
pub mod console { pub mod console {
use pyo3::prelude::*; use pyo3::prelude::*;
use std::io::{self, Write};
#[pyclass] #[pyclass]
#[pyo3(name = "Console_rs")] #[pyo3(name = "Console_rs")]
@ -255,7 +195,7 @@ pub mod console {
let (stop_sender, stop_receiver) = std::sync::mpsc::channel(); let (stop_sender, stop_receiver) = std::sync::mpsc::channel();
let (keyboard_input_sender, keyboard_input_receiver) = std::sync::mpsc::channel(); let (keyboard_input_sender, keyboard_input_receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || { std::thread::spawn(move || {
let std_in = std::io::stdin(); let std_in = io::stdin();
loop { loop {
if let Ok(()) = stop_receiver.try_recv() { if let Ok(()) = stop_receiver.try_recv() {
break; break;
@ -265,9 +205,10 @@ pub mod console {
if !input.is_empty() { if !input.is_empty() {
keyboard_input_sender.send(input).unwrap(); keyboard_input_sender.send(input).unwrap();
} }
print!(">>");
} }
}); });
print!("rs>");
io::stdout().flush().unwrap();
self.stop_sender = Some(stop_sender); self.stop_sender = Some(stop_sender);
self.keyboard_input_receiver = Some(keyboard_input_receiver); self.keyboard_input_receiver = Some(keyboard_input_receiver);
} }
@ -280,6 +221,12 @@ pub mod console {
false false
} }
fn new_command(&self) -> bool {
print!("rs>");
io::stdout().flush().unwrap();
true
}
fn get_command(&self) -> Option<String> { fn get_command(&self) -> Option<String> {
// 获取输入 // 获取输入
if let Some(receiver) = &self.keyboard_input_receiver { if let Some(receiver) = &self.keyboard_input_receiver {

View File

@ -9,6 +9,7 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use rapier2d_f64::prelude::*; use rapier2d_f64::prelude::*;
#[allow(unused)]
#[pyfunction] #[pyfunction]
#[pyo3(name = "simulation")] #[pyo3(name = "simulation")]
pub fn 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::*; use rapier2d_f64::prelude::*;
pub struct PhysicsSpace {
pub rigid_body_set: RigidBodySet,
pub collider_set: ColliderSet,
pub gravity: Vector<f64>,
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,
);
}
}
} }

View File

@ -0,0 +1,16 @@
/*
* -------------------------------
* Difficult Rocket
* Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
* All rights reserved
* -------------------------------
*/
use std::collections::HashMap;
type TranslateMapper = HashMap<String, HashMap<String, HashMap<String, String>>>;
pub struct Translater {
pub data: TranslateMapper,
pub language: String,
}

View File

@ -197,9 +197,13 @@ pub mod sr1 {
} }
impl SR1PartType { impl SR1PartType {
pub fn get_box(&self) -> (f64, f64, f64, f64) { pub fn get_box(&self) -> ((f64, f64), (f64, f64)) {
let x = self.width as f64 / 2.0; // -x, -y, x, y
(-x, 0.0, x, self.height as f64) // 居中
(
(-(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); let mut max_box = (0_f64, 0_f64, 0_f64, 0_f64);
for part in parts.iter() { for part in parts.iter() {
let part_type = part_list.get_part_type(part.part_type_id.clone()).unwrap(); 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 // rotate
let mut p1 = Point2D::new(x1, y1); let mut p1 = Point2D::new(x1, y1);
let mut p2 = Point2D::new(x2, y2); let mut p2 = Point2D::new(x2, y2);
p1.rotate_radius_mut(part.angle); p1.rotate_radius_mut(part.angle);
p2.rotate_radius_mut(part.angle); p2.rotate_radius_mut(part.angle);
let p1 = p1.add(part.x, part.y); let p1 = p1.add(part.x * 2.0, part.y * 2.0);
let p2 = p2.add(part.x, part.y); 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); let (x1, y1, x2, y2) = (p1.x, p1.y, p2.x, p2.y);
// get max box // get max box
max_box.0 = max_box.0.min(x1).min(part.x); max_box.0 = max_box.0.min(x1).min(part.x);
@ -835,6 +839,12 @@ pub mod math {
#[inline] #[inline]
pub fn add(&self, x: f64, y: f64) -> Self { Point2D::new(self.x + x, self.y + y) } 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 { impl Rotatable for Point2D {

View File

@ -17,7 +17,7 @@ from Difficult_Rocket.api.mod import ModInfo
from Difficult_Rocket.client import ClientWindow from Difficult_Rocket.client import ClientWindow
from Difficult_Rocket.api.types import Options, Version 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') logger = logging.getLogger('client.dr_game')

View File

@ -22,3 +22,6 @@ class RustConsole(Console):
def get_command(self) -> str: def get_command(self) -> str:
return self.console.get_command() return self.console.get_command()
def new_command(self) -> None:
self.console.new_command()

View File

@ -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"

View File

@ -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 = "飞船渲染完成"

View File

@ -9,26 +9,24 @@ import time
import random import random
import logging import logging
import traceback import traceback
# from xml.etree import ElementTree
from pathlib import Path
from xml.etree.ElementTree import Element from xml.etree.ElementTree import Element
from typing import List, TYPE_CHECKING, Union, Dict, Optional, Generator from typing import List, TYPE_CHECKING, Union, Dict, Optional, Generator
# third party package
from defusedxml.ElementTree import parse from defusedxml.ElementTree import parse
# pyglet
from pyglet.math import Vec4 from pyglet.math import Vec4
from pyglet.text import Label from pyglet.text import Label
from pyglet.shapes import Line, Rectangle
from pyglet.sprite import Sprite from pyglet.sprite import Sprite
# from pyglet.image import Texture # from pyglet.image import Texture
from pyglet.graphics import Batch, Group from pyglet.graphics import Batch, Group
from pyglet.shapes import Line, Rectangle
from . import DR_mod_runtime from . import DR_mod_runtime
# Difficult Rocket # Difficult Rocket
from Difficult_Rocket import DR_status 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.api.types import Fonts, Options
from Difficult_Rocket.command.line import CommandText from Difficult_Rocket.command.line import CommandText
from Difficult_Rocket.client.screen import BaseScreen 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 from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, SR1Ship_rs
logger = logging.getLogger('client.dr_game_sr1_ship') 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]: def get_sr1_part(part_xml: Element) -> Optional[SR1PartData]:
@ -88,7 +87,7 @@ class SR1ShipRender(BaseScreen):
def __init__(self, def __init__(self,
main_window: "ClientWindow"): main_window: "ClientWindow"):
super().__init__(main_window) 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() load_start_time = time.time_ns()
self.rendered = False self.rendered = False
self.focus = True self.focus = True
@ -124,15 +123,16 @@ class SR1ShipRender(BaseScreen):
self.part_box_batch = Batch() self.part_box_batch = Batch()
self.part_batch = Batch() self.part_batch = Batch()
self.part_group = Group() 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.微软等宽无线, text='SR1 render!', font_name=Fonts.微软等宽无线,
width=main_window.width - 20, height=20, width=main_window.width - 20, height=20,
anchor_x='left', anchor_y='top') anchor_x='left', anchor_y='top')
self.part_data: Dict[int, SR1PartData] = {} self.part_data: Dict[int, SR1PartData] = {}
self.parts_sprite: Dict[int, Sprite] = {} self.parts_sprite: Dict[int, Sprite] = {}
self.part_box_dict: Dict[int, Rectangle] = {} self.part_box_dict: Dict[int, Rectangle] = {}
self.part_line_box: Dict[int, List[Line]] = {}
load_end_time = time.time_ns() 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)) (load_end_time - load_start_time) / 1000000000))
if DR_mod_runtime.use_DR_rust: if DR_mod_runtime.use_DR_rust:
self.camera_rs = CenterCamera_rs(main_window, self.camera_rs = CenterCamera_rs(main_window,
@ -143,7 +143,7 @@ class SR1ShipRender(BaseScreen):
def load_xml(self, file_path: str) -> bool: def load_xml(self, file_path: str) -> bool:
try: try:
start_time = time.time_ns() 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) cache_doc = parse(file_path)
self.xml_doc = cache_doc self.xml_doc = cache_doc
self.xml_root = self.xml_doc.getroot() self.xml_root = self.xml_doc.getroot()
@ -155,8 +155,8 @@ class SR1ShipRender(BaseScreen):
print(self.rust_ship.img_pos) print(self.rust_ship.img_pos)
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
logger.info(tr().client.sr1_render.xml.load_done()) logger.info(sr_tr().sr1.ship.xml.load_done())
logger.info(tr().client.sr1_render.xml.load_time().format( logger.info(sr_tr().sr1.ship.xml.load_time().format(
(time.time_ns() - start_time) / 1000000000)) (time.time_ns() - start_time) / 1000000000))
return True return True
except Exception as e: except Exception as e:
@ -191,19 +191,26 @@ class SR1ShipRender(BaseScreen):
cache_sprite.y = cache_sprite.y - cache_sprite.scale_y / 2 cache_sprite.y = cache_sprite.y - cache_sprite.scale_y / 2
self.parts_sprite[part.id] = cache_sprite self.parts_sprite[part.id] = cache_sprite
part_width = 100
part_height = 100
if DR_mod_runtime.use_DR_rust: if DR_mod_runtime.use_DR_rust:
part_type = self.part_list_rs.get_part_type(part.p_type) part_debug_box = self.rust_ship.get_part_box(part.id)
if part_type is not None: if part_debug_box:
part_width = part_type.width * 15 # 线框
part_height = part_type.height * 15 part_line_box = []
part_box = Rectangle(x=render_x, y=render_y, width = 4
width=part_width, height=part_height, color = (random.randrange(0, 255), random.randrange(0, 255), random.randrange(0, 255), random.randrange(100, 200))
batch=self.part_box_batch, group=self.part_group) part_line_box.append(Line(x=part_debug_box[0][0] * 30, y=part_debug_box[0][1] * 30,
part_box.rotation = SR1Rotation.get_rotation(part.angle) x2=part_debug_box[0][0] * 30, y2=part_debug_box[1][1] * 30,
part_box.opacity = 50 batch=self.part_box_batch, width=width, color=color))
self.part_box_dict[part.id] = part_box 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: # 如果不渲染(渲染有毛病) # if not part_render: # 如果不渲染(渲染有毛病)
# self.parts_sprite[part.id].visible = False # self.parts_sprite[part.id].visible = False
count += 1 count += 1
@ -216,10 +223,11 @@ class SR1ShipRender(BaseScreen):
def render_ship(self): def render_ship(self):
if self.textures is None: if self.textures is None:
self.load_textures() 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() start_time = time.perf_counter_ns()
self.part_data: Dict[int, SR1PartData] = {} self.part_data: Dict[int, SR1PartData] = {}
self.parts_sprite: Dict[int, Sprite] = {} self.parts_sprite: Dict[int, Sprite] = {}
self.part_line_box = {}
self.camera_rs.zoom = 1.0 self.camera_rs.zoom = 1.0
if DR_mod_runtime.use_DR_rust: if DR_mod_runtime.use_DR_rust:
self.camera_rs.dx = 0 self.camera_rs.dx = 0
@ -243,10 +251,10 @@ class SR1ShipRender(BaseScreen):
if DR_mod_runtime.use_DR_rust: if DR_mod_runtime.use_DR_rust:
for part in self.part_data: for part in self.part_data:
full_mass += self.part_list_rs.get_part_type(self.part_data[part].p_type).mass * 500 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)) (time.perf_counter_ns() - start_time) / 1000000000))
logger.info(tr().client.sr1_render.ship.info().format( 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 tr().game.require_DR_rs())) 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 self.rendered = True
def update_parts(self) -> bool: def update_parts(self) -> bool:
@ -269,7 +277,7 @@ class SR1ShipRender(BaseScreen):
next(self.gen_draw) next(self.gen_draw)
except GeneratorExit: except GeneratorExit:
self.drawing = False 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: if self.need_update_parts:
self.update_parts() self.update_parts()
@ -292,6 +300,7 @@ class SR1ShipRender(BaseScreen):
self.debug_mouse_delta_line.draw() self.debug_mouse_delta_line.draw()
def on_resize(self, width: int, height: int, window: "ClientWindow"): def on_resize(self, width: int, height: int, window: "ClientWindow"):
self.debug_label.y = height - 100
if not self.rendered: if not self.rendered:
return return
self.debug_line.x = width / 2 self.debug_line.x = width / 2
@ -348,22 +357,26 @@ class SR1ShipRender(BaseScreen):
self.need_draw = True self.need_draw = True
print('应该渲染飞船的') print('应该渲染飞船的')
elif command.find('debug'): elif command.find('debug'):
print('sr ?')
if command.find('delta'): if command.find('delta'):
SR1ShipRender_Option.debug_d_pos = not SR1ShipRender_Option.debug_mouse_d_pos # SR1ShipRender_Option.debug_d_pos = not SR1ShipRender_Option.debug_mouse_d_pos
self.debug_line.visible = SR1ShipRender_Option.debug_d_pos self.debug_line.visible = not self.debug_line.visible
self.debug_d_pos_label.visible = SR1ShipRender_Option.debug_d_pos self.debug_d_pos_label.visible = not self.debug_d_pos_label.visible
# print('sr1 delta') SR1ShipRender_Option.debug_d_pos = self.debug_line.visible
logger.debug('sr1 delta')
elif command.find('mouse'): elif command.find('mouse'):
if command.find('delta'): if command.find('delta'):
SR1ShipRender_Option.debug_mouse_pos = not SR1ShipRender_Option.debug_mouse_pos SR1ShipRender_Option.debug_mouse_pos = not SR1ShipRender_Option.debug_mouse_pos
self.debug_mouse_line.visible = 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 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: else:
SR1ShipRender_Option.debug_mouse_d_pos = not SR1ShipRender_Option.debug_mouse_d_pos self.debug_mouse_delta_line.visible = not self.debug_mouse_delta_line.visible
self.debug_mouse_delta_line.visible = SR1ShipRender_Option.debug_mouse_d_pos SR1ShipRender_Option.debug_mouse_d_pos = self.debug_mouse_delta_line.visible
# print('sr1 mouse') 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'): elif command.find('get_buf'):
@ -390,7 +403,6 @@ class SR1ShipRender(BaseScreen):
return return
img_box = self.rust_ship.img_pos img_box = self.rust_ship.img_pos
img_size = (img_box[2] - img_box[0] + 1000, img_box[3] - img_box[1] + 1000) 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])) img_center = (abs(img_box[0]), abs(img_box[3]))
print(f"img_box: {img_box} img_size: {img_size} img_center: {img_center}") print(f"img_box: {img_box} img_size: {img_size} img_center: {img_center}")
@ -400,23 +412,6 @@ class SR1ShipRender(BaseScreen):
traceback.print_exc() traceback.print_exc()
print('PIL not found') print('PIL not found')
return 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) img = Image.new('RGBA', img_size)
for part, sprite in self.parts_sprite.items(): for part, sprite in self.parts_sprite.items():
sprite_img = sprite.image sprite_img = sprite.image