Merge pull request #35 from shenjackyuanjie/feature/py_camera
Feature/py camera
This commit is contained in:
commit
c51b86ba9b
123
Difficult_Rocket/utils/camera.py
Normal file
123
Difficult_Rocket/utils/camera.py
Normal file
@ -0,0 +1,123 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
# Huge thanks to pyglet developers
|
||||
|
||||
from typing import Tuple, Optional
|
||||
|
||||
|
||||
class Camera:
|
||||
"""
|
||||
|
||||
>>> from pyglet.window import Window
|
||||
>>> window = Window()
|
||||
|
||||
>>> camera = Camera(window)
|
||||
>>> @window.event
|
||||
|
||||
>>> def on_draw():
|
||||
>>> camera.begin()
|
||||
>>> window.clear()
|
||||
>>> camera.end()
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
window,
|
||||
zoom: Optional[float] = 1.0,
|
||||
dx: Optional[float] = 1.0,
|
||||
dy: Optional[float] = 1.0,
|
||||
min_zoom: Optional[float] = 1.0,
|
||||
max_zoom: Optional[float] = 1.0) -> None:
|
||||
self.window = window
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
self.zoom = zoom
|
||||
self.min_zoom = min_zoom
|
||||
self.max_zoom = max_zoom
|
||||
|
||||
def get_view(self):
|
||||
return self.window.view
|
||||
|
||||
@property
|
||||
def position(self) -> Tuple[float, float]:
|
||||
return self.dx, self.dy
|
||||
|
||||
@position.setter
|
||||
def position(self, value: Tuple[float, float]):
|
||||
self.dx, self.dy = value
|
||||
|
||||
@property
|
||||
def zoom_level(self) -> float:
|
||||
return self.zoom
|
||||
|
||||
@zoom_level.setter
|
||||
def zoom_level(self, value: float) -> None:
|
||||
self.zoom = min(max(value, self.min_zoom), self.max_zoom)
|
||||
|
||||
def begin(self) -> None:
|
||||
view = self.window.view
|
||||
x = self.window.width / self.zoom + (self.dx / self.zoom)
|
||||
y = self.window.height / self.zoom + (self.dy / self.zoom)
|
||||
|
||||
view_matrix = view.translate((x * self.zoom, y * self.zoom, 0))
|
||||
view_matrix = view_matrix.scale((self.zoom, self.zoom, 1))
|
||||
|
||||
self.window.view = view_matrix
|
||||
|
||||
def end(self) -> None:
|
||||
view = self.window.view
|
||||
x = self.window.width / self.zoom + (self.dx / self.zoom)
|
||||
y = self.window.height / self.zoom + (self.dy / self.zoom)
|
||||
|
||||
view_matrix = view.scale((1.0 / self.zoom, 1.0 / self.zoom, 1))
|
||||
view_matrix = view_matrix.translate((-x * self.zoom, -y * self.zoom, 0))
|
||||
|
||||
self.window.view = view_matrix
|
||||
|
||||
def __enter__(self):
|
||||
self.begin()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.end()
|
||||
|
||||
|
||||
class CenterCamera(Camera):
|
||||
"""
|
||||
A camera that centers the view on the center of the window
|
||||
|
||||
>>> from pyglet.window import Window
|
||||
>>> window = Window()
|
||||
|
||||
>>> camera = CenterCamera(window)
|
||||
>>> @window.event
|
||||
|
||||
>>> def on_draw():
|
||||
>>> camera.begin()
|
||||
>>> window.clear()
|
||||
>>> camera.end()
|
||||
|
||||
"""
|
||||
def begin(self) -> None:
|
||||
view = self.window.view
|
||||
x = self.window.width / 2.0 / self.zoom + (self.dx / self.zoom)
|
||||
y = self.window.height / 2.0 / self.zoom + (self.dy / self.zoom)
|
||||
|
||||
view_matrix = view.translate((x * self.zoom, y * self.zoom, 0))
|
||||
view_matrix = view_matrix.scale((self.zoom, self.zoom, 1))
|
||||
|
||||
self.window.view = view_matrix
|
||||
|
||||
def end(self) -> None:
|
||||
view = self.window.view
|
||||
x = self.window.width / 2.0 / self.zoom + (self.dx / self.zoom)
|
||||
y = self.window.height / 2.0 / self.zoom + (self.dy / self.zoom)
|
||||
|
||||
view_matrix = view.scale((1.0 / self.zoom, 1.0 / self.zoom, 1))
|
||||
view_matrix = view_matrix.translate((-x * self.zoom, -y * self.zoom, 0))
|
||||
|
||||
self.window.view = view_matrix
|
||||
|
@ -12,16 +12,16 @@
|
||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
||||
[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
|
||||
[![Generic badge](https://img.shields.io/badge/编写于_Python_版本-3.8.10-blue.svg)](https://Python.org)
|
||||
[![Generic badge](https://img.shields.io/badge/编写于_Pyglet_版本-2.0.7-blue.svg)](https://pyglet.org)
|
||||
[![Generic badge](https://img.shields.io/badge/编写于_Pyglet_版本-2.0.8-blue.svg)](https://pyglet.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_|_3.11_-blue.svg)](https://Python.org)
|
||||
|
||||
## 版本
|
||||
|
||||
[关于版本号的说明](./docs/src/version.md)
|
||||
|
||||
[![Generic badge](https://img.shields.io/badge/Release-0.8.3.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Release-0.8.4.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Pre_Release-0.8.4.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Devloping-0.8.4-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Devloping-0.8.5-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
|
||||
[![language badge](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)
|
||||
|
||||
|
@ -7,8 +7,8 @@ fonts_folder = "libs/fonts"
|
||||
|
||||
[window]
|
||||
style = "None"
|
||||
width = 1041
|
||||
height = 1050
|
||||
width = 1918
|
||||
height = 2088
|
||||
visible = true
|
||||
gui_scale = 1
|
||||
caption = "Difficult Rocket v{DR_version}"
|
||||
|
@ -12,16 +12,16 @@
|
||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
||||
[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
|
||||
[![Generic badge](https://img.shields.io/badge/Write_with_Python-3.8.10-blue.svg)](https://Python.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Write_with_Pyglet-2.0.5-blue.svg)](https://pyglet.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Write_with_Pyglet-2.0.8-blue.svg)](https://pyglet.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_|_3.11_-blue.svg)](https://Python.org)
|
||||
|
||||
## Version
|
||||
|
||||
[About Versions](src/version.md)
|
||||
|
||||
[![Generic badge](https://img.shields.io/badge/Release-0.8.3.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Release-0.8.4.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Pre_Release-0.8.4.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Devloping-0.8.4-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Devloping-0.8.5-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
|
||||
[![language badge](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)
|
||||
|
||||
|
@ -3,7 +3,27 @@
|
||||
|
||||
- 最新版本号
|
||||
- DR game: 0.2.0.0
|
||||
- DR rs: 0.2.11.0
|
||||
- DR rs: 0.2.13.0
|
||||
|
||||
## DR game 0.2.1.0
|
||||
|
||||
### 修改
|
||||
|
||||
- 将 `sr1_ship` 中的 `Camera_rs` 改为 `Difficult_Rocket.utils.camera.Camera`
|
||||
|
||||
## DR rs 0.2.13.0
|
||||
|
||||
### 删除
|
||||
|
||||
- 删除了 `render.rs`
|
||||
- 没必要拿 rust 写这玩意(
|
||||
- 用 `DR game` 的 `camera` 代替
|
||||
|
||||
## DR rs 0.2.12.0
|
||||
|
||||
### 添加
|
||||
|
||||
- 添加了 xml 的读取测试
|
||||
|
||||
## DR game 0.1.2.0
|
||||
|
||||
|
@ -2,13 +2,23 @@
|
||||
# DR SDK 更新日志
|
||||
|
||||
- 最新版本号
|
||||
- DR sdk: 0.8.3.0
|
||||
- DR sdk: 0.8.4.0
|
||||
|
||||
## DR sdk 0.8.4.1
|
||||
|
||||
### Add
|
||||
|
||||
- `utils.camera`
|
||||
- `Camera`
|
||||
- 一个 2D 摄影机,可以用于高效变换渲染坐标
|
||||
- `CenterCamera`
|
||||
- 一个中心对器的 2D 摄影机,可以用于高效变换渲染坐标
|
||||
|
||||
## DR sdk 0.8.4.0
|
||||
|
||||
### Fix
|
||||
|
||||
- issue #33 (https://github.com/shenjackyuanjie/Difficult-Rocket/issues/33)
|
||||
- issue #33 (<https://github.com/shenjackyuanjie/Difficult-Rocket/issues/33>)
|
||||
- 修复了实际上并不会加载 `.otf` 格式的字体文件的问题
|
||||
|
||||
### language
|
||||
|
@ -9,7 +9,7 @@ import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
#: The release version
|
||||
version = '2.0.7'
|
||||
version = '2.0.8'
|
||||
__version__ = version
|
||||
|
||||
MIN_PYTHON_VERSION = 3, 8
|
||||
|
@ -4,6 +4,7 @@ import fcntl
|
||||
import ctypes
|
||||
import warnings
|
||||
|
||||
from os import readv
|
||||
from ctypes import c_uint16 as _u16
|
||||
from ctypes import c_int16 as _s16
|
||||
from ctypes import c_uint32 as _u32
|
||||
@ -306,7 +307,6 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
self._filename = filename
|
||||
|
||||
fileno = os.open(filename, os.O_RDONLY)
|
||||
# event_version = EVIOCGVERSION(fileno).value
|
||||
|
||||
self._id = EVIOCGID(fileno)
|
||||
self.id_bustype = self._id.bustype
|
||||
@ -357,6 +357,9 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
self.controls.sort(key=lambda c: c._event_code)
|
||||
os.close(fileno)
|
||||
|
||||
self._event_size = ctypes.sizeof(InputEvent)
|
||||
self._event_buffer = (InputEvent * 64)()
|
||||
|
||||
super().__init__(display, name)
|
||||
|
||||
def get_guid(self):
|
||||
@ -405,17 +408,16 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
return
|
||||
|
||||
try:
|
||||
events = (InputEvent * 64)()
|
||||
bytes_read = os.readv(self._fileno, events)
|
||||
bytes_read = readv(self._fileno, self._event_buffer)
|
||||
except OSError:
|
||||
self.close()
|
||||
return
|
||||
|
||||
n_events = bytes_read // ctypes.sizeof(InputEvent)
|
||||
for event in events[:n_events]:
|
||||
n_events = bytes_read // self._event_size
|
||||
|
||||
for event in self._event_buffer[:n_events]:
|
||||
try:
|
||||
control = self.control_map[(event.type, event.code)]
|
||||
control.value = event.value
|
||||
self.control_map[(event.type, event.code)].value = event.value
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@ -651,5 +653,4 @@ def _create_controller(device):
|
||||
|
||||
def get_controllers(display=None):
|
||||
return [controller for controller in
|
||||
[_create_controller(device) for device in get_devices(display)]
|
||||
if controller is not None]
|
||||
[_create_controller(device) for device in get_devices(display)] if controller]
|
||||
|
@ -135,17 +135,6 @@ class AudioData:
|
||||
self.duration -= num_bytes / audio_format.bytes_per_second
|
||||
self.timestamp += num_bytes / audio_format.bytes_per_second
|
||||
|
||||
def get_string_data(self):
|
||||
"""Return data as a bytestring.
|
||||
|
||||
Returns:
|
||||
bytes: Data as a (byte)string.
|
||||
"""
|
||||
if self.data is None:
|
||||
return b''
|
||||
|
||||
return memoryview(self.data).tobytes()[:self.length]
|
||||
|
||||
|
||||
class SourceInfo:
|
||||
"""Source metadata information.
|
||||
@ -409,7 +398,7 @@ class StaticSource(Source):
|
||||
audio_data = source.get_audio_data(buffer_size)
|
||||
if not audio_data:
|
||||
break
|
||||
data.write(audio_data.get_string_data())
|
||||
data.write(audio_data.data)
|
||||
self._data = data.getvalue()
|
||||
|
||||
self._duration = len(self._data) / self.audio_format.bytes_per_second
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
from .lib import *
|
||||
|
||||
from typing import TYPE_CHECKING, Dict, Tuple, Optional
|
||||
from typing import TYPE_CHECKING, Dict, Tuple, Optional, List, Tuple
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
@ -18,56 +18,11 @@ if TYPE_CHECKING:
|
||||
|
||||
def get_version_str() -> str: ...
|
||||
|
||||
|
||||
def simluation() -> None: ...
|
||||
|
||||
|
||||
""" 用来测试 rust 的物理模拟能不能用 """
|
||||
|
||||
|
||||
def part_list_read_test(file_name: Optional[str] = "./configs/PartList.xml") -> None: ...
|
||||
|
||||
def read_ship_test(path: Optional[str] = "./configs/dock1.xml") -> None: ...
|
||||
|
||||
class Camera_rs:
|
||||
""" 用于闲的没事 用 rust 写一个 camera """
|
||||
|
||||
def __new__(cls, window: Window,
|
||||
zoom: float = 1.0,
|
||||
dx: float = 1.0, dy: float = 1.0,
|
||||
min_zoom: float = 1.0,
|
||||
max_zoom: float = 1.0): ...
|
||||
|
||||
@property
|
||||
def dx(self) -> float: ...
|
||||
@property
|
||||
def dy(self) -> float: ...
|
||||
@property
|
||||
def zoom(self) -> float: ...
|
||||
@property
|
||||
def position(self) -> Tuple[float, float]: ...
|
||||
@dx.setter
|
||||
def dx(self, value: float) -> None: ...
|
||||
@dy.setter
|
||||
def dy(self, value: float) -> None: ...
|
||||
@zoom.setter
|
||||
def zoom(self, value: float) -> None: ...
|
||||
|
||||
def begin(self) -> None: ...
|
||||
|
||||
def end(self) -> None: ...
|
||||
|
||||
def __enter__(self, window) -> None: ...
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...
|
||||
|
||||
|
||||
class CenterCamera_rs(Camera_rs):
|
||||
""" 用于依旧闲的没事 用 rust 写一个中央对齐的 camera """
|
||||
|
||||
|
||||
class PartFrame_rs:
|
||||
...
|
||||
|
||||
def load_and_save_test(file_name: str): ...
|
||||
|
||||
|
||||
class SR1PartType_rs:
|
||||
@ -107,6 +62,20 @@ if TYPE_CHECKING:
|
||||
|
||||
def get_part_type(self, name: str) -> SR1PartType_rs: ...
|
||||
|
||||
class SR1PartData_rs:
|
||||
""" 用于从 rust 中读取 SR1PartData (其实好像也没啥用哈)
|
||||
"""
|
||||
@property
|
||||
def part_type_id(self) -> str: ...
|
||||
@property
|
||||
def pos(self) -> Tuple[float, float]: ...
|
||||
@property
|
||||
def angle(self) -> float: ...
|
||||
@property
|
||||
def flip_x(self) -> bool: ...
|
||||
@property
|
||||
def flip_y(self) -> bool: ...
|
||||
|
||||
class SR1Ship_rs:
|
||||
""" 用于高效且省内存的读取 SR1Ship """
|
||||
def __init__(self, file_path = './configs/dock1.xml', part_list = './configs/PartList.xml', ship_name = 'NewShip'): ...
|
||||
@ -122,6 +91,8 @@ if TYPE_CHECKING:
|
||||
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]]]: ...
|
||||
def as_dict(self) -> Dict[int, List[Tuple[SR1PartType_rs, SR1PartData]]]:
|
||||
"""用于返回一个包含所有已连接零件的字典"""
|
||||
|
||||
class Console_rs:
|
||||
def __init__(self) -> None: ...
|
||||
|
44
mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock
generated
44
mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock
generated
@ -91,7 +91,7 @@ dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset 0.9.0",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
@ -119,6 +119,7 @@ name = "difficult_rocket_rs"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"pyo3",
|
||||
"quick-xml",
|
||||
"rapier2d-f64",
|
||||
"serde",
|
||||
"serde-xml-rs",
|
||||
@ -182,13 +183,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.8.0"
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@ -350,14 +348,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b1ac5b3731ba34fdaa9785f8d74d17448cd18f30cf19e0c7e7b1fdb5272109"
|
||||
checksum = "cffef52f74ec3b1a1baf295d9b8fcc3070327aefc39a6d00656b13c1d0b8885c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indoc",
|
||||
"libc",
|
||||
"memoffset 0.8.0",
|
||||
"memoffset",
|
||||
"parking_lot",
|
||||
"pyo3-build-config",
|
||||
"pyo3-ffi",
|
||||
@ -367,9 +365,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cb946f5ac61bb61a5014924910d936ebd2b23b705f7a4a3c40b05c720b079a3"
|
||||
checksum = "713eccf888fb05f1a96eb78c0dbc51907fee42b3377272dc902eb38985f418d5"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
@ -377,9 +375,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd4d7c5337821916ea2a1d21d1092e8443cf34879e53a0ac653fbb98f44ff65c"
|
||||
checksum = "5b2ecbdcfb01cbbf56e179ce969a048fd7305a66d4cdf3303e0da09d69afe4c3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
@ -387,9 +385,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros"
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d39c55dab3fc5a4b25bbd1ac10a2da452c4aca13bb450f22818a002e29648d"
|
||||
checksum = "b78fdc0899f2ea781c463679b20cb08af9247febc8d052de941951024cd8aea0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"pyo3-macros-backend",
|
||||
@ -399,15 +397,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97daff08a4c48320587b5224cc98d609e3c27b6d437315bd40b605c98eeb5918"
|
||||
checksum = "60da7b84f1227c3e2fe7593505de274dcf4c8928b4e0a1c23d551a14e4e80a0f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
|
@ -16,11 +16,11 @@ opt-level = 3
|
||||
[profile.release]
|
||||
strip = true
|
||||
opt-level = "s"
|
||||
codegen-units = 1
|
||||
# codegen-units = 1
|
||||
|
||||
#[dependencies.quick-xml]
|
||||
#version = "0.27.1"
|
||||
#features = ["serialize"]
|
||||
[dependencies.quick-xml]
|
||||
version = "0.29.0"
|
||||
features = ["serialize"]
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.164"
|
||||
@ -37,5 +37,5 @@ version = "0.17.2"
|
||||
features = ["simd-stable"]
|
||||
|
||||
[dependencies.pyo3]
|
||||
version = "0.18.3"
|
||||
version = "0.19.0"
|
||||
features = ["extension-module"]
|
||||
|
@ -9,10 +9,8 @@
|
||||
mod logger;
|
||||
mod plugin;
|
||||
mod python;
|
||||
mod render;
|
||||
mod simulator;
|
||||
mod sr1_data;
|
||||
mod translate;
|
||||
mod types;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
@ -27,7 +25,7 @@ enum LoadState {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_version_str() -> String { "0.2.11.0".to_string() }
|
||||
fn get_version_str() -> String { "0.2.13.0".to_string() }
|
||||
|
||||
#[pyfunction]
|
||||
fn test_call(py_obj: &PyAny) -> PyResult<bool> {
|
||||
@ -45,9 +43,8 @@ fn module_init(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(test_call, 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::<render::camera::CameraRs>()?;
|
||||
m.add_class::<render::camera::CenterCameraRs>()?;
|
||||
m.add_class::<render::screen::PartFrame>()?;
|
||||
m.add_function(wrap_pyfunction!(python::data::load_and_save_test, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(python::serde_test::test_ship_read_and_write, m)?)?;
|
||||
m.add_class::<python::data::PySR1Ship>()?;
|
||||
m.add_class::<python::data::PySR1PartList>()?;
|
||||
m.add_class::<python::data::PySR1PartType>()?;
|
||||
|
@ -55,7 +55,6 @@ pub mod data {
|
||||
|
||||
#[pyclass]
|
||||
#[pyo3(name = "SR1PartList_rs")]
|
||||
#[pyo3(text_signature = "(file_path = './configs/PartList.xml', list_name = 'NewPartList')")]
|
||||
pub struct PySR1PartList {
|
||||
pub data: SR1PartList,
|
||||
}
|
||||
@ -63,6 +62,7 @@ pub mod data {
|
||||
#[pymethods]
|
||||
impl PySR1PartList {
|
||||
#[new]
|
||||
#[pyo3(text_signature = "(file_path = './configs/PartList.xml', list_name = 'NewPartList')")]
|
||||
fn new(file_path: String, list_name: String) -> Self {
|
||||
let raw_part_list: RawPartList = RawPartList::from_file(file_path).unwrap();
|
||||
let data = raw_part_list.to_sr_part_list(Some(list_name));
|
||||
@ -74,7 +74,7 @@ pub mod data {
|
||||
}
|
||||
|
||||
fn get_part_type(&self, name: String) -> Option<PySR1PartType> {
|
||||
let part_type = self.data.get_part_type(name.clone());
|
||||
let part_type = self.data.get_part_type(&name);
|
||||
if let Some(part_type) = part_type {
|
||||
Some(PySR1PartType::new(part_type.clone()))
|
||||
} else {
|
||||
@ -89,9 +89,30 @@ pub mod data {
|
||||
pub data: SR1PartData,
|
||||
}
|
||||
|
||||
impl PySR1PartData {
|
||||
pub fn new(data: SR1PartData) -> Self { Self { data } }
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PySR1PartData {
|
||||
#[getter]
|
||||
fn get_part_type_id(&self) -> String { self.data.part_type_id.clone() }
|
||||
|
||||
#[getter]
|
||||
fn get_pos(&self) -> (f64, f64) { (self.data.x, self.data.y) }
|
||||
|
||||
#[getter]
|
||||
fn get_angle(&self) -> f64 { self.data.angle }
|
||||
|
||||
#[getter]
|
||||
fn get_flip_x(&self) -> bool { self.data.flip_x }
|
||||
|
||||
#[getter]
|
||||
fn get_flip_y(&self) -> bool { self.data.flip_y }
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyo3(name = "SR1Ship_rs")]
|
||||
#[pyo3(text_signature = "(file_path = './configs/dock1.xml', part_list = './configs/PartList.xml', ship_name = 'NewShip')")]
|
||||
pub struct PySR1Ship {
|
||||
pub ship: SR1Ship,
|
||||
pub part_list: SR1PartList,
|
||||
@ -100,9 +121,11 @@ pub mod data {
|
||||
#[pymethods]
|
||||
impl PySR1Ship {
|
||||
#[new]
|
||||
#[pyo3(text_signature = "(file_path = './configs/dock1.xml', part_list = './configs/PartList.xml', ship_name = 'NewShip')")]
|
||||
fn new(file_path: String, part_list: String, ship_name: String) -> Self {
|
||||
let ship = SR1Ship::from_file(file_path, Some(ship_name)).unwrap();
|
||||
let mut ship = SR1Ship::from_file(file_path, Some(ship_name)).unwrap();
|
||||
let part_list = SR1PartList::from_file(part_list).unwrap();
|
||||
ship.parse_part_list_to_part(&part_list); //
|
||||
Self { ship, part_list }
|
||||
}
|
||||
|
||||
@ -132,14 +155,28 @@ pub mod data {
|
||||
#[getter]
|
||||
fn get_touch_ground(&self) -> bool { self.ship.touch_ground.to_owned() }
|
||||
|
||||
fn iter_parts(&self) -> HashMap<i64, (PySR1PartType, PySR1PartData)> {
|
||||
let mut parts = HashMap::new();
|
||||
#[getter]
|
||||
fn get_mass(&self) -> f64 {
|
||||
let mut mass = 0_f64;
|
||||
for part_data in self.ship.parts.iter() {
|
||||
let part_type = self.part_list.get_part_type(part_data.part_type_id.clone()).unwrap();
|
||||
parts.insert(
|
||||
part_data.id,
|
||||
(PySR1PartType::new(part_type), PySR1PartData { data: part_data.clone() }),
|
||||
);
|
||||
let part_type = self.part_list.get_part_type(&part_data.part_type_id).unwrap();
|
||||
mass += part_type.mass
|
||||
}
|
||||
mass
|
||||
}
|
||||
|
||||
fn as_dict(&self) -> HashMap<i64, Vec<(PySR1PartType, PySR1PartData)>> {
|
||||
let mut parts: HashMap<i64, Vec<(PySR1PartType, PySR1PartData)>> = HashMap::new();
|
||||
for part_data in self.ship.parts.iter() {
|
||||
if let Some(part_type) = self.part_list.get_part_type(&part_data.part_type_id) {
|
||||
let part_type = PySR1PartType::new(part_type.clone());
|
||||
let py_part_data = PySR1PartData::new(part_data.clone());
|
||||
if let Some(part_list) = parts.get_mut(&part_data.id) {
|
||||
part_list.push((part_type, py_part_data));
|
||||
} else {
|
||||
parts.insert(part_data.id, vec![(part_type, py_part_data)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
parts
|
||||
}
|
||||
@ -147,7 +184,7 @@ pub mod data {
|
||||
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();
|
||||
let part_type = self.part_list.get_part_type(&part_data.part_type_id).unwrap();
|
||||
// rotate
|
||||
let radius = part_data.angle;
|
||||
let ((x1, y1), (x2, y2)) = part_type.get_box();
|
||||
@ -162,11 +199,21 @@ pub mod data {
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod translate {
|
||||
use crate::translate;
|
||||
fn save(&self, file_path: String) -> PyResult<()> {
|
||||
self.ship.save(file_path).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
pub fn load_and_save_test(file_name: String) -> PyResult<()> {
|
||||
use crate::sr1_data::ship::RawShip;
|
||||
use serde_xml_rs::to_string;
|
||||
let ship = RawShip::from_file(file_name).unwrap();
|
||||
let _save_string = to_string(&ship);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub mod console {
|
||||
@ -238,3 +285,127 @@ pub mod console {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod serde_test {
|
||||
use pyo3::prelude::*;
|
||||
use quick_xml::de::from_str;
|
||||
use quick_xml::se::to_string;
|
||||
use quick_xml::Writer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
|
||||
type IdType = i64;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename = "Ship")]
|
||||
pub struct TestShip {
|
||||
#[serde(rename = "@version")]
|
||||
pub version: i32,
|
||||
#[serde(rename = "@liftedOff")]
|
||||
pub lift_off: i8,
|
||||
#[serde(rename = "@touchingGround")]
|
||||
pub touching_ground: i8,
|
||||
#[serde(rename = "Connections")]
|
||||
pub connections: Connections,
|
||||
#[serde(rename = "DisconnectedParts")]
|
||||
pub disconnected_parts: Option<DisconnectedParts>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct DisconnectedParts {
|
||||
#[serde(rename = "DisconnectedPart")]
|
||||
pub disconnected_part: Option<Vec<DisconnectedPart>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct DisconnectedPart {
|
||||
#[serde(rename = "Parts")]
|
||||
pub parts: Parts,
|
||||
#[serde(rename = "Connections")]
|
||||
pub connections: Connections,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Connections {
|
||||
#[serde(rename = "Connection")]
|
||||
pub connection: Option<Vec<Connection>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Connection {
|
||||
#[serde(rename = "@parentAttachPoint")]
|
||||
pub parent_attach_point: i32,
|
||||
#[serde(rename = "@childAttachPoint")]
|
||||
pub child_attach_point: i32,
|
||||
#[serde(rename = "@parentPart")]
|
||||
pub parent_part: IdType,
|
||||
#[serde(rename = "@childPart")]
|
||||
pub child_part: IdType,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Parts {
|
||||
#[serde(rename = "Part")]
|
||||
pub part: Vec<Part>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Part {
|
||||
// #[serde(rename = "@Tank")]
|
||||
// pub tank: Option<Tank>,
|
||||
// #[serde(rename = "@Engine")]
|
||||
// pub engine: Option<Engine>,
|
||||
// #[serde(rename = "@Pod")]
|
||||
// pub pod: Option<Pod>,
|
||||
#[serde(rename = "@partType")]
|
||||
pub part_type_id: String,
|
||||
#[serde(rename = "@id")]
|
||||
pub id: i64,
|
||||
#[serde(rename = "@x")]
|
||||
pub x: f64,
|
||||
#[serde(rename = "@y")]
|
||||
pub y: f64,
|
||||
#[serde(rename = "@editorAngle")]
|
||||
pub editor_angle: i32,
|
||||
#[serde(rename = "@angle")]
|
||||
pub angle: f64,
|
||||
#[serde(rename = "@angleV")]
|
||||
pub angle_v: f64,
|
||||
#[serde(rename = "@flippedX")]
|
||||
pub flip_x: Option<i8>,
|
||||
#[serde(rename = "@flippedY")]
|
||||
pub flip_y: Option<i8>,
|
||||
#[serde(rename = "@chuteX")]
|
||||
pub chute_x: Option<f64>,
|
||||
#[serde(rename = "@chuteY")]
|
||||
pub chute_y: Option<f64>,
|
||||
#[serde(rename = "@chuteAngle")]
|
||||
pub chute_angle: Option<f64>,
|
||||
#[serde(rename = "@chuteHeight")]
|
||||
pub chute_height: Option<f64>,
|
||||
#[serde(rename = "@extension")]
|
||||
pub extension: Option<f64>,
|
||||
#[serde(rename = "@inflate")]
|
||||
pub inflate: Option<i8>,
|
||||
#[serde(rename = "@inflation")]
|
||||
pub inflation: Option<f64>,
|
||||
#[serde(rename = "@exploded")]
|
||||
pub exploded: Option<i8>,
|
||||
#[serde(rename = "@rope")]
|
||||
pub rope: Option<i8>,
|
||||
#[serde(rename = "@activated")]
|
||||
pub activated: Option<i8>,
|
||||
#[serde(rename = "@deployed")]
|
||||
pub deployed: Option<i8>,
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(name = "test_ship_read_and_write")]
|
||||
pub fn test_ship_read_and_write(file_name: String) -> PyResult<()> {
|
||||
let file = fs::read_to_string(file_name).unwrap();
|
||||
let ship: TestShip = from_str(&file).unwrap();
|
||||
let save_string = to_string(&ship).unwrap();
|
||||
fs::write("./test-xml-rs.xml", save_string).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* -------------------------------
|
||||
* Difficult Rocket
|
||||
* Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||
* All rights reserved
|
||||
* -------------------------------
|
||||
*/
|
||||
|
||||
pub mod camera {
|
||||
|
||||
use pyo3::intern;
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pyclass(name = "Camera_rs", subclass)]
|
||||
pub struct CameraRs {
|
||||
pub window: Py<PyAny>,
|
||||
#[pyo3(get, set)]
|
||||
pub dx: f64,
|
||||
#[pyo3(get, set)]
|
||||
pub dy: f64,
|
||||
pub zoom: f64,
|
||||
#[pyo3(get, set)]
|
||||
pub max_zoom: f64,
|
||||
#[pyo3(get, set)]
|
||||
pub min_zoom: f64,
|
||||
}
|
||||
|
||||
#[pyclass(extends = CameraRs, name = "CenterCamera_rs")]
|
||||
pub struct CenterCameraRs;
|
||||
|
||||
#[pymethods]
|
||||
impl CenterCameraRs {
|
||||
#[new]
|
||||
#[pyo3(signature = (window, zoom=1.0, dx=1.0, dy=1.0, min_zoom=1.0, max_zoom=1.0))]
|
||||
pub fn py_new(window: &PyAny, zoom: f64, dx: f64, dy: f64, min_zoom: f64, max_zoom: f64) -> PyResult<(Self, CameraRs)> {
|
||||
return Ok((
|
||||
CenterCameraRs {},
|
||||
CameraRs {
|
||||
dx,
|
||||
dy,
|
||||
zoom,
|
||||
min_zoom,
|
||||
max_zoom,
|
||||
window: window.into(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
// pub fn __enter__(py_self: PyRef<Self>) -> PyResult<PyRef<Self>> {
|
||||
// // println!("enter!");
|
||||
// CenterCameraRs::begin()?;
|
||||
// Ok(py_self)
|
||||
// }
|
||||
|
||||
pub fn begin(self_: PyRef<'_, Self>) -> PyResult<()> {
|
||||
println!("begin!");
|
||||
let super_: &CameraRs = self_.as_ref();
|
||||
// 获取父类
|
||||
Python::with_gil(|py| -> PyResult<()> {
|
||||
let view = super_.window.getattr(py, intern!(py, "view"))?;
|
||||
// 获取存储的 view
|
||||
let x: f64 = super_.window.getattr(py, intern!(py, "width"))?.extract(py)?;
|
||||
let y: f64 = super_.window.getattr(py, intern!(py, "height"))?.extract(py)?;
|
||||
let x: f64 = x / 2.0 / super_.zoom + (super_.dx / super_.zoom);
|
||||
let y: f64 = y / 2.0 / super_.zoom + (super_.dy / super_.zoom);
|
||||
// 计算中心点
|
||||
|
||||
// view.call_method1(py, "translate", (x, y))?;
|
||||
// view.call_method1(py, "scale", (super_.zoom, super_.zoom))?;
|
||||
|
||||
let args = ((x * super_.zoom, y * super_.zoom, 0),);
|
||||
let view_matrix = view.call_method1(py, intern!(py, "translate"), args)?;
|
||||
// view_matrix = self.view.translate((x * zoom, y * zoom, 0))
|
||||
|
||||
let args = ((super_.zoom, super_.zoom, 1),);
|
||||
let view_matrix = view_matrix.call_method1(py, intern!(py, "scale"), args)?;
|
||||
// view_matrix = view_matrix.scale((zoom, zoom, 1))
|
||||
|
||||
super_.window.setattr(py, intern!(py, "view"), view_matrix)?;
|
||||
// self.view = view_matrix
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl CameraRs {
|
||||
#[new]
|
||||
#[pyo3(signature = (window, zoom=1.0, dx=1.0, dy=1.0, min_zoom=1.0, max_zoom=1.0))]
|
||||
pub fn py_new(window: &PyAny, zoom: f64, dx: f64, dy: f64, min_zoom: f64, max_zoom: f64) -> PyResult<Self> {
|
||||
return Ok(CameraRs {
|
||||
dx,
|
||||
dy,
|
||||
zoom,
|
||||
min_zoom,
|
||||
max_zoom,
|
||||
window: window.into(),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_view(&self) -> PyResult<PyObject> {
|
||||
Ok(Python::with_gil(|py| -> PyResult<PyObject> {
|
||||
Ok(self.window.getattr(py, intern!(py, "view"))?)
|
||||
})?)
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn get_position(&self) -> (f64, f64) { return (self.dx, self.dy); }
|
||||
|
||||
#[setter]
|
||||
pub fn set_position(&mut self, value: (f64, f64)) -> () {
|
||||
self.dx = value.0;
|
||||
self.dy = value.1;
|
||||
}
|
||||
|
||||
#[getter]
|
||||
pub fn get_zoom(&self) -> PyResult<f64> { Ok(self.zoom) }
|
||||
|
||||
#[setter]
|
||||
pub fn set_zoom(&mut self, value: f64) -> PyResult<()> {
|
||||
self.zoom = value.min(self.max_zoom).max(self.min_zoom);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn begin(&self) -> PyResult<()> {
|
||||
Python::with_gil(|py| -> PyResult<()> {
|
||||
let view = self.window.getattr(py, intern!(py, "view"))?;
|
||||
|
||||
let x: f64 = self.window.getattr(py, intern!(py, "width"))?.extract(py)?;
|
||||
let y: f64 = self.window.getattr(py, intern!(py, "height"))?.extract(py)?;
|
||||
let x: f64 = x / 2.0 / self.zoom + (self.dx / self.zoom);
|
||||
let y: f64 = y / 2.0 / self.zoom + (self.dy / self.zoom);
|
||||
// use to get center of the screen
|
||||
|
||||
let args = ((x * self.zoom, y * self.zoom, 0),);
|
||||
let view_matrix = view.call_method1(py, intern!(py, "translate"), args)?;
|
||||
// view_matrix = self.view.translate((x * zoom, y * zoom, 0))
|
||||
|
||||
let args = ((self.zoom, self.zoom, 1),);
|
||||
let view_matrix = view_matrix.call_method1(py, intern!(py, "scale"), args)?;
|
||||
// view_matrix = view_matrix.scale((zoom, zoom, 1))
|
||||
|
||||
self.window.setattr(py, intern!(py, "view"), view_matrix)?;
|
||||
// self.view = view_matrix
|
||||
Ok(())
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn end(&self) -> PyResult<()> {
|
||||
Python::with_gil(|py| -> PyResult<()> {
|
||||
let view = self.window.getattr(py, intern!(py, "view"))?;
|
||||
|
||||
let x: f64 = self.window.getattr(py, intern!(py, "width"))?.extract(py)?;
|
||||
let y: f64 = self.window.getattr(py, intern!(py, "height"))?.extract(py)?;
|
||||
let x: f64 = x / 2.0 / self.zoom + (self.dx / self.zoom);
|
||||
let y: f64 = y / 2.0 / self.zoom + (self.dy / self.zoom);
|
||||
|
||||
let args = ((1.0 / self.zoom, 1.0 / self.zoom, 1),);
|
||||
let view_matrix = view.call_method1(py, intern!(py, "scale"), args)?;
|
||||
|
||||
let args = ((-x * self.zoom, -y * self.zoom, 0),);
|
||||
let view_matrix = view_matrix.call_method1(py, intern!(py, "translate"), args)?;
|
||||
|
||||
self.window.setattr(py, intern!(py, "view"), view_matrix)?;
|
||||
Ok(())
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// https://github.com/PyO3/pyo3/discussions/2931#discussioncomment-4820729 for finding this
|
||||
/// https://github.com/PyO3/pyo3/issues/1205#issuecomment-1164096251 for advice on `__enter__`
|
||||
pub fn __enter__(py_self: PyRef<Self>) -> PyResult<PyRef<Self>> {
|
||||
// println!("enter!");
|
||||
py_self.begin()?;
|
||||
Ok(py_self)
|
||||
}
|
||||
|
||||
pub fn __exit__(&self, _exc_type: PyObject, _exc_value: PyObject, _traceback: PyObject) -> PyResult<()> {
|
||||
// println!("exit!");
|
||||
self.end()?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod screen {
|
||||
use pyo3::prelude::*;
|
||||
// use crate::types::sr1::SR1PartData;
|
||||
|
||||
#[pyclass]
|
||||
#[pyo3(name = "PartFrame_rs")]
|
||||
pub struct PartFrame {
|
||||
pub box_size: i32,
|
||||
pub width: i64,
|
||||
pub height: i64,
|
||||
// pub frame_box: Vec<Vec<SR1PartData>>
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PartFrame {
|
||||
#[new]
|
||||
pub fn py_new() -> PyResult<Self> {
|
||||
Ok(PartFrame {
|
||||
box_size: 111,
|
||||
width: 111,
|
||||
height: 111,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -64,8 +64,38 @@ pub fn simulation() -> () {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct Simulator {
|
||||
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: (),
|
||||
}
|
||||
|
||||
pub mod python {
|
||||
use pyo3::prelude::*;
|
||||
use rapier2d_f64::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
pub struct PyIntegrationParameters {
|
||||
pub data: IntegrationParameters,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyIntegrationParameters {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
PyIntegrationParameters {
|
||||
data: IntegrationParameters::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -607,6 +607,18 @@ pub mod ship {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn save(&self, file_name: String) -> Option<()> {
|
||||
let part_list_file = serde_xml_rs::to_string(self);
|
||||
print!("{:?}", part_list_file);
|
||||
if let Ok(part_list_file) = part_list_file {
|
||||
fs::write(file_name, part_list_file).unwrap();
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
@ -1,16 +0,0 @@
|
||||
/*
|
||||
* -------------------------------
|
||||
* 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,
|
||||
}
|
@ -246,9 +246,9 @@ pub mod sr1 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_part_type(&self, type_name: String) -> Option<SR1PartType> {
|
||||
pub fn get_part_type(&self, type_name: &String) -> Option<SR1PartType> {
|
||||
let cache = self.get_cache();
|
||||
match cache.get(&type_name) {
|
||||
match cache.get(type_name) {
|
||||
Some(part) => Some(part.clone()),
|
||||
None => None,
|
||||
}
|
||||
@ -699,11 +699,10 @@ pub mod sr1 {
|
||||
Some(ship.to_sr_ship(ship_name))
|
||||
}
|
||||
|
||||
pub fn parse_part_list_to_part(&mut self, part_list: SR1PartList) {
|
||||
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) {
|
||||
if let Some(part_type) = part_list.get_part_type(&part.part_type_id) {
|
||||
part.part_type = part_type.p_type;
|
||||
} else {
|
||||
part.part_type = SR1PartTypeEnum::strut;
|
||||
@ -712,8 +711,7 @@ pub mod sr1 {
|
||||
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) {
|
||||
if let Some(part_type) = part_list.get_part_type(&part.part_type_id) {
|
||||
part.part_type = part_type.p_type;
|
||||
} else {
|
||||
part.part_type = SR1PartTypeEnum::strut;
|
||||
@ -722,6 +720,27 @@ pub mod sr1 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_as_hashmap(&self) -> HashMap<i64, Vec<SR1PartData>> {
|
||||
// 返回一个 HashMap 用于快速查找
|
||||
// 同时为了 防止出现多个相同的 PartID 造成的数据丢失
|
||||
// 采用 Vec 存储
|
||||
let mut result: HashMap<i64, Vec<SR1PartData>> = HashMap::new();
|
||||
for part_data in self.parts.iter() {
|
||||
if let Some(part_vec) = result.get_mut(&part_data.id) {
|
||||
part_vec.push(part_data.clone());
|
||||
} else {
|
||||
result.insert(part_data.id, vec![part_data.clone()]);
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn save(&self, file_name: String) -> Option<()> {
|
||||
let raw_ship = self.to_raw_ship();
|
||||
raw_ship.save(file_name);
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SR1ShipTrait for SR1Ship {
|
||||
@ -780,7 +799,7 @@ pub mod sr1 {
|
||||
pub fn get_max_box(parts: &Vec<SR1PartData>, part_list: &SR1PartList) -> (f64, f64, f64, f64) {
|
||||
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 part_type = part_list.get_part_type(&part.part_type_id).unwrap();
|
||||
let ((x1, y1), (x2, y2)) = part_type.get_box();
|
||||
// rotate
|
||||
let mut p1 = Point2D::new(x1, y1);
|
||||
|
@ -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.11.0") # DR_mod 的 Rust 编写部分的兼容版本
|
||||
DR_rust_version = Version("0.2.12.0") # DR_mod 的 Rust 编写部分的兼容版本
|
||||
|
||||
logger = logging.getLogger('client.dr_game')
|
||||
|
||||
|
@ -8,6 +8,6 @@ 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 = "飞船渲染完成"
|
||||
save.start = "正在保存飞船: {}"
|
||||
|
@ -30,13 +30,17 @@ 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
|
||||
from Difficult_Rocket.utils.camera import CenterCamera
|
||||
from .types import SR1Textures, SR1PartTexture, SR1PartData, SR1Rotation, xml_bool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from Difficult_Rocket.client import ClientWindow
|
||||
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, SR1Ship_rs
|
||||
from .Difficult_Rocket_rs import (SR1PartList_rs,
|
||||
SR1Ship_rs,
|
||||
load_and_save_test,
|
||||
test_ship_read_and_write)
|
||||
|
||||
logger = logging.getLogger('client.dr_game_sr1_ship')
|
||||
sr_tr = Tr(lang_path=Path('./mods/dr_game/lang'))
|
||||
@ -134,9 +138,9 @@ class SR1ShipRender(BaseScreen):
|
||||
load_end_time = time.time_ns()
|
||||
logger.info(sr_tr().mod.info.setup.use_time().format(
|
||||
(load_end_time - load_start_time) / 1000000000))
|
||||
self.camera = CenterCamera(main_window,
|
||||
min_zoom=(1 / 2) ** 10, max_zoom=10)
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
self.camera_rs = CenterCamera_rs(main_window,
|
||||
min_zoom=(1 / 2) ** 10, max_zoom=10)
|
||||
self.rust_parts = None
|
||||
self.part_list_rs = SR1PartList_rs('configs/PartList.xml', 'default_part_list')
|
||||
|
||||
@ -150,6 +154,8 @@ class SR1ShipRender(BaseScreen):
|
||||
self.xml_name = file_path
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
try:
|
||||
load_and_save_test(self.xml_name)
|
||||
test_ship_read_and_write(self.xml_name)
|
||||
self.rust_ship = SR1Ship_rs(file_path, 'configs/PartList.xml', 'a_new_ship')
|
||||
print(self.rust_ship.name)
|
||||
print(self.rust_ship.img_pos)
|
||||
@ -228,10 +234,9 @@ class SR1ShipRender(BaseScreen):
|
||||
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
|
||||
self.camera_rs.dy = 0
|
||||
self.camera.zoom = 1.0
|
||||
self.camera.dx = 0
|
||||
self.camera.dy = 0
|
||||
parts = self.xml_root.find('Parts')
|
||||
for part_xml in parts:
|
||||
if part_xml.tag != 'Part':
|
||||
@ -260,11 +265,11 @@ class SR1ShipRender(BaseScreen):
|
||||
def update_parts(self) -> bool:
|
||||
if not self.rendered:
|
||||
return False
|
||||
self.debug_line.x2, self.debug_line.y2 = self.camera_rs.dx + (
|
||||
self.window_pointer.width / 2), self.camera_rs.dy + (
|
||||
self.debug_line.x2, self.debug_line.y2 = self.camera.dx + (
|
||||
self.window_pointer.width / 2), self.camera.dy + (
|
||||
self.window_pointer.height / 2)
|
||||
self.debug_d_pos_label.text = f'x: {self.camera_rs.dx} y: {self.camera_rs.dy}'
|
||||
self.debug_d_pos_label.position = self.camera_rs.dx + (self.window_pointer.width / 2), self.camera_rs.dy + (
|
||||
self.debug_d_pos_label.text = f'x: {self.camera.dx} y: {self.camera.dy}'
|
||||
self.debug_d_pos_label.position = self.camera.dx + (self.window_pointer.width / 2), self.camera.dy + (
|
||||
self.window_pointer.height / 2) + 10, 0
|
||||
self.need_update_parts = False
|
||||
|
||||
@ -283,7 +288,7 @@ class SR1ShipRender(BaseScreen):
|
||||
self.update_parts()
|
||||
self.need_update_parts = False
|
||||
|
||||
with self.camera_rs:
|
||||
with self.camera:
|
||||
self.part_box_batch.draw()
|
||||
self.part_batch.draw()
|
||||
self.part_box_batch.draw()
|
||||
@ -317,29 +322,29 @@ class SR1ShipRender(BaseScreen):
|
||||
mouse_dx = x - (window.width / 2)
|
||||
mouse_dy = y - (window.height / 2)
|
||||
# 鼠标缩放位置相对于屏幕中心的位置
|
||||
mouse_dx_d = mouse_dx - self.camera_rs.dx
|
||||
mouse_dy_d = mouse_dy - self.camera_rs.dy
|
||||
mouse_dx_d = mouse_dx - self.camera.dx
|
||||
mouse_dy_d = mouse_dy - self.camera.dy
|
||||
# 鼠标相对偏移量的偏移量
|
||||
if scroll_y == 0:
|
||||
zoom_d = 1
|
||||
else:
|
||||
zoom_d = ((2 ** scroll_y) - 1) * 0.5 + 1
|
||||
# 缩放的变换量
|
||||
if not (self.camera_rs.zoom == 10 and scroll_y > 0):
|
||||
if self.camera_rs.zoom * zoom_d >= 10:
|
||||
zoom_d = 10 / self.camera_rs.zoom
|
||||
self.camera_rs.zoom = 10
|
||||
if not (self.camera.zoom == 10 and scroll_y > 0):
|
||||
if self.camera.zoom * zoom_d >= 10:
|
||||
zoom_d = 10 / self.camera.zoom
|
||||
self.camera.zoom = 10
|
||||
else:
|
||||
self.camera_rs.zoom *= zoom_d
|
||||
self.camera.zoom *= zoom_d
|
||||
mouse_dx_d *= (1 - zoom_d)
|
||||
mouse_dy_d *= (1 - zoom_d)
|
||||
self.camera_rs.dx += mouse_dx_d
|
||||
self.camera_rs.dy += mouse_dy_d
|
||||
self.camera.dx += mouse_dx_d
|
||||
self.camera.dy += mouse_dy_d
|
||||
|
||||
self.debug_mouse_line.x2, self.debug_mouse_line.y2 = x, y
|
||||
self.debug_mouse_delta_line.x2 = (mouse_dx - self.camera_rs.dx) * (1 - (0.5 ** scroll_y)) + (
|
||||
self.debug_mouse_delta_line.x2 = (mouse_dx - self.camera.dx) * (1 - (0.5 ** scroll_y)) + (
|
||||
window.width / 2)
|
||||
self.debug_mouse_delta_line.y2 = (mouse_dy - self.camera_rs.dy) * (1 - (0.5 ** scroll_y)) + (
|
||||
self.debug_mouse_delta_line.y2 = (mouse_dy - self.camera.dy) * (1 - (0.5 ** scroll_y)) + (
|
||||
window.height / 2)
|
||||
self.debug_mouse_label.text = f'x: {mouse_dx} y: {mouse_dy}'
|
||||
self.debug_mouse_label.position = x, y + 10, 0
|
||||
@ -349,9 +354,9 @@ class SR1ShipRender(BaseScreen):
|
||||
def on_command(self, command: CommandText, window: "ClientWindow"):
|
||||
if command.find('render'):
|
||||
if command.find('reset'):
|
||||
self.camera_rs.zoom = 1
|
||||
self.camera_rs.dx = 0
|
||||
self.camera_rs.dy = 0
|
||||
self.camera.zoom = 1
|
||||
self.camera.dx = 0
|
||||
self.camera.dy = 0
|
||||
self.window_pointer.view = Vec4()
|
||||
else:
|
||||
self.need_draw = True
|
||||
@ -430,11 +435,20 @@ class SR1ShipRender(BaseScreen):
|
||||
img.paste(pil_image, (int(self.part_data[part].x * 60 + img_center[0]), int(-self.part_data[part].y * 60 + img_center[1])), pil_image)
|
||||
img.save(f'test{time.time()}.png', 'PNG')
|
||||
|
||||
elif command.find('test'):
|
||||
if command.find('save'):
|
||||
if not self.rendered:
|
||||
return
|
||||
if not DR_mod_runtime.use_DR_rust:
|
||||
return
|
||||
logger.info(sr_tr().sr1.ship.save.start().format(self.rust_ship))
|
||||
self.rust_ship.save('./test-save.xml')
|
||||
|
||||
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int, window: "ClientWindow"):
|
||||
if not self.focus:
|
||||
return
|
||||
self.camera_rs.dx += dx
|
||||
self.camera_rs.dy += dy
|
||||
self.camera.dx += dx
|
||||
self.camera.dy += dy
|
||||
self.need_update_parts = True
|
||||
# self.update_parts()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user