ruff format!
This commit is contained in:
parent
5361c10868
commit
960811f684
92
.github/workflows/dsm.py
vendored
92
.github/workflows/dsm.py
vendored
@ -14,30 +14,32 @@ class DSM:
|
||||
def __init__(self, docs_path: str, dsm_path: str):
|
||||
self.docs_path = docs_path
|
||||
self.dsm_path = dsm_path
|
||||
self.token = os.environ['DSM_TOKEN']
|
||||
self.fl = filestation.FileStation(ip_address='hws.shenjack.top',
|
||||
port=5000,
|
||||
username='github',
|
||||
password=self.token,
|
||||
secure=False,
|
||||
cert_verify=False,
|
||||
dsm_version=7,
|
||||
debug=True,
|
||||
interactive_output=False)
|
||||
self.token = os.environ["DSM_TOKEN"]
|
||||
self.fl = filestation.FileStation(
|
||||
ip_address="hws.shenjack.top",
|
||||
port=5000,
|
||||
username="github",
|
||||
password=self.token,
|
||||
secure=False,
|
||||
cert_verify=False,
|
||||
dsm_version=7,
|
||||
debug=True,
|
||||
interactive_output=False,
|
||||
)
|
||||
|
||||
def list_files(self):
|
||||
# 输出 文档构建目录 的内容
|
||||
print(f'==========输出 {self.docs_path} 的内容==========')
|
||||
print(f"==========输出 {self.docs_path} 的内容==========")
|
||||
for root, dirs, files in os.walk(self.docs_path):
|
||||
print(root, dirs)
|
||||
print('==========就这些==========')
|
||||
print("==========就这些==========")
|
||||
|
||||
def clear_dsm(self):
|
||||
# 清空 DSM 的 /web/dr 目录
|
||||
delete_task = self.fl.start_delete_task(self.dsm_path, recursive=True)
|
||||
delete_task_id = delete_task['taskid']
|
||||
delete_task_id = delete_task["taskid"]
|
||||
time.sleep(1) # 等待 1 秒 保证任务已经完成
|
||||
pprint(self.fl.get_delete_status(delete_task_id)['data']['finished'])
|
||||
pprint(self.fl.get_delete_status(delete_task_id)["data"]["finished"])
|
||||
|
||||
def check_md5(self, local_md5: str) -> bool:
|
||||
"""
|
||||
@ -47,24 +49,26 @@ class DSM:
|
||||
"""
|
||||
# 打开提供的md5文件
|
||||
try:
|
||||
with open(local_md5, 'r', encoding='utf-8') as f:
|
||||
with open(local_md5, "r", encoding="utf-8") as f:
|
||||
md5 = f.read()
|
||||
except FileNotFoundError:
|
||||
print(f'文件 {local_md5} 不存在')
|
||||
print(f"文件 {local_md5} 不存在")
|
||||
return False
|
||||
# 检测是否存在 dsm 上的 md5.txt
|
||||
dsm_files = self.fl.get_file_list(folder_path='/web/dr')
|
||||
if dsm_files.get('error'):
|
||||
print(dsm_files['error'])
|
||||
dsm_files = self.fl.get_file_list(folder_path="/web/dr")
|
||||
if dsm_files.get("error"):
|
||||
print(dsm_files["error"])
|
||||
return False
|
||||
dsm_files = dsm_files['data']['files']
|
||||
if '/web/dr/md5.txt' not in [file['path'] for file in dsm_files]:
|
||||
print('dsm md5.txt 不存在')
|
||||
dsm_files = dsm_files["data"]["files"]
|
||||
if "/web/dr/md5.txt" not in [file["path"] for file in dsm_files]:
|
||||
print("dsm md5.txt 不存在")
|
||||
return False
|
||||
# 下载 dsm 上的 md5.txt
|
||||
try:
|
||||
self.fl.get_file(path='/web/dr/md5.txt', mode='download', dest_path='./docs/book')
|
||||
with open('./docs/book/md5.txt', 'r', encoding='utf-8') as f:
|
||||
self.fl.get_file(
|
||||
path="/web/dr/md5.txt", mode="download", dest_path="./docs/book"
|
||||
)
|
||||
with open("./docs/book/md5.txt", "r", encoding="utf-8") as f:
|
||||
md5_last = f.read()
|
||||
if md5 == md5_last:
|
||||
return True
|
||||
@ -74,43 +78,47 @@ class DSM:
|
||||
|
||||
def upload_docs(self, local_md5: str):
|
||||
# 上传本地构建的文档到 DSM
|
||||
print(f'==========上传 {self.docs_path} 到 {self.dsm_path}==========')
|
||||
print(f"==========上传 {self.docs_path} 到 {self.dsm_path}==========")
|
||||
# 使用 os.walk 递归遍历文件夹 依次按照对应路径上传
|
||||
# 上传的时候 目标路径为本地路径的相对路径
|
||||
for root, dirs, files in os.walk(self.docs_path):
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
dest_path = f'{self.dsm_path}{root[len(self.docs_path):]}'
|
||||
dest_path = dest_path.replace('\\', '/')
|
||||
dest_path = f"{self.dsm_path}{root[len(self.docs_path):]}"
|
||||
dest_path = dest_path.replace("\\", "/")
|
||||
# 输出 文件路径 和 目标路径
|
||||
print(f'{file_path} -> {dest_path}', end=' ')
|
||||
pprint(self.fl.upload_file(dest_path=dest_path,
|
||||
file_path=file_path,
|
||||
overwrite=True))
|
||||
print(f"{file_path} -> {dest_path}", end=" ")
|
||||
pprint(
|
||||
self.fl.upload_file(
|
||||
dest_path=dest_path, file_path=file_path, overwrite=True
|
||||
)
|
||||
)
|
||||
# self.fl.upload_file(dest_path=dest_path,
|
||||
# file_path=file_path,
|
||||
# overwrite=True)
|
||||
# 上传本地的 md5 文件
|
||||
print(f'{local_md5} -> {self.dsm_path}', end=' ')
|
||||
pprint(self.fl.upload_file(dest_path=self.dsm_path,
|
||||
file_path=local_md5,
|
||||
overwrite=True))
|
||||
print('==========上传完成==========')
|
||||
print(f"{local_md5} -> {self.dsm_path}", end=" ")
|
||||
pprint(
|
||||
self.fl.upload_file(
|
||||
dest_path=self.dsm_path, file_path=local_md5, overwrite=True
|
||||
)
|
||||
)
|
||||
print("==========上传完成==========")
|
||||
|
||||
|
||||
def main():
|
||||
docs_path = 'docs/book'
|
||||
dsm_path = '/web/dr'
|
||||
docs_path = "docs/book"
|
||||
dsm_path = "/web/dr"
|
||||
dsm = DSM(docs_path, dsm_path)
|
||||
dsm.list_files()
|
||||
if dsm.check_md5('docs/md5.txt'):
|
||||
print('md5 一致,不需要上传')
|
||||
if dsm.check_md5("docs/md5.txt"):
|
||||
print("md5 一致,不需要上传")
|
||||
return 0
|
||||
dsm.clear_dsm()
|
||||
dsm.upload_docs('docs/md5.txt')
|
||||
dsm.upload_docs("docs/md5.txt")
|
||||
|
||||
dsm.fl.logout()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
23
.github/workflows/get_info.py
vendored
23
.github/workflows/get_info.py
vendored
@ -15,22 +15,23 @@ try:
|
||||
except ImportError:
|
||||
raise
|
||||
|
||||
args = ['-env', '-github-dev']
|
||||
args = ["-env", "-github-dev"]
|
||||
|
||||
|
||||
if sys.argv == [__file__]: # 没有输入参数,直接输出默认信息并输出
|
||||
print(sys.version)
|
||||
from Difficult_Rocket.utils import tools
|
||||
# 重置窗口信息
|
||||
config_file = tools.load_file('./config/main.toml')
|
||||
config_file['window']['width'] = 1024
|
||||
config_file['window']['height'] = 768
|
||||
rtoml.dump(config_file, open('./config/main.toml', 'w'))
|
||||
|
||||
elif os.path.abspath(os.curdir) in sys.path and '-env' in sys.argv:
|
||||
with open('./.github/workflows/env.ps1', encoding='utf-8', mode='w') as env_file:
|
||||
# 重置窗口信息
|
||||
config_file = tools.load_file("./config/main.toml")
|
||||
config_file["window"]["width"] = 1024
|
||||
config_file["window"]["height"] = 768
|
||||
rtoml.dump(config_file, open("./config/main.toml", "w"))
|
||||
|
||||
elif os.path.abspath(os.curdir) in sys.path and "-env" in sys.argv:
|
||||
with open("./.github/workflows/env.ps1", encoding="utf-8", mode="w") as env_file:
|
||||
print(f'$env:DR_version = "{DR_status.DR_version}"', file=env_file)
|
||||
print(f'$env:Build_version = "{DR_status.Build_version}"', file=env_file)
|
||||
elif os.path.abspath(os.curdir) in sys.path and '-github' in sys.argv:
|
||||
print(f'DR_version={DR_status.DR_version}')
|
||||
print(f'Build_version={DR_status.Build_version}')
|
||||
elif os.path.abspath(os.curdir) in sys.path and "-github" in sys.argv:
|
||||
print(f"DR_version={DR_status.DR_version}")
|
||||
print(f"Build_version={DR_status.Build_version}")
|
||||
|
@ -18,19 +18,19 @@ __version__ = sdk_version
|
||||
|
||||
__all__ = [
|
||||
# __init__
|
||||
'DR_status',
|
||||
"DR_status",
|
||||
# folder
|
||||
'api',
|
||||
'client',
|
||||
'server',
|
||||
'command',
|
||||
'crash',
|
||||
'exception',
|
||||
'mod',
|
||||
'utils',
|
||||
"api",
|
||||
"client",
|
||||
"server",
|
||||
"command",
|
||||
"crash",
|
||||
"exception",
|
||||
"mod",
|
||||
"utils",
|
||||
# file
|
||||
'main',
|
||||
'runtime',
|
||||
"main",
|
||||
"runtime",
|
||||
]
|
||||
|
||||
|
||||
@ -38,23 +38,24 @@ class _DR_status(Options):
|
||||
"""
|
||||
DR 的特性开关 / 基本状态
|
||||
"""
|
||||
name = 'DR Option'
|
||||
|
||||
name = "DR Option"
|
||||
# run status
|
||||
client_running: bool = False
|
||||
server_running: bool = False
|
||||
|
||||
# feature switch
|
||||
InputBox_use_TextEntry: bool = True
|
||||
record_threads: bool = True
|
||||
InputBox_use_TextEntry: bool = True
|
||||
record_threads: bool = True
|
||||
report_translate_not_found: bool = True
|
||||
use_multiprocess: bool = False
|
||||
use_cProfile: bool = False
|
||||
use_local_logging: bool = False
|
||||
|
||||
use_multiprocess: bool = False
|
||||
use_cProfile: bool = False
|
||||
use_local_logging: bool = False
|
||||
|
||||
# tests
|
||||
playing: bool = False
|
||||
debugging: bool = False
|
||||
crash_report_test: bool = False
|
||||
playing: bool = False
|
||||
debugging: bool = False
|
||||
crash_report_test: bool = False
|
||||
|
||||
# game version status
|
||||
DR_version: Version = sdk_version # DR SDK 版本
|
||||
@ -62,7 +63,7 @@ class _DR_status(Options):
|
||||
API_version: Version = Api_version # DR SDK API 版本
|
||||
|
||||
# game options
|
||||
default_language: str = 'zh-CN'
|
||||
default_language: str = "zh-CN"
|
||||
|
||||
# window option
|
||||
gui_scale: float = 1.0 # default 1.0 2.0 -> 2x 3 -> 3x
|
||||
@ -76,14 +77,15 @@ DR_status = _DR_status()
|
||||
|
||||
|
||||
def load_logging():
|
||||
with open('./config/logger.toml') as f:
|
||||
with open("./config/logger.toml") as f:
|
||||
import rtoml
|
||||
|
||||
logger_config = rtoml.load(f)
|
||||
log_path = logger_config['handlers']['file']['filename']
|
||||
log_path = logger_config["handlers"]["file"]["filename"]
|
||||
log_path = f"logs/{log_path.format(time.strftime('%Y-%m-%d %H-%M-%S', time.gmtime(time.time_ns() / 1000_000_000)))}"
|
||||
if not Path('logs/').is_dir():
|
||||
Path('logs/').mkdir()
|
||||
logger_config['handlers']['file']['filename'] = log_path
|
||||
if not Path("logs/").is_dir():
|
||||
Path("logs/").mkdir()
|
||||
logger_config["handlers"]["file"]["filename"] = log_path
|
||||
logging.config.dictConfig(logger_config)
|
||||
|
||||
|
||||
@ -96,8 +98,7 @@ if DR_status.playing:
|
||||
def think_it(something):
|
||||
return something
|
||||
|
||||
|
||||
@new_thread('think')
|
||||
@new_thread("think")
|
||||
def think(some_thing_to_think):
|
||||
gotcha = think_it(some_thing_to_think)
|
||||
return gotcha
|
||||
return gotcha
|
||||
|
@ -13,12 +13,12 @@ gitee: @shenjackyuanjie
|
||||
|
||||
|
||||
__all__ = [
|
||||
'exception',
|
||||
"exception",
|
||||
# 错误类定义
|
||||
'screen',
|
||||
"screen",
|
||||
# screen api
|
||||
'types',
|
||||
"types",
|
||||
# 类型定义
|
||||
'mod',
|
||||
"mod",
|
||||
# mod api
|
||||
]
|
||||
|
@ -4,14 +4,11 @@
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
from Difficult_Rocket.utils.camera import (Camera,
|
||||
CenterCamera,
|
||||
GroupCamera,
|
||||
CenterGroupCamera)
|
||||
from Difficult_Rocket.utils.camera import (
|
||||
Camera,
|
||||
CenterCamera,
|
||||
GroupCamera,
|
||||
CenterGroupCamera,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'Camera',
|
||||
'CenterCamera',
|
||||
'GroupCamera',
|
||||
'CenterGroupCamera'
|
||||
]
|
||||
__all__ = ["Camera", "CenterCamera", "GroupCamera", "CenterGroupCamera"]
|
||||
|
@ -16,4 +16,4 @@ from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from Difficult_Rocket.api.exception import command, logger, main, threading, unsupport
|
||||
|
||||
__all__ = ['command', 'logger', 'main', 'threading', 'unsupport']
|
||||
__all__ = ["command", "logger", "main", "threading", "unsupport"]
|
||||
|
@ -18,7 +18,7 @@ from Difficult_Rocket.exception.command import (
|
||||
CommandQMarkConflict,
|
||||
CommandQMarkMissing,
|
||||
CommandQMarkPreMissing,
|
||||
CommandQMarkSufMissing
|
||||
CommandQMarkSufMissing,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
@ -28,5 +28,5 @@ __all__ = [
|
||||
"CommandQMarkPosError",
|
||||
"CommandQMarkConflict",
|
||||
"CommandQMarkSufMissing",
|
||||
"CommandQMarkPreMissing"
|
||||
"CommandQMarkPreMissing",
|
||||
]
|
||||
|
@ -4,10 +4,6 @@
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
from Difficult_Rocket.exception.logger import (
|
||||
LogFileLockTimeOutError
|
||||
)
|
||||
from Difficult_Rocket.exception.logger import LogFileLockTimeOutError
|
||||
|
||||
__all__ = [
|
||||
"LogFileLockTimeOutError"
|
||||
]
|
||||
__all__ = ["LogFileLockTimeOutError"]
|
||||
|
@ -4,10 +4,6 @@
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
from Difficult_Rocket.exception.threading import (
|
||||
LockTimeOutError
|
||||
)
|
||||
from Difficult_Rocket.exception.threading import LockTimeOutError
|
||||
|
||||
__all__ = [
|
||||
"LockTimeOutError"
|
||||
]
|
||||
__all__ = ["LockTimeOutError"]
|
||||
|
@ -17,14 +17,14 @@ from Difficult_Rocket.exception.unsupport import (
|
||||
ThinkError,
|
||||
BrainError,
|
||||
BigBrainError,
|
||||
GrammarError
|
||||
GrammarError,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'NoMoreJson5',
|
||||
'Nope418ImATeapot',
|
||||
'ThinkError',
|
||||
'BrainError',
|
||||
'BigBrainError',
|
||||
'GrammarError'
|
||||
"NoMoreJson5",
|
||||
"Nope418ImATeapot",
|
||||
"ThinkError",
|
||||
"BrainError",
|
||||
"BigBrainError",
|
||||
"GrammarError",
|
||||
]
|
||||
|
@ -4,6 +4,4 @@
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
__all__ = [
|
||||
'widget'
|
||||
]
|
||||
__all__ = ["widget"]
|
||||
|
@ -6,6 +6,4 @@
|
||||
|
||||
from Difficult_Rocket.gui.widget.button import PressTextButton
|
||||
|
||||
__all__ = [
|
||||
'PressTextButton'
|
||||
]
|
||||
__all__ = ["PressTextButton"]
|
||||
|
@ -6,6 +6,4 @@
|
||||
|
||||
from Difficult_Rocket.mod.api import ModInfo
|
||||
|
||||
__all__ = [
|
||||
"ModInfo"
|
||||
]
|
||||
__all__ = ["ModInfo"]
|
||||
|
@ -25,7 +25,7 @@ class BaseScreen(EventDispatcher, Options):
|
||||
DR 的 页面API
|
||||
"""
|
||||
|
||||
name: str = 'BaseScreen'
|
||||
name: str = "BaseScreen"
|
||||
|
||||
def __init__(self, main_window: ClientWindow):
|
||||
super().__init__()
|
||||
@ -33,6 +33,7 @@ class BaseScreen(EventDispatcher, Options):
|
||||
self.window_pointer = main_window
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
def on_command(self, command: CommandText, window: ClientWindow):
|
||||
"""
|
||||
命令输入事件
|
||||
@ -56,6 +57,7 @@ class BaseScreen(EventDispatcher, Options):
|
||||
"""
|
||||
Pyglet 定义的事件
|
||||
"""
|
||||
|
||||
def on_activate(self, window: ClientWindow):
|
||||
"""The window was activated.
|
||||
|
||||
@ -151,7 +153,9 @@ class BaseScreen(EventDispatcher, Options):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_file_drop(self, x: int, y: int, paths: List[PathLike] , window: ClientWindow):
|
||||
def on_file_drop(
|
||||
self, x: int, y: int, paths: List[PathLike], window: ClientWindow
|
||||
):
|
||||
"""File(s) were dropped into the window, will return the position of the cursor and
|
||||
a list of paths to the files that were dropped.
|
||||
|
||||
@ -212,7 +216,16 @@ class BaseScreen(EventDispatcher, Options):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int, window: ClientWindow):
|
||||
def on_mouse_drag(
|
||||
self,
|
||||
x: int,
|
||||
y: int,
|
||||
dx: int,
|
||||
dy: int,
|
||||
buttons: int,
|
||||
modifiers: int,
|
||||
window: ClientWindow,
|
||||
):
|
||||
"""The mouse was moved with one or more mouse buttons pressed.
|
||||
|
||||
This event will continue to be fired even if the mouse leaves
|
||||
@ -236,7 +249,9 @@ class BaseScreen(EventDispatcher, Options):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_mouse_press(self, x: int, y: int, button: int, modifiers: int, window: ClientWindow):
|
||||
def on_mouse_press(
|
||||
self, x: int, y: int, button: int, modifiers: int, window: ClientWindow
|
||||
):
|
||||
"""A mouse button was pressed (and held down).
|
||||
|
||||
:Parameters:
|
||||
@ -253,7 +268,9 @@ class BaseScreen(EventDispatcher, Options):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_mouse_release(self, x: int, y: int, button: int, modifiers: int, window: ClientWindow):
|
||||
def on_mouse_release(
|
||||
self, x: int, y: int, button: int, modifiers: int, window: ClientWindow
|
||||
):
|
||||
"""A mouse button was released.
|
||||
|
||||
:Parameters:
|
||||
@ -270,7 +287,9 @@ class BaseScreen(EventDispatcher, Options):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_mouse_scroll(self, x: int, y: int, scroll_x: float, scroll_y: float, window: ClientWindow):
|
||||
def on_mouse_scroll(
|
||||
self, x: int, y: int, scroll_x: float, scroll_y: float, window: ClientWindow
|
||||
):
|
||||
"""The mouse wheel was scrolled.
|
||||
|
||||
Note that most mice have only a vertical scroll wheel, so
|
||||
@ -471,28 +490,28 @@ class BaseScreen(EventDispatcher, Options):
|
||||
"""
|
||||
|
||||
|
||||
BaseScreen.register_event_type('on_key_press')
|
||||
BaseScreen.register_event_type('on_key_release')
|
||||
BaseScreen.register_event_type('on_text')
|
||||
BaseScreen.register_event_type('on_text_motion')
|
||||
BaseScreen.register_event_type('on_text_motion_select')
|
||||
BaseScreen.register_event_type('on_mouse_motion')
|
||||
BaseScreen.register_event_type('on_mouse_drag')
|
||||
BaseScreen.register_event_type('on_mouse_press')
|
||||
BaseScreen.register_event_type('on_mouse_release')
|
||||
BaseScreen.register_event_type('on_mouse_scroll')
|
||||
BaseScreen.register_event_type('on_mouse_enter')
|
||||
BaseScreen.register_event_type('on_mouse_leave')
|
||||
BaseScreen.register_event_type('on_close')
|
||||
BaseScreen.register_event_type('on_expose')
|
||||
BaseScreen.register_event_type('on_resize')
|
||||
BaseScreen.register_event_type('on_move')
|
||||
BaseScreen.register_event_type('on_activate')
|
||||
BaseScreen.register_event_type('on_deactivate')
|
||||
BaseScreen.register_event_type('on_show')
|
||||
BaseScreen.register_event_type('on_hide')
|
||||
BaseScreen.register_event_type('on_context_lost')
|
||||
BaseScreen.register_event_type('on_context_state_lost')
|
||||
BaseScreen.register_event_type('on_file_drop')
|
||||
BaseScreen.register_event_type('on_draw')
|
||||
BaseScreen.register_event_type('on_refresh')
|
||||
BaseScreen.register_event_type("on_key_press")
|
||||
BaseScreen.register_event_type("on_key_release")
|
||||
BaseScreen.register_event_type("on_text")
|
||||
BaseScreen.register_event_type("on_text_motion")
|
||||
BaseScreen.register_event_type("on_text_motion_select")
|
||||
BaseScreen.register_event_type("on_mouse_motion")
|
||||
BaseScreen.register_event_type("on_mouse_drag")
|
||||
BaseScreen.register_event_type("on_mouse_press")
|
||||
BaseScreen.register_event_type("on_mouse_release")
|
||||
BaseScreen.register_event_type("on_mouse_scroll")
|
||||
BaseScreen.register_event_type("on_mouse_enter")
|
||||
BaseScreen.register_event_type("on_mouse_leave")
|
||||
BaseScreen.register_event_type("on_close")
|
||||
BaseScreen.register_event_type("on_expose")
|
||||
BaseScreen.register_event_type("on_resize")
|
||||
BaseScreen.register_event_type("on_move")
|
||||
BaseScreen.register_event_type("on_activate")
|
||||
BaseScreen.register_event_type("on_deactivate")
|
||||
BaseScreen.register_event_type("on_show")
|
||||
BaseScreen.register_event_type("on_hide")
|
||||
BaseScreen.register_event_type("on_context_lost")
|
||||
BaseScreen.register_event_type("on_context_state_lost")
|
||||
BaseScreen.register_event_type("on_file_drop")
|
||||
BaseScreen.register_event_type("on_draw")
|
||||
BaseScreen.register_event_type("on_refresh")
|
||||
|
@ -7,47 +7,48 @@
|
||||
from typing import Dict, Union
|
||||
from dataclasses import dataclass
|
||||
|
||||
from lib_not_dr.types.options import (Options,
|
||||
OptionsError,
|
||||
OptionNameNotDefined,
|
||||
OptionNotFound,
|
||||
get_type_hints_)
|
||||
from libs.MCDR.version import (Version,
|
||||
VersionRequirement,
|
||||
VersionParsingError)
|
||||
from lib_not_dr.types.options import (
|
||||
Options,
|
||||
OptionsError,
|
||||
OptionNameNotDefined,
|
||||
OptionNotFound,
|
||||
get_type_hints_,
|
||||
)
|
||||
from libs.MCDR.version import Version, VersionRequirement, VersionParsingError
|
||||
|
||||
|
||||
class Fonts(Options):
|
||||
# font's value
|
||||
|
||||
HOS: str = 'HarmonyOS Sans'
|
||||
HOS_S: str = 'HarmonyOS Sans SC'
|
||||
HOS_T: str = 'HarmonyOS Sans TC'
|
||||
HOS_C: str = 'HarmonyOS Sans Condensed'
|
||||
HOS: str = "HarmonyOS Sans"
|
||||
HOS_S: str = "HarmonyOS Sans SC"
|
||||
HOS_T: str = "HarmonyOS Sans TC"
|
||||
HOS_C: str = "HarmonyOS Sans Condensed"
|
||||
|
||||
鸿蒙字体: str = HOS
|
||||
鸿蒙简体: str = HOS_S
|
||||
鸿蒙繁体: str = HOS_T
|
||||
鸿蒙窄体: str = HOS_C
|
||||
|
||||
CC: str = 'Cascadia Code'
|
||||
CM: str = 'Cascadia Mono'
|
||||
CCPL: str = 'Cascadia Code PL'
|
||||
CMPL: str = 'Cascadia Mono PL'
|
||||
CC: str = "Cascadia Code"
|
||||
CM: str = "Cascadia Mono"
|
||||
CCPL: str = "Cascadia Code PL"
|
||||
CMPL: str = "Cascadia Mono PL"
|
||||
|
||||
微软等宽: str = CC
|
||||
微软等宽无线: str = CM
|
||||
微软等宽带电线: str = CCPL
|
||||
微软等宽带电线无线: str = CMPL
|
||||
|
||||
得意黑: str = '得意黑'
|
||||
得意黑: str = "得意黑"
|
||||
# SS = smiley-sans
|
||||
SS: str = 得意黑
|
||||
|
||||
|
||||
@dataclass
|
||||
class FontData:
|
||||
""" 用于保存字体的信息 """
|
||||
"""用于保存字体的信息"""
|
||||
|
||||
font_name: str = Fonts.鸿蒙简体
|
||||
font_size: int = 13
|
||||
bold: bool = False
|
||||
@ -55,29 +56,28 @@ class FontData:
|
||||
stretch: bool = False
|
||||
|
||||
def dict(self) -> Dict[str, Union[str, int, bool]]:
|
||||
return dict(font_name=self.font_name,
|
||||
font_size=self.font_size,
|
||||
bold=self.bold,
|
||||
italic=self.italic,
|
||||
stretch=self.stretch)
|
||||
return dict(
|
||||
font_name=self.font_name,
|
||||
font_size=self.font_size,
|
||||
bold=self.bold,
|
||||
italic=self.italic,
|
||||
stretch=self.stretch,
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
# main class
|
||||
'Options',
|
||||
'Version',
|
||||
'VersionRequirement',
|
||||
|
||||
"Options",
|
||||
"Version",
|
||||
"VersionRequirement",
|
||||
# data class
|
||||
'FontData',
|
||||
'Fonts',
|
||||
|
||||
"FontData",
|
||||
"Fonts",
|
||||
# exception
|
||||
'OptionsError',
|
||||
'OptionNameNotDefined',
|
||||
'OptionNotFound',
|
||||
'VersionParsingError',
|
||||
|
||||
"OptionsError",
|
||||
"OptionNameNotDefined",
|
||||
"OptionNotFound",
|
||||
"VersionParsingError",
|
||||
# other
|
||||
'get_type_hints_',
|
||||
"get_type_hints_",
|
||||
]
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||
@ -20,6 +19,7 @@ from typing import Callable, Dict, List, TYPE_CHECKING, Type
|
||||
# third function
|
||||
import rtoml
|
||||
import pyglet
|
||||
|
||||
# from pyglet import gl
|
||||
# from pyglet.gl import glClearColor
|
||||
# from pyglet.libs.win32 import _user32
|
||||
@ -44,7 +44,7 @@ from Difficult_Rocket.client.fps.fps_log import FpsLogger
|
||||
from Difficult_Rocket.exception.language import LanguageNotFound
|
||||
|
||||
|
||||
logger = logging.getLogger('client')
|
||||
logger = logging.getLogger("client")
|
||||
|
||||
|
||||
class ClientOption(Options):
|
||||
@ -59,14 +59,14 @@ class ClientOption(Options):
|
||||
caption: str = "Difficult Rocket v{DR_version}"
|
||||
|
||||
def load_file(self) -> None:
|
||||
file: dict = tools.load_file('./config/main.toml')
|
||||
self.fps = int(file['runtime']['fps'])
|
||||
self.width = int(file['window']['width'])
|
||||
self.height = int(file['window']['height'])
|
||||
self.fullscreen = tools.format_bool(file['window']['full_screen'])
|
||||
self.resizeable = tools.format_bool(file['window']['resizable'])
|
||||
self.gui_scale = float(file['window']['gui_scale'])
|
||||
self.caption = DR_status.format(file['window']['caption'])
|
||||
file: dict = tools.load_file("./config/main.toml")
|
||||
self.fps = int(file["runtime"]["fps"])
|
||||
self.width = int(file["window"]["width"])
|
||||
self.height = int(file["window"]["height"])
|
||||
self.fullscreen = tools.format_bool(file["window"]["full_screen"])
|
||||
self.resizeable = tools.format_bool(file["window"]["resizable"])
|
||||
self.gui_scale = float(file["window"]["gui_scale"])
|
||||
self.caption = DR_status.format(file["window"]["caption"])
|
||||
self.caption = DR_runtime.format(self.caption)
|
||||
|
||||
|
||||
@ -74,27 +74,36 @@ class Client:
|
||||
"""
|
||||
客户端
|
||||
"""
|
||||
def __init__(self, game: "Game", net_mode='local'):
|
||||
|
||||
def __init__(self, game: "Game", net_mode="local"):
|
||||
start_time = time.time_ns()
|
||||
# logging
|
||||
self.logger = logging.getLogger('client')
|
||||
self.logger = logging.getLogger("client")
|
||||
self.logger.info(tr().client.setup.start())
|
||||
# config
|
||||
self.config = ClientOption()
|
||||
# value
|
||||
self.process_id = 'Client'
|
||||
self.process_name = 'Client process'
|
||||
self.process_id = "Client"
|
||||
self.process_name = "Client process"
|
||||
self.process_pid = os.getpid()
|
||||
self.net_mode = net_mode
|
||||
self.game = game
|
||||
self.window = ClientWindow(game=game, net_mode=self.net_mode,
|
||||
width=self.config.width, height=self.config.height,
|
||||
fullscreen=self.config.fullscreen, caption=self.config.caption,
|
||||
resizable=self.config.resizeable, visible=self.config.visible,
|
||||
file_drops=True)
|
||||
self.window = ClientWindow(
|
||||
game=game,
|
||||
net_mode=self.net_mode,
|
||||
width=self.config.width,
|
||||
height=self.config.height,
|
||||
fullscreen=self.config.fullscreen,
|
||||
caption=self.config.caption,
|
||||
resizable=self.config.resizeable,
|
||||
visible=self.config.visible,
|
||||
file_drops=True,
|
||||
)
|
||||
end_time = time.time_ns()
|
||||
self.use_time = end_time - start_time
|
||||
self.logger.info(tr().client.setup.use_time().format(Decimal(self.use_time) / 1000000000))
|
||||
self.logger.info(
|
||||
tr().client.setup.use_time().format(Decimal(self.use_time) / 1000000000)
|
||||
)
|
||||
self.logger.debug(tr().client.setup.use_time_ns().format(self.use_time))
|
||||
|
||||
def start(self):
|
||||
@ -106,7 +115,7 @@ class Client:
|
||||
# TODO 写一下服务端启动相关,还是需要服务端啊
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Client {self.process_name} {self.process_pid}>'
|
||||
return f"<Client {self.process_name} {self.process_pid}>"
|
||||
|
||||
|
||||
def pyglet_load_fonts_folder(folder) -> None:
|
||||
@ -125,12 +134,18 @@ def pyglet_load_fonts_folder(folder) -> None:
|
||||
dir_path = Path(dir_path)
|
||||
for file_name in file_names:
|
||||
file_name = Path(file_name)
|
||||
if file_name.suffix in ('.ttf', '.otf'):
|
||||
logger.debug(tr().client.load.font.file().format(str(dir_path / file_name)))
|
||||
if file_name.suffix in (".ttf", ".otf"):
|
||||
logger.debug(
|
||||
tr().client.load.font.file().format(str(dir_path / file_name))
|
||||
)
|
||||
try:
|
||||
pyglet.font.add_file(str(dir_path / file_name))
|
||||
except Exception:
|
||||
logger.error(tr().client.load.font.error().format(str(dir_path / file_name), traceback.format_exc()))
|
||||
logger.error(
|
||||
tr()
|
||||
.client.load.font.error()
|
||||
.format(str(dir_path / file_name), traceback.format_exc())
|
||||
)
|
||||
end_time = time.time_ns()
|
||||
use_time = end_time - start_time
|
||||
logger.info(tr().client.load.font.use_time().format(use_time / 1000000000))
|
||||
@ -147,13 +162,16 @@ def _call_back(call_back: Callable) -> Callable:
|
||||
: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
|
||||
|
||||
|
||||
@ -166,6 +184,7 @@ def _call_screen_after(func: Callable) -> Callable:
|
||||
:param func: 需要包装的函数
|
||||
:return: 包装后的函数
|
||||
"""
|
||||
|
||||
@functools.wraps(func)
|
||||
def warped(self: "ClientWindow", *args, **kwargs):
|
||||
result = func(self, *args, **kwargs)
|
||||
@ -192,6 +211,7 @@ def _call_screen_before(func: Callable) -> Callable:
|
||||
:param func: 需要包装的函数
|
||||
:return: 包装后的函数
|
||||
"""
|
||||
|
||||
@functools.wraps(func)
|
||||
def warped(self: "ClientWindow", *args, **kwargs):
|
||||
for title, a_screen in self.screen_list.items():
|
||||
@ -210,8 +230,7 @@ def _call_screen_before(func: Callable) -> Callable:
|
||||
|
||||
|
||||
class ClientWindow(Window):
|
||||
|
||||
def __init__(self, game: "Game", net_mode='local', *args, **kwargs):
|
||||
def __init__(self, game: "Game", net_mode="local", *args, **kwargs):
|
||||
"""
|
||||
|
||||
@param net_mode:
|
||||
@ -221,7 +240,7 @@ class ClientWindow(Window):
|
||||
start_time = time.time_ns()
|
||||
super().__init__(*args, **kwargs)
|
||||
# logging
|
||||
self.logger = logging.getLogger('client')
|
||||
self.logger = logging.getLogger("client")
|
||||
self.logger.info(tr().window.setup.start())
|
||||
# value
|
||||
self.game = game
|
||||
@ -229,11 +248,11 @@ class ClientWindow(Window):
|
||||
self.run_input = False
|
||||
self.command_list: List[str] = []
|
||||
# config
|
||||
self.main_config = tools.load_file('./config/main.toml')
|
||||
self.game_config = tools.load_file('./config/game.config')
|
||||
self.main_config = tools.load_file("./config/main.toml")
|
||||
self.game_config = tools.load_file("./config/game.config")
|
||||
# FPS
|
||||
self.FPS = Decimal(int(self.main_config['runtime']['fps']))
|
||||
self.SPF = Decimal('1') / self.FPS
|
||||
self.FPS = Decimal(int(self.main_config["runtime"]["fps"]))
|
||||
self.SPF = Decimal("1") / self.FPS
|
||||
self.fps_log = FpsLogger(stable_fps=int(self.FPS))
|
||||
# batch
|
||||
self.main_batch = Batch()
|
||||
@ -245,10 +264,16 @@ class ClientWindow(Window):
|
||||
# setup
|
||||
self.setup()
|
||||
# 命令显示
|
||||
self.input_box = TextEntry(x=50, y=30, width=300,
|
||||
batch=self.main_batch, text='', group=Group(1000, parent=self.main_group)) # 实例化
|
||||
self.input_box = TextEntry(
|
||||
x=50,
|
||||
y=30,
|
||||
width=300,
|
||||
batch=self.main_batch,
|
||||
text="",
|
||||
group=Group(1000, parent=self.main_group),
|
||||
) # 实例化
|
||||
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.push_handlers(self.input_box)
|
||||
self.input_box.enabled = True
|
||||
# 设置刷新率
|
||||
@ -263,19 +288,19 @@ class ClientWindow(Window):
|
||||
self.count = 0
|
||||
|
||||
def setup(self):
|
||||
self.set_icon(pyglet.image.load('assets/textures/icon.png'))
|
||||
self.set_icon(pyglet.image.load("assets/textures/icon.png"))
|
||||
self.load_fonts()
|
||||
self.screen_list['DR_debug'] = DRDEBUGScreen(self)
|
||||
self.game.dispatch_mod_event('on_client_start', game=self.game, client=self)
|
||||
self.screen_list["DR_debug"] = DRDEBUGScreen(self)
|
||||
self.game.dispatch_mod_event("on_client_start", game=self.game, client=self)
|
||||
|
||||
def load_fonts(self) -> None:
|
||||
fonts_folder_path = self.main_config['runtime']['fonts_folder']
|
||||
fonts_folder_path = self.main_config["runtime"]["fonts_folder"]
|
||||
# 加载字体路径
|
||||
# 淦,还写了个递归来处理
|
||||
pyglet_load_fonts_folder(fonts_folder_path)
|
||||
|
||||
def start_game(self) -> None:
|
||||
self.set_icon(pyglet.image.load('assets/textures/icon.png'))
|
||||
self.set_icon(pyglet.image.load("assets/textures/icon.png"))
|
||||
try:
|
||||
# pyglet.clock.schedule_interval(self.on_draw, float(self.SPF))
|
||||
# pyglet.app.run()
|
||||
@ -284,18 +309,20 @@ class ClientWindow(Window):
|
||||
except KeyboardInterrupt:
|
||||
self.logger.warning("==========client stop. KeyboardInterrupt info==========")
|
||||
traceback.print_exc()
|
||||
self.logger.warning("==========client stop. KeyboardInterrupt info end==========")
|
||||
self.dispatch_event("on_close", 'input')
|
||||
self.logger.warning(
|
||||
"==========client stop. KeyboardInterrupt info end=========="
|
||||
)
|
||||
self.dispatch_event("on_close", "input")
|
||||
sys.exit(0)
|
||||
|
||||
@new_thread('window save_info')
|
||||
@new_thread("window save_info")
|
||||
def save_info(self):
|
||||
self.logger.info(tr().client.config.save.start())
|
||||
config_file: dict = tools.load_file('./config/main.toml')
|
||||
config_file['window']['width'] = self.width
|
||||
config_file['window']['height'] = self.height
|
||||
config_file['runtime']['language'] = DR_runtime.language
|
||||
rtoml.dump(config_file, open('./config/main.toml', 'w'))
|
||||
config_file: dict = tools.load_file("./config/main.toml")
|
||||
config_file["window"]["width"] = self.width
|
||||
config_file["window"]["height"] = self.height
|
||||
config_file["runtime"]["language"] = DR_runtime.language
|
||||
rtoml.dump(config_file, open("./config/main.toml", "w"))
|
||||
self.logger.info(tr().client.config.save.done())
|
||||
|
||||
"""
|
||||
@ -323,7 +350,7 @@ class ClientWindow(Window):
|
||||
def on_draw(self):
|
||||
while (command := self.game.console.get_command()) is not None:
|
||||
self.on_command(line.CommandText(command))
|
||||
pyglet.gl.glClearColor(21/255, 22/255, 23/255, 0.0)
|
||||
pyglet.gl.glClearColor(21 / 255, 22 / 255, 23 / 255, 0.0)
|
||||
self.clear()
|
||||
# self.draw_update(dt) # TODO: wait for pyglet 2.1
|
||||
self.draw_update(float(self.SPF))
|
||||
@ -346,7 +373,7 @@ class ClientWindow(Window):
|
||||
@_call_screen_after
|
||||
def on_hide(self):
|
||||
# self.set_location(*self.get_location())
|
||||
print('on hide!')
|
||||
print("on hide!")
|
||||
|
||||
@_call_screen_before
|
||||
def draw_batch(self):
|
||||
@ -359,7 +386,7 @@ class ClientWindow(Window):
|
||||
def on_input(self, message: str) -> None:
|
||||
command_text = line.CommandText(message)
|
||||
self.on_command(command_text)
|
||||
self.input_box.value = ''
|
||||
self.input_box.value = ""
|
||||
|
||||
def new_command(self):
|
||||
self.game.console.new_command()
|
||||
@ -367,38 +394,44 @@ class ClientWindow(Window):
|
||||
@_call_back(new_command)
|
||||
@_call_screen_after
|
||||
def on_command(self, command: line.CommandText):
|
||||
command.text = command.text.rstrip('\n').rstrip(' ').strip('/')
|
||||
command.text = command.text.rstrip("\n").rstrip(" ").strip("/")
|
||||
self.logger.info(tr().window.command.text().format(f"|{command.text}|"))
|
||||
if command.find('stop'):
|
||||
if command.find("stop"):
|
||||
self.logger.info("command stop!")
|
||||
# HUGE THANKS to Discord @nokiyasos for this fix!
|
||||
pyglet.app.exit()
|
||||
elif command.find('fps'):
|
||||
if command.find('log'):
|
||||
elif command.find("fps"):
|
||||
if command.find("log"):
|
||||
self.logger.debug(self.fps_log.fps_list)
|
||||
elif command.find('max'):
|
||||
elif command.find("max"):
|
||||
self.logger.info(self.fps_log.max_fps)
|
||||
# self.command.push_line(self.fps_log.max_fps, block_line=True)
|
||||
elif command.find('min'):
|
||||
elif command.find("min"):
|
||||
self.logger.info(self.fps_log.min_fps)
|
||||
# self.command.push_line(self.fps_log.min_fps, block_line=True)
|
||||
elif command.find('default'):
|
||||
self.set_size(int(self.main_config['window_default']['width']),
|
||||
int(self.main_config['window_default']['height']))
|
||||
elif command.find('lang'):
|
||||
elif command.find("default"):
|
||||
self.set_size(
|
||||
int(self.main_config["window_default"]["width"]),
|
||||
int(self.main_config["window_default"]["height"]),
|
||||
)
|
||||
elif command.find("lang"):
|
||||
try:
|
||||
lang = command.text[5:]
|
||||
tr._language = lang
|
||||
self.logger.info(tr().language_set_to())
|
||||
except LanguageNotFound:
|
||||
self.logger.info(tr().language_available().format(os.listdir('./config/lang')))
|
||||
self.logger.info(
|
||||
tr().language_available().format(os.listdir("./config/lang"))
|
||||
)
|
||||
self.save_info()
|
||||
elif command.find('mods'):
|
||||
if command.find('list'):
|
||||
elif command.find("mods"):
|
||||
if command.find("list"):
|
||||
self.logger.info(tr().mod.list())
|
||||
for mod in self.game.mod_manager.loaded_mod_modules.values():
|
||||
self.logger.info(f"mod: {mod.name} id: {mod.mod_id} version: {mod.version}")
|
||||
elif command.find('reload'):
|
||||
self.logger.info(
|
||||
f"mod: {mod.name} id: {mod.mod_id} version: {mod.version}"
|
||||
)
|
||||
elif command.find("reload"):
|
||||
if not len(command.text) == 0:
|
||||
print(f"reload mod: |{command.text}|")
|
||||
self.game.mod_manager.reload_mod(command.text, game=self.game)
|
||||
@ -448,34 +481,40 @@ class ClientWindow(Window):
|
||||
@_call_screen_after
|
||||
def on_mouse_press(self, x, y, button, modifiers) -> None:
|
||||
self.logger.debug(
|
||||
tr().window.mouse.press().format(
|
||||
[x, y], tr().window.mouse[mouse.buttons_string(button)]()
|
||||
)
|
||||
tr()
|
||||
.window.mouse.press()
|
||||
.format([x, y], tr().window.mouse[mouse.buttons_string(button)]())
|
||||
)
|
||||
|
||||
@_call_screen_after
|
||||
def on_mouse_release(self, x, y, button, modifiers) -> None:
|
||||
self.logger.debug(
|
||||
tr().window.mouse.release().format(
|
||||
[x, y], tr().window.mouse[mouse.buttons_string(button)]()
|
||||
)
|
||||
tr()
|
||||
.window.mouse.release()
|
||||
.format([x, y], tr().window.mouse[mouse.buttons_string(button)]())
|
||||
)
|
||||
|
||||
@_call_screen_after
|
||||
def on_key_press(self, symbol, modifiers) -> None:
|
||||
if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
|
||||
key.MOD_CAPSLOCK |
|
||||
key.MOD_SCROLLLOCK)):
|
||||
self.dispatch_event('on_close', 'window')
|
||||
if symbol == key.ESCAPE and not (
|
||||
modifiers & ~(key.MOD_NUMLOCK | key.MOD_CAPSLOCK | key.MOD_SCROLLLOCK)
|
||||
):
|
||||
self.dispatch_event("on_close", "window")
|
||||
if symbol == key.SLASH:
|
||||
self.input_box._set_focus(True)
|
||||
self.logger.debug(
|
||||
tr().window.key.press().format(key.symbol_string(symbol), key.modifiers_string(modifiers)))
|
||||
tr()
|
||||
.window.key.press()
|
||||
.format(key.symbol_string(symbol), key.modifiers_string(modifiers))
|
||||
)
|
||||
|
||||
@_call_screen_after
|
||||
def on_key_release(self, symbol, modifiers) -> None:
|
||||
self.logger.debug(
|
||||
tr().window.key.release().format(key.symbol_string(symbol), key.modifiers_string(modifiers)))
|
||||
tr()
|
||||
.window.key.release()
|
||||
.format(key.symbol_string(symbol), key.modifiers_string(modifiers))
|
||||
)
|
||||
|
||||
@_call_screen_after
|
||||
def on_file_drop(self, x, y, paths):
|
||||
@ -483,11 +522,11 @@ class ClientWindow(Window):
|
||||
|
||||
@_call_screen_after
|
||||
def on_text(self, text):
|
||||
if text == '\r':
|
||||
if text == "\r":
|
||||
self.logger.debug(tr().window.text.new_line())
|
||||
else:
|
||||
self.logger.debug(tr().window.text.input().format(text))
|
||||
if text == 't':
|
||||
if text == "t":
|
||||
self.input_box.enabled = True
|
||||
|
||||
@_call_screen_after
|
||||
@ -501,8 +540,10 @@ class ClientWindow(Window):
|
||||
self.logger.debug(tr().window.text.motion_select().format(motion_string))
|
||||
|
||||
@_call_screen_before
|
||||
def on_close(self, source: str = 'window') -> None:
|
||||
self.game.dispatch_mod_event('on_close', game=self.game, client=self, source=source)
|
||||
def on_close(self, source: str = "window") -> None:
|
||||
self.game.dispatch_mod_event(
|
||||
"on_close", game=self.game, client=self, source=source
|
||||
)
|
||||
self.logger.info(tr().window.game.stop_get().format(tr().game[source]()))
|
||||
self.logger.info(tr().window.game.stop())
|
||||
# self.fps_log.check_list = False
|
||||
|
@ -18,9 +18,7 @@ from decimal import Decimal
|
||||
|
||||
|
||||
class FpsLogger:
|
||||
def __init__(self,
|
||||
stable_fps: int = 60,
|
||||
count: int = 700):
|
||||
def __init__(self, stable_fps: int = 60, count: int = 700):
|
||||
self.stable_fps = stable_fps
|
||||
self.count = count
|
||||
self._fps = stable_fps
|
||||
@ -30,9 +28,7 @@ class FpsLogger:
|
||||
self._max_fps = stable_fps
|
||||
self._min_fps = stable_fps
|
||||
|
||||
def update_tick(self,
|
||||
pyglet_fps: float,
|
||||
tick: Decimal):
|
||||
def update_tick(self, pyglet_fps: float, tick: Decimal):
|
||||
if pyglet_fps != 0:
|
||||
self.fps_list.append(pyglet_fps)
|
||||
elif tick == 0:
|
||||
@ -40,11 +36,13 @@ class FpsLogger:
|
||||
else:
|
||||
self.fps_list.append(float(1 / tick))
|
||||
if len(self.fps_list) > self.count:
|
||||
self.fps_list = self.fps_list[-self.count + 1:] # 整个列表往前挪一位
|
||||
self.fps_list = self.fps_list[-self.count + 1 :] # 整个列表往前挪一位
|
||||
if len(self.get_fps_list) > self.count:
|
||||
self.get_fps_list = self.get_fps_list[-self.count + 1:] # 整个列表往前挪一位
|
||||
self.get_fps_list = self.get_fps_list[-self.count + 1 :] # 整个列表往前挪一位
|
||||
try:
|
||||
self._fps = statistics.geometric_mean(self.fps_list[-100:]) # 取最后100个值的平均值
|
||||
self._fps = statistics.geometric_mean(
|
||||
self.fps_list[-100:]
|
||||
) # 取最后100个值的平均值
|
||||
self.middle_fps = statistics.median(self.fps_list) # 取中间值
|
||||
except Exception:
|
||||
print(self.fps_list)
|
||||
|
@ -18,10 +18,10 @@ from Difficult_Rocket.api.types import Fonts
|
||||
from pyglet.text.formats import structured
|
||||
|
||||
default_style = {
|
||||
'font_name': 'Times New Roman',
|
||||
'font_size': 12,
|
||||
'bold': False,
|
||||
'italic': False
|
||||
"font_name": "Times New Roman",
|
||||
"font_size": 12,
|
||||
"bold": False,
|
||||
"italic": False,
|
||||
}
|
||||
|
||||
|
||||
@ -34,17 +34,19 @@ class SingleTextStyle:
|
||||
单个字符的字体样式
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
font_name: str = '',
|
||||
font_size: int = 12,
|
||||
bold: bool = False,
|
||||
italic: bool = False,
|
||||
color: str = 'white',
|
||||
text_tag: list = None,
|
||||
show: bool = True,
|
||||
prefix: str = '',
|
||||
suffix: str = '',
|
||||
text: str = ''):
|
||||
def __init__(
|
||||
self,
|
||||
font_name: str = "",
|
||||
font_size: int = 12,
|
||||
bold: bool = False,
|
||||
italic: bool = False,
|
||||
color: str = "white",
|
||||
text_tag: list = None,
|
||||
show: bool = True,
|
||||
prefix: str = "",
|
||||
suffix: str = "",
|
||||
text: str = "",
|
||||
):
|
||||
self.font_name = font_name
|
||||
self.font_size = font_size
|
||||
self.bold = bold
|
||||
@ -66,7 +68,7 @@ class SingleTextStyle:
|
||||
|
||||
@tag.setter
|
||||
def tag(self, value: list):
|
||||
assert isinstance(value, list), 'SingleTextStyle.tag must be list'
|
||||
assert isinstance(value, list), "SingleTextStyle.tag must be list"
|
||||
for tag in value:
|
||||
if tag not in self._tag:
|
||||
self._tag.append(tag)
|
||||
@ -76,13 +78,15 @@ class SingleTextStyle:
|
||||
对运算操作的支持
|
||||
"""
|
||||
|
||||
def __add__(self, other: 'SingleTextStyle') -> 'SingleTextStyle':
|
||||
def __add__(self, other: "SingleTextStyle") -> "SingleTextStyle":
|
||||
"""
|
||||
叠加两个字体样式 优先使用 other 的样式
|
||||
:param other: 叠加的字体样式
|
||||
:return: 叠加后的字体样式
|
||||
"""
|
||||
assert isinstance(other, SingleTextStyle), f'SingleTextStyle + other\n other must be the same type, not a {type(other)}'
|
||||
assert isinstance(
|
||||
other, SingleTextStyle
|
||||
), f"SingleTextStyle + other\n other must be the same type, not a {type(other)}"
|
||||
return SingleTextStyle(
|
||||
font_name=other.font_name or self.font_name,
|
||||
font_size=other.font_size or self.font_size,
|
||||
@ -93,16 +97,18 @@ class SingleTextStyle:
|
||||
show=other.show or self.show,
|
||||
prefix=other.prefix + self.prefix,
|
||||
suffix=other.suffix + self.suffix,
|
||||
text=self.text
|
||||
text=self.text,
|
||||
)
|
||||
|
||||
def __iadd__(self, other: 'SingleTextStyle') -> 'SingleTextStyle':
|
||||
def __iadd__(self, other: "SingleTextStyle") -> "SingleTextStyle":
|
||||
"""
|
||||
叠加两个字体样式 优先使用 other 的样式
|
||||
:param other: 叠加的字体样式
|
||||
:return: 叠加后的字体样式
|
||||
"""
|
||||
assert isinstance(other, SingleTextStyle), f'SingleTextStyle += other\n other must be the same type, not a {type(other)}'
|
||||
assert isinstance(
|
||||
other, SingleTextStyle
|
||||
), f"SingleTextStyle += other\n other must be the same type, not a {type(other)}"
|
||||
self.font_name = other.font_name or self.font_name
|
||||
self.font_size = other.font_size or self.font_size
|
||||
self.bold = other.bold or self.bold
|
||||
@ -119,7 +125,7 @@ class SingleTextStyle:
|
||||
对各种判定的支持
|
||||
"""
|
||||
|
||||
def have_tag(self, other: 'SingleTextStyle') -> bool:
|
||||
def have_tag(self, other: "SingleTextStyle") -> bool:
|
||||
"""
|
||||
比较两个字体样式tag是否相同
|
||||
:param other: 叠加的字体样式
|
||||
@ -128,19 +134,21 @@ class SingleTextStyle:
|
||||
assert isinstance(other, SingleTextStyle)
|
||||
return other.tag in self.tag
|
||||
|
||||
def same_font(self, other: 'SingleTextStyle') -> bool:
|
||||
def same_font(self, other: "SingleTextStyle") -> bool:
|
||||
"""
|
||||
比较两个字体样式的字体属性是否相同
|
||||
:param other: 叠加的字体样式
|
||||
:return: 是否相同
|
||||
"""
|
||||
assert isinstance(other, SingleTextStyle)
|
||||
return (self.font_name == other.font_name and
|
||||
self.font_size == other.font_size and
|
||||
self.color == other.color and
|
||||
self.show == other.show)
|
||||
return (
|
||||
self.font_name == other.font_name
|
||||
and self.font_size == other.font_size
|
||||
and self.color == other.color
|
||||
and self.show == other.show
|
||||
)
|
||||
|
||||
def same_bold(self, other: 'SingleTextStyle') -> bool:
|
||||
def same_bold(self, other: "SingleTextStyle") -> bool:
|
||||
"""
|
||||
比较两个字体样式的加粗属性是否相同
|
||||
:param other: 叠加的字体样式
|
||||
@ -149,7 +157,7 @@ class SingleTextStyle:
|
||||
assert isinstance(other, SingleTextStyle)
|
||||
return self.bold == other.bold
|
||||
|
||||
def same_italic(self, other: 'SingleTextStyle') -> bool:
|
||||
def same_italic(self, other: "SingleTextStyle") -> bool:
|
||||
"""
|
||||
比较两个字体样式的斜体属性是否相同
|
||||
:param other: 叠加的字体样式
|
||||
@ -170,9 +178,9 @@ class SingleTextStyle:
|
||||
if suffix:
|
||||
return font_HTML_end
|
||||
text = f'<font face="{self.font_name}" color={self.color}'
|
||||
if self.font_size != default_style['font_size']:
|
||||
text += f' real_size={self.font_size}'
|
||||
text += '>'
|
||||
if self.font_size != default_style["font_size"]:
|
||||
text += f" real_size={self.font_size}"
|
||||
text += ">"
|
||||
return text
|
||||
|
||||
def HTML_bold(self, suffix: bool = False) -> str:
|
||||
@ -184,9 +192,9 @@ class SingleTextStyle:
|
||||
if self.bold:
|
||||
if suffix:
|
||||
return bold_HTML_end
|
||||
return '<b>'
|
||||
return "<b>"
|
||||
else:
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def HTML_italic(self, suffix: bool = False) -> str:
|
||||
"""
|
||||
@ -196,9 +204,9 @@ class SingleTextStyle:
|
||||
if self.italic:
|
||||
if suffix:
|
||||
return italic_HTML_end
|
||||
return '<i>'
|
||||
return "<i>"
|
||||
else:
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def HTML(self, suffix: bool = False) -> str:
|
||||
"""
|
||||
@ -206,9 +214,11 @@ class SingleTextStyle:
|
||||
:return: HTML 格式字符
|
||||
"""
|
||||
return (
|
||||
(font_HTML_end
|
||||
+ (bold_HTML_end if self.bold else '')
|
||||
+ (italic_HTML_end if self.italic else ''))
|
||||
(
|
||||
font_HTML_end
|
||||
+ (bold_HTML_end if self.bold else "")
|
||||
+ (italic_HTML_end if self.italic else "")
|
||||
)
|
||||
if suffix
|
||||
else self.HTML_bold() + self.HTML_italic() + self.HTML_font()
|
||||
)
|
||||
@ -217,37 +227,44 @@ class SingleTextStyle:
|
||||
# [\u4e00-\u9fa5] 中文字符
|
||||
default_fonts_config = [
|
||||
{
|
||||
'match': re.compile(r''), # 匹配的字符 匹配选项是re.compile()
|
||||
'shown': re.compile(r''), # 匹配到的字符中显示的部分 匹配选项是re.compile()
|
||||
'style': SingleTextStyle(font_name=Fonts.鸿蒙简体, font_size=15, bold=False, italic=False, show=True, color='white')
|
||||
"match": re.compile(r""), # 匹配的字符 匹配选项是re.compile()
|
||||
"shown": re.compile(r""), # 匹配到的字符中显示的部分 匹配选项是re.compile()
|
||||
"style": SingleTextStyle(
|
||||
font_name=Fonts.鸿蒙简体,
|
||||
font_size=15,
|
||||
bold=False,
|
||||
italic=False,
|
||||
show=True,
|
||||
color="white",
|
||||
),
|
||||
},
|
||||
{
|
||||
'match': re.compile(r'[a-zA-Z0-9]'),
|
||||
'shown': re.compile(r'[a-zA-Z0-9]'),
|
||||
'style': SingleTextStyle(font_name=Fonts.微软等宽, font_size=15)
|
||||
"match": re.compile(r"[a-zA-Z0-9]"),
|
||||
"shown": re.compile(r"[a-zA-Z0-9]"),
|
||||
"style": SingleTextStyle(font_name=Fonts.微软等宽, font_size=15),
|
||||
},
|
||||
# Markdown 语法规则匹配
|
||||
{
|
||||
# Markdown 粗体语法规则匹配
|
||||
'match': re.compile(r'\*\*(.*?(?<!\s))\*\*'),
|
||||
'shown': re.compile(r'(?<=\*\*)(.*?(?<!\s))(?=\*\*)'),
|
||||
'tag': {
|
||||
"match": re.compile(r"\*\*(.*?(?<!\s))\*\*"),
|
||||
"shown": re.compile(r"(?<=\*\*)(.*?(?<!\s))(?=\*\*)"),
|
||||
"tag": {
|
||||
# 为 match 匹配到的字符添加标签
|
||||
'match': re.compile(r'\*\*'),
|
||||
'style': SingleTextStyle(text_tag=['bold'])
|
||||
"match": re.compile(r"\*\*"),
|
||||
"style": SingleTextStyle(text_tag=["bold"]),
|
||||
},
|
||||
'style': SingleTextStyle(bold=True)
|
||||
"style": SingleTextStyle(bold=True),
|
||||
},
|
||||
{
|
||||
# Markdown 斜体语法规则匹配
|
||||
'match': re.compile(r'\*(.*?(?<!\s))\*'),
|
||||
'shown': re.compile(r'(?<=\*)(.*?(?<!\s))(?=\*)'),
|
||||
'ignore': {
|
||||
"match": re.compile(r"\*(.*?(?<!\s))\*"),
|
||||
"shown": re.compile(r"(?<=\*)(.*?(?<!\s))(?=\*)"),
|
||||
"ignore": {
|
||||
# 如果匹配到的字符含有 tag 就忽略本次解析
|
||||
'match': re.compile(r'\*'),
|
||||
'tag': SingleTextStyle(text_tag=['italic'])
|
||||
"match": re.compile(r"\*"),
|
||||
"tag": SingleTextStyle(text_tag=["italic"]),
|
||||
},
|
||||
'style': SingleTextStyle(italic=True)
|
||||
"style": SingleTextStyle(italic=True),
|
||||
},
|
||||
{
|
||||
# Markdown 链接规则匹配
|
||||
@ -255,23 +272,21 @@ default_fonts_config = [
|
||||
# 即:链接名称不能是空格等空白字符开头,链接名称不能是空格等空白字符结尾
|
||||
# 匹配的内容:[abc](def)
|
||||
# 显示的内容:abc
|
||||
'match': re.compile(r'\[(.*?(?<!\s))]\((.*?(?<!\s))\)'),
|
||||
'shown': re.compile(r'(?<=\[)(.*?(?<!\s))(?=]\((.*?(?<!\s))\))'),
|
||||
'style': SingleTextStyle(bold=True)
|
||||
}
|
||||
"match": re.compile(r"\[(.*?(?<!\s))]\((.*?(?<!\s))\)"),
|
||||
"shown": re.compile(r"(?<=\[)(.*?(?<!\s))(?=]\((.*?(?<!\s))\))"),
|
||||
"style": SingleTextStyle(bold=True),
|
||||
},
|
||||
]
|
||||
font_HTML_end = '</font>'
|
||||
bold_HTML = '<b>'
|
||||
bold_HTML_end = '</b>'
|
||||
italic_HTML = '<i>'
|
||||
italic_HTML_end = '</i>'
|
||||
font_HTML_end = "</font>"
|
||||
bold_HTML = "<b>"
|
||||
bold_HTML_end = "</b>"
|
||||
italic_HTML = "<i>"
|
||||
italic_HTML_end = "</i>"
|
||||
|
||||
|
||||
def decode_text2HTML(text: str,
|
||||
configs=None,
|
||||
show_style: bool = False) -> str:
|
||||
def decode_text2HTML(text: str, configs=None, show_style: bool = False) -> str:
|
||||
if not text:
|
||||
return ''
|
||||
return ""
|
||||
if configs is None:
|
||||
configs = default_fonts_config
|
||||
style_list = [SingleTextStyle(text=text[x]) for x in range(len(text))]
|
||||
@ -279,36 +294,51 @@ def decode_text2HTML(text: str,
|
||||
# 根据输入的配置对每一个字符进行样式设定
|
||||
for config in configs:
|
||||
# 根据 配置"文件"
|
||||
match_texts = config['match'].finditer(text) # 使用 config.match 匹配
|
||||
match_texts = config["match"].finditer(text) # 使用 config.match 匹配
|
||||
for match_text in match_texts: # 每一个匹配到的匹配项
|
||||
text_match = match_text.group() # 缓存一下匹配到的字符,用于匹配显示的字符
|
||||
shown_texts = config['shown'].finditer(text_match) # 使用 config.shown 匹配
|
||||
shown_texts = config["shown"].finditer(text_match) # 使用 config.shown 匹配
|
||||
match_start, match_end = match_text.span()
|
||||
if 'ignore' in config: # 如果样式选项包含忽略某些字符的tag
|
||||
ignore_texts = config['ignore']['match'].finditer(text_match) # 根据选项匹配可能忽略的字符
|
||||
if "ignore" in config: # 如果样式选项包含忽略某些字符的tag
|
||||
ignore_texts = config["ignore"]["match"].finditer(
|
||||
text_match
|
||||
) # 根据选项匹配可能忽略的字符
|
||||
ignore = False # 忽略先为False
|
||||
for ignore_text in ignore_texts: # 每一个可能忽略的字符
|
||||
if ignore: # 为了方便退出
|
||||
break
|
||||
for ignore_index in range(match_start + ignore_text.span()[0], match_start + ignore_text.span()[1]): # 对每一个可能的字符进行检测
|
||||
if style_list[ignore_index].have_tag(config['ignore']['tag']): # 如果确实包含要忽略的
|
||||
for ignore_index in range(
|
||||
match_start + ignore_text.span()[0],
|
||||
match_start + ignore_text.span()[1],
|
||||
): # 对每一个可能的字符进行检测
|
||||
if style_list[ignore_index].have_tag(
|
||||
config["ignore"]["tag"]
|
||||
): # 如果确实包含要忽略的
|
||||
ignore = True # 忽略为True
|
||||
break
|
||||
if ignore:
|
||||
continue # 跳过本次匹配
|
||||
if 'tag' in config: # 如果样式选项包含对部分字符添加tag
|
||||
tag_texts = config['tag']['match'].finditer(text_match) # 根据配置的正则表达式匹配要添加tag的字符
|
||||
if "tag" in config: # 如果样式选项包含对部分字符添加tag
|
||||
tag_texts = config["tag"]["match"].finditer(
|
||||
text_match
|
||||
) # 根据配置的正则表达式匹配要添加tag的字符
|
||||
for tag_text in tag_texts: # 对每一个匹配到的~~~~~~
|
||||
for tag_index in range(match_start + tag_text.span()[0], match_start + tag_text.span()[1]): # 用于遍历匹配到的字符
|
||||
style_list[tag_index] += config['tag']['style']
|
||||
for tag_index in range(
|
||||
match_start + tag_text.span()[0], match_start + tag_text.span()[1]
|
||||
): # 用于遍历匹配到的字符
|
||||
style_list[tag_index] += config["tag"]["style"]
|
||||
# 为匹配到的字符添加样式
|
||||
for match_index in range(match_start, match_end): # 用于遍历匹配到的字符
|
||||
# 这里用 match index 来精确读写列表里的元素,毕竟 re.Match 返回的 span 是两个标点,得遍历
|
||||
style_list[match_index] += config['style'] # 字体样式列表的 [match_index] += config['style'] 的样式
|
||||
style_list[match_index] += config[
|
||||
"style"
|
||||
] # 字体样式列表的 [match_index] += config['style'] 的样式
|
||||
style_list[match_index].show = show_style # 设置显示属性变为 False
|
||||
# 为每一个显示的字符设置显示属性
|
||||
for shown_text in shown_texts: # 每一个显示的匹配项
|
||||
for shown_index in range(match_start + shown_text.span()[0], match_start + shown_text.span()[1]):
|
||||
for shown_index in range(
|
||||
match_start + shown_text.span()[0], match_start + shown_text.span()[1]
|
||||
):
|
||||
style_list[shown_index].show = True
|
||||
# 字体样式列表的 [shown_index] 设置显示属性变为 True
|
||||
# 开始根据配置好的样式输出HTML文本
|
||||
@ -317,25 +347,35 @@ def decode_text2HTML(text: str,
|
||||
if style_list[style_index].show: # 如果这个字符显示
|
||||
if style_list[style_index - 1].show: # 开始根据前面的情况处理每种单独的标签
|
||||
if not style_list[style_index - 1].same_font(style_list[style_index]):
|
||||
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_font(suffix=True)
|
||||
style_list[style_index - 1].suffix += style_list[
|
||||
style_index - 1
|
||||
].HTML_font(suffix=True)
|
||||
style_list[style_index].prefix += style_list[style_index].HTML_font()
|
||||
if not style_list[style_index - 1].same_bold(style_list[style_index]):
|
||||
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_bold(suffix=True)
|
||||
style_list[style_index - 1].suffix += style_list[
|
||||
style_index - 1
|
||||
].HTML_bold(suffix=True)
|
||||
style_list[style_index].prefix += style_list[style_index].HTML_bold()
|
||||
if not style_list[style_index - 1].same_italic(style_list[style_index]):
|
||||
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML_italic(suffix=True)
|
||||
style_list[style_index].prefix += style_list[style_index].HTML_italic()
|
||||
style_list[style_index - 1].suffix += style_list[
|
||||
style_index - 1
|
||||
].HTML_italic(suffix=True)
|
||||
style_list[style_index].prefix += style_list[
|
||||
style_index
|
||||
].HTML_italic()
|
||||
else: # 如果前面一个字符不显示(且这个字符显示)
|
||||
style_list[style_index].prefix += style_list[style_index].HTML() # 那么就直接给这个字符的前缀添加
|
||||
style_list[style_index].prefix += style_list[
|
||||
style_index
|
||||
].HTML() # 那么就直接给这个字符的前缀添加
|
||||
elif style_list[style_index - 1].show: # 如果前面一个字符显示(且这个字符不显示)
|
||||
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML(suffix=True)
|
||||
style_list[style_index - 1].suffix += style_list[style_index - 1].HTML(
|
||||
suffix=True
|
||||
)
|
||||
if style_list[-1].show:
|
||||
style_list[-1].suffix += style_list[-1].HTML(suffix=True)
|
||||
|
||||
formatted_HTML_text = ''.join(
|
||||
style.prefix + style.text + style.suffix
|
||||
for style in style_list
|
||||
if style.show
|
||||
formatted_HTML_text = "".join(
|
||||
style.prefix + style.text + style.suffix for style in style_list if style.show
|
||||
)
|
||||
del style_list # 主动删掉 style_list 释放内存
|
||||
return formatted_HTML_text # 返回,DONE!
|
||||
|
@ -21,5 +21,5 @@ class FontsLabel(DocumentLabel):
|
||||
|
||||
def __init__(self, x, y, width, height):
|
||||
super().__init__(x, y, width, height)
|
||||
self._text = 'a'
|
||||
self.formatted_text = 'a'
|
||||
self._text = "a"
|
||||
self.formatted_text = "a"
|
||||
|
@ -23,12 +23,19 @@ class DRDEBUGScreen(BaseScreen):
|
||||
super().__init__(main_window)
|
||||
self.main_batch = Batch()
|
||||
self.main_group = Group(order=1)
|
||||
self.fps_label = Label(x=10, y=main_window.height - 10,
|
||||
width=main_window.width - 20, height=20,
|
||||
anchor_x='left', anchor_y='top',
|
||||
font_name=Fonts.微软等宽无线, font_size=20,
|
||||
multiline=True,
|
||||
batch=self.main_batch, group=self.main_group)
|
||||
self.fps_label = Label(
|
||||
x=10,
|
||||
y=main_window.height - 10,
|
||||
width=main_window.width - 20,
|
||||
height=20,
|
||||
anchor_x="left",
|
||||
anchor_y="top",
|
||||
font_name=Fonts.微软等宽无线,
|
||||
font_size=20,
|
||||
multiline=True,
|
||||
batch=self.main_batch,
|
||||
group=self.main_group,
|
||||
)
|
||||
self.fps_label.text = "11111114514"
|
||||
|
||||
def draw_update(self, tick: float, window: "ClientWindow"):
|
||||
@ -37,10 +44,10 @@ class DRDEBUGScreen(BaseScreen):
|
||||
def update_label(self, window: "ClientWindow"):
|
||||
now_FPS = get_frequency()
|
||||
self.fps_label.text = (
|
||||
f'FPS: {window.fps_log.fps: >5.1f}('
|
||||
f'{window.fps_log.middle_fps: >5.1f})[{now_FPS: >.7f}]\n '
|
||||
f'{window.fps_log.max_fps: >7.1f} '
|
||||
f'{window.fps_log.min_fps:>5.1f}'
|
||||
f"FPS: {window.fps_log.fps: >5.1f}("
|
||||
f"{window.fps_log.middle_fps: >5.1f})[{now_FPS: >.7f}]\n "
|
||||
f"{window.fps_log.max_fps: >7.1f} "
|
||||
f"{window.fps_log.min_fps:>5.1f}"
|
||||
)
|
||||
|
||||
def on_resize(self, width, height, window: "ClientWindow"):
|
||||
|
@ -1,4 +1,4 @@
|
||||
# -------------------------------
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||
# All rights reserved
|
||||
|
@ -49,7 +49,11 @@ class CommandText:
|
||||
find = self.text.find(text)
|
||||
if find != -1:
|
||||
if not len(text) == len(self.text):
|
||||
self.text = self.text[find + len(text):] if not self.text[find+len(text)] == ' ' else self.text[find + len(text) + 1:]
|
||||
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
|
||||
|
||||
@ -64,9 +68,9 @@ class CommandText:
|
||||
# 20230122 我现在也不知道为啥这么写了
|
||||
# 果然使用正则表达式就是让一个问题变成两个问题
|
||||
except IndexError:
|
||||
self.text = self.text[finding.span()[1] + 1:]
|
||||
self.text = self.text[finding.span()[1] + 1 :]
|
||||
return True
|
||||
if next_find == ' ':
|
||||
if next_find == " ":
|
||||
return True
|
||||
# 将匹配到的字符串,和最后一个匹配字符后面的字符删除(相当暴力的操作)
|
||||
return False
|
||||
@ -74,17 +78,14 @@ class CommandText:
|
||||
def int_value(self, name: Optional[str]):
|
||||
...
|
||||
|
||||
def value(self,
|
||||
name: str = None,
|
||||
split: str = ' ',
|
||||
middle: list = ('\'', '\"')):
|
||||
def value(self, name: str = None, split: str = " ", middle: list = ("'", '"')):
|
||||
pass
|
||||
|
||||
def get_all(self, value_name: str):
|
||||
self.value_list.append(self.text)
|
||||
if value_name:
|
||||
self.value_dict[value_name] = self.text
|
||||
self.text = ''
|
||||
self.text = ""
|
||||
return self.value_list[-1]
|
||||
|
||||
def get_value(self):
|
||||
|
@ -35,14 +35,28 @@ class CommandLineTextEntry(widgets.TextEntry):
|
||||
基于 Text Entry 重写的 Command Line
|
||||
"""
|
||||
|
||||
def __init__(self, x: int, y: int, width: int,
|
||||
color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255),
|
||||
text_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0, 255),
|
||||
caret_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0),
|
||||
batch: Optional[Batch] = None, group: Optional[Group] = None):
|
||||
super().__init__(x=x, y=y, width=width,
|
||||
color=color, text_color=text_color, caret_color=caret_color,
|
||||
batch=batch, group=group, text='')
|
||||
def __init__(
|
||||
self,
|
||||
x: int,
|
||||
y: int,
|
||||
width: int,
|
||||
color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255),
|
||||
text_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0, 255),
|
||||
caret_color: Optional[Tuple[int, int, int, int]] = (0, 0, 0),
|
||||
batch: Optional[Batch] = None,
|
||||
group: Optional[Group] = None,
|
||||
):
|
||||
super().__init__(
|
||||
x=x,
|
||||
y=y,
|
||||
width=width,
|
||||
color=color,
|
||||
text_color=text_color,
|
||||
caret_color=caret_color,
|
||||
batch=batch,
|
||||
group=group,
|
||||
text="",
|
||||
)
|
||||
...
|
||||
|
||||
|
||||
@ -51,26 +65,28 @@ class CommandLine(widgets.WidgetBase):
|
||||
command line show
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
x: int,
|
||||
y: int,
|
||||
width: int,
|
||||
height: int,
|
||||
length: int,
|
||||
batch: Batch,
|
||||
group: Group = None,
|
||||
command_text: str = '/',
|
||||
font_size: int = 20):
|
||||
def __init__(
|
||||
self,
|
||||
x: int,
|
||||
y: int,
|
||||
width: int,
|
||||
height: int,
|
||||
length: int,
|
||||
batch: Batch,
|
||||
group: Group = None,
|
||||
command_text: str = "/",
|
||||
font_size: int = 20,
|
||||
):
|
||||
super().__init__(x, y, width, height)
|
||||
|
||||
# normal values
|
||||
self.length = length
|
||||
self._command_list = ['' for _ in range(length)]
|
||||
self._command_list = ["" for _ in range(length)]
|
||||
self._command_text = command_text
|
||||
self._text_position = 0
|
||||
self._command_view = 0
|
||||
self._value = 0
|
||||
self._text = ''
|
||||
self._text = ""
|
||||
self.command_split = 25
|
||||
self.command_distance = 20
|
||||
|
||||
@ -80,24 +96,45 @@ class CommandLine(widgets.WidgetBase):
|
||||
fg_group = Group(order=1, parent=group)
|
||||
|
||||
# hidden value
|
||||
self._text = ''
|
||||
self._line = Label(x=x, y=y, batch=batch, text=self.text,
|
||||
color=(100, 255, 255, 255),
|
||||
anchor_x='left', anchor_y='bottom',
|
||||
font_size=font_size, font_name=translate.微软等宽,
|
||||
group=fg_group)
|
||||
self._label = [Label(x=x + 10, y=y + self.command_distance + (line * self.command_split), batch=batch, text='a',
|
||||
anchor_x='left', anchor_y='bottom',
|
||||
font_size=font_size - 3, font_name=translate.鸿蒙简体,
|
||||
group=bg_group)
|
||||
for line in range(length)]
|
||||
self._text = ""
|
||||
self._line = Label(
|
||||
x=x,
|
||||
y=y,
|
||||
batch=batch,
|
||||
text=self.text,
|
||||
color=(100, 255, 255, 255),
|
||||
anchor_x="left",
|
||||
anchor_y="bottom",
|
||||
font_size=font_size,
|
||||
font_name=translate.微软等宽,
|
||||
group=fg_group,
|
||||
)
|
||||
self._label = [
|
||||
Label(
|
||||
x=x + 10,
|
||||
y=y + self.command_distance + (line * self.command_split),
|
||||
batch=batch,
|
||||
text="a",
|
||||
anchor_x="left",
|
||||
anchor_y="bottom",
|
||||
font_size=font_size - 3,
|
||||
font_name=translate.鸿蒙简体,
|
||||
group=bg_group,
|
||||
)
|
||||
for line in range(length)
|
||||
]
|
||||
# Rectangular outline with 5-pixel pad:
|
||||
color = (100, 100, 100, 100)
|
||||
self._pad = p = 5
|
||||
self._outline = pyglet.shapes.Rectangle(x=x - p, y=y - p,
|
||||
width=width + p, height=height + p,
|
||||
color=color[:3],
|
||||
batch=batch, group=fg_group)
|
||||
self._outline = pyglet.shapes.Rectangle(
|
||||
x=x - p,
|
||||
y=y - p,
|
||||
width=width + p,
|
||||
height=height + p,
|
||||
color=color[:3],
|
||||
batch=batch,
|
||||
group=fg_group,
|
||||
)
|
||||
self._outline.opacity = color[3]
|
||||
|
||||
self.editing = False
|
||||
@ -125,7 +162,7 @@ class CommandLine(widgets.WidgetBase):
|
||||
|
||||
@text.setter
|
||||
def text(self, value):
|
||||
assert isinstance(value, str), 'CommandLine\'s text must be string!'
|
||||
assert isinstance(value, str), "CommandLine's text must be string!"
|
||||
self._text = value
|
||||
self._line.text = value
|
||||
|
||||
@ -143,15 +180,19 @@ class CommandLine(widgets.WidgetBase):
|
||||
0 ~ (self.length-1) -> 切换视角到对应的行数
|
||||
实际上还有一个限制
|
||||
"""
|
||||
assert isinstance(value, int), 'Command View must be integer'
|
||||
assert -self.length < value < self.length, f'Command View must be bigger than {-self.length} and smaller than {self.length}'
|
||||
assert isinstance(value, int), "Command View must be integer"
|
||||
assert (
|
||||
-self.length < value < self.length
|
||||
), f"Command View must be bigger than {-self.length} and smaller than {self.length}"
|
||||
if value == -1: # flush command list
|
||||
self._label.insert(0, self._label[-1])
|
||||
self._label.pop(-1)
|
||||
for line in range(self.length):
|
||||
self._label[line].y = self.y + self.command_distance + (line * self.command_split)
|
||||
self._label[line].y = (
|
||||
self.y + self.command_distance + (line * self.command_split)
|
||||
)
|
||||
self._label[0].text = self.text
|
||||
self.text = ''
|
||||
self.text = ""
|
||||
self._command_view = 0
|
||||
self._text_position = 0
|
||||
elif value == self._command_view: # not doing anything
|
||||
@ -168,21 +209,25 @@ class CommandLine(widgets.WidgetBase):
|
||||
|
||||
@editing.setter
|
||||
def editing(self, value):
|
||||
assert isinstance(value, bool), 'Command editing must be bool!'
|
||||
assert isinstance(value, bool), "Command editing must be bool!"
|
||||
self._editing = value
|
||||
self._line.visible = value
|
||||
self._outline.visible = value
|
||||
for label in self._label:
|
||||
label.visible = value
|
||||
|
||||
@new_thread('command wait', daemon=True, log_thread=False)
|
||||
@new_thread("command wait", daemon=True, log_thread=False)
|
||||
def wait(self, wait: Union[float, int] = 0):
|
||||
this = self._label[0]
|
||||
self._label[0].visible = True
|
||||
time.sleep(wait)
|
||||
if self._label[0].visible and not self.editing:
|
||||
while (self._label[0].opacity >= 30) and self._label[0].visible and (
|
||||
self._label[0] is this) and not self.editing:
|
||||
while (
|
||||
(self._label[0].opacity >= 30)
|
||||
and self._label[0].visible
|
||||
and (self._label[0] is this)
|
||||
and not self.editing
|
||||
):
|
||||
# (label 的透明度不是 0) and (label 还在显示) and (label 还是载入线程时候的那个label) and (现在不在输入新行)
|
||||
self._label[0].opacity -= 2
|
||||
time.sleep(0.01)
|
||||
@ -206,45 +251,57 @@ class CommandLine(widgets.WidgetBase):
|
||||
# 这里的大部分东西都会在最近被重写
|
||||
# TODO 重写成基于新的 InputBox 的解析
|
||||
if self.editing:
|
||||
if text in ('\r', '\n'): # goto a new line
|
||||
if text in ("\r", "\n"): # goto a new line
|
||||
if not self.text:
|
||||
pass
|
||||
elif self.text[0] == self._command_text:
|
||||
self.dispatch_event('on_command', CommandText(self.text[1:]))
|
||||
self.dispatch_event("on_command", CommandText(self.text[1:]))
|
||||
else:
|
||||
self.dispatch_event('on_message', CommandText(self.text))
|
||||
self.dispatch_event("on_message", CommandText(self.text))
|
||||
# on_message 和 on_command 可能会覆盖 self.text 需要再次判定
|
||||
if self.text:
|
||||
self.command_view = -1
|
||||
self.editing = False
|
||||
self.wait()
|
||||
else:
|
||||
self.text = f'{self.text[:self._text_position]}{text}{self.text[self._text_position:]}' # 插入字符(简单粗暴)
|
||||
self.text = f"{self.text[:self._text_position]}{text}{self.text[self._text_position:]}" # 插入字符(简单粗暴)
|
||||
self._text_position += 1
|
||||
elif text == 't': # open message line
|
||||
elif text == "t": # open message line
|
||||
self.editing = True
|
||||
elif text == '/': # open command line
|
||||
elif text == "/": # open command line
|
||||
self.editing = True
|
||||
self.text = '/'
|
||||
self.text = "/"
|
||||
self._text_position = 1
|
||||
|
||||
def on_text_motion(self, motion):
|
||||
if self.editing:
|
||||
# edit motion
|
||||
if motion == key.MOTION_DELETE: # 确保不越界
|
||||
self.text = f'{self.text[:self._text_position]}{self.text[self._text_position + 1:]}' # 简单粗暴的删除
|
||||
elif motion == key.MOTION_BACKSPACE and self._text_position >= 1: # 确保不越界
|
||||
self.text = f'{self.text[:self._text_position - 1]}{self.text[self._text_position:]}' # 简单粗暴的删除
|
||||
self.text = f"{self.text[:self._text_position]}{self.text[self._text_position + 1:]}" # 简单粗暴的删除
|
||||
elif (
|
||||
motion == key.MOTION_BACKSPACE and self._text_position >= 1
|
||||
): # 确保不越界
|
||||
self.text = f"{self.text[:self._text_position - 1]}{self.text[self._text_position:]}" # 简单粗暴的删除
|
||||
self._text_position -= 1 # 记得切换光标位置
|
||||
|
||||
# move motion
|
||||
elif motion == key.MOTION_LEFT and self._text_position >= 0: # 确保不越界
|
||||
self._text_position -= 1
|
||||
elif motion == key.MOTION_RIGHT and self._text_position <= len(self.text): # 确保不越界
|
||||
elif motion == key.MOTION_RIGHT and self._text_position <= len(
|
||||
self.text
|
||||
): # 确保不越界
|
||||
self._text_position += 1
|
||||
elif motion in (key.MOTION_BEGINNING_OF_LINE, key.MOTION_BEGINNING_OF_FILE, key.MOTION_PREVIOUS_PAGE):
|
||||
elif motion in (
|
||||
key.MOTION_BEGINNING_OF_LINE,
|
||||
key.MOTION_BEGINNING_OF_FILE,
|
||||
key.MOTION_PREVIOUS_PAGE,
|
||||
):
|
||||
self._text_position = 0
|
||||
elif motion in (key.MOTION_END_OF_LINE, key.MOTION_END_OF_FILE, key.MOTION_NEXT_PAGE):
|
||||
elif motion in (
|
||||
key.MOTION_END_OF_LINE,
|
||||
key.MOTION_END_OF_FILE,
|
||||
key.MOTION_NEXT_PAGE,
|
||||
):
|
||||
self._text_position = len(self.text)
|
||||
|
||||
# view move motion
|
||||
@ -288,5 +345,5 @@ class CommandLine(widgets.WidgetBase):
|
||||
self.text = _text
|
||||
|
||||
|
||||
CommandLine.register_event_type('on_command')
|
||||
CommandLine.register_event_type('on_message')
|
||||
CommandLine.register_event_type("on_command")
|
||||
CommandLine.register_event_type("on_message")
|
||||
|
@ -54,31 +54,35 @@ all_process = [multiprocessing.current_process()]
|
||||
|
||||
def crash_info_handler(info: Optional[str] = None) -> str:
|
||||
if not info:
|
||||
info = traceback.format_exc().replace('<', '< ')
|
||||
info = traceback.format_exc().replace("<", "< ")
|
||||
format_info = f"<pre>\n{info}</pre>\n"
|
||||
format_info.replace('<module>', '< module>')
|
||||
format_info.replace("<module>", "< module>")
|
||||
return format_info
|
||||
|
||||
|
||||
def markdown_line_handler(string: Optional[Union[str, bool, int, float]], code: bool = False, level: int = 1,
|
||||
end: str = '\n') -> str:
|
||||
lvl = '- ' * level
|
||||
def markdown_line_handler(
|
||||
string: Optional[Union[str, bool, int, float]],
|
||||
code: bool = False,
|
||||
level: int = 1,
|
||||
end: str = "\n",
|
||||
) -> str:
|
||||
lvl = "- " * level
|
||||
f_string = string
|
||||
if code:
|
||||
f_string = f'`{f_string}`'
|
||||
return f'{lvl}{f_string}{end}'
|
||||
f_string = f"`{f_string}`"
|
||||
return f"{lvl}{f_string}{end}"
|
||||
|
||||
|
||||
def to_code(string: str):
|
||||
return f'`{string}`'
|
||||
return f"`{string}`"
|
||||
|
||||
|
||||
def create_crash_report(info: Optional[str] = None) -> None:
|
||||
crash_info = crash_info_handler(info)
|
||||
if 'crash_report' not in os.listdir('./'):
|
||||
os.mkdir('./crash_report')
|
||||
date_time = time.strftime('%Y-%m-%d %H-%M-%S', time.localtime())
|
||||
filename = f'crash-{date_time}.md'
|
||||
if "crash_report" not in os.listdir("./"):
|
||||
os.mkdir("./crash_report")
|
||||
date_time = time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())
|
||||
filename = f"crash-{date_time}.md"
|
||||
cache_stream = io.StringIO()
|
||||
try:
|
||||
write_cache(cache_stream, crash_info)
|
||||
@ -86,13 +90,15 @@ def create_crash_report(info: Optional[str] = None) -> None:
|
||||
finally:
|
||||
get_cache = cache_stream.getvalue()
|
||||
cache_stream.close()
|
||||
with open(f'./crash_report/{filename}', 'w+', encoding='utf-8') as crash_file:
|
||||
with open(f"./crash_report/{filename}", "w+", encoding="utf-8") as crash_file:
|
||||
crash_file.write(get_cache)
|
||||
|
||||
|
||||
def write_cache(cache_stream, crash_info):
|
||||
# 开头信息
|
||||
cache_stream.write(Head_message.format(now_time=time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())))
|
||||
cache_stream.write(
|
||||
Head_message.format(now_time=time.strftime("%Y/%m/%d %H:%M:%S", time.localtime()))
|
||||
)
|
||||
# 崩溃信息
|
||||
cache_stream.write(crash_info)
|
||||
|
||||
@ -101,47 +107,82 @@ def write_info_to_cache(cache_stream):
|
||||
# 运行状态信息
|
||||
from Difficult_Rocket import DR_status
|
||||
from Difficult_Rocket.runtime import DR_runtime
|
||||
|
||||
cache_stream.write(Run_message)
|
||||
cache_stream.write(markdown_line_handler(f'DR Version: {Difficult_Rocket.sdk_version}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'DR language: {DR_runtime.language}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'Running Dir: {Path(os.curdir).resolve()}', level=1))
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"DR Version: {Difficult_Rocket.sdk_version}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"DR language: {DR_runtime.language}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Running Dir: {Path(os.curdir).resolve()}", level=1)
|
||||
)
|
||||
cache_stream.write(f"\n{DR_runtime.as_markdown()}")
|
||||
cache_stream.write(DR_configs)
|
||||
cache_stream.write(f"\n{DR_status.as_markdown()}")
|
||||
cache_stream.write(Process_message)
|
||||
for process in all_process:
|
||||
process: multiprocessing.Process
|
||||
cache_stream.write(markdown_line_handler(f'{process.name}', code=True))
|
||||
cache_stream.write(markdown_line_handler(f'Ident: {process.ident}', level=2))
|
||||
cache_stream.write(markdown_line_handler(f'Running: {process.is_alive()}', level=2))
|
||||
cache_stream.write(markdown_line_handler(f"{process.name}", code=True))
|
||||
cache_stream.write(markdown_line_handler(f"Ident: {process.ident}", level=2))
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Running: {process.is_alive()}", level=2)
|
||||
)
|
||||
# 运行线程信息
|
||||
cache_stream.write(Thread_message)
|
||||
for thread in all_thread:
|
||||
thread: threading.Thread
|
||||
cache_stream.write(markdown_line_handler(f'{thread.name}', code=True))
|
||||
cache_stream.write(markdown_line_handler(f'order: {all_thread.index(thread)}', level=2))
|
||||
cache_stream.write(markdown_line_handler(f'Ident: {thread.ident}', level=2))
|
||||
cache_stream.write(markdown_line_handler(f'Daemon: {thread.daemon}', level=2))
|
||||
cache_stream.write(markdown_line_handler(f'Running: {thread.is_alive()}', level=2))
|
||||
cache_stream.write(markdown_line_handler(f"{thread.name}", code=True))
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"order: {all_thread.index(thread)}", level=2)
|
||||
)
|
||||
cache_stream.write(markdown_line_handler(f"Ident: {thread.ident}", level=2))
|
||||
cache_stream.write(markdown_line_handler(f"Daemon: {thread.daemon}", level=2))
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Running: {thread.is_alive()}", level=2)
|
||||
)
|
||||
# Python 信息
|
||||
cache_stream.write(Python_message)
|
||||
cache_stream.write(markdown_line_handler(f'Version: {to_code(platform.python_version())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'Branch: {to_code(platform.python_branch())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'Implementation: {to_code(platform.python_implementation())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'Compiler: {to_code(platform.python_compiler())}', level=1))
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Version: {to_code(platform.python_version())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Branch: {to_code(platform.python_branch())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(
|
||||
f"Implementation: {to_code(platform.python_implementation())}", level=1
|
||||
)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Compiler: {to_code(platform.python_compiler())}", level=1)
|
||||
)
|
||||
# 电脑系统信息
|
||||
cache_stream.write(System_message)
|
||||
cache_stream.write(markdown_line_handler(f'System: {to_code(platform.platform())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'Computer name: {to_code(platform.node())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'machine: {to_code(platform.machine())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'processor: {to_code(platform.processor())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'release: {to_code(platform.release())}', level=1))
|
||||
cache_stream.write(markdown_line_handler(f'version: {to_code(platform.version())}', level=1))
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"System: {to_code(platform.platform())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"Computer name: {to_code(platform.node())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"machine: {to_code(platform.machine())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"processor: {to_code(platform.processor())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"release: {to_code(platform.release())}", level=1)
|
||||
)
|
||||
cache_stream.write(
|
||||
markdown_line_handler(f"version: {to_code(platform.version())}", level=1)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.chdir('../../')
|
||||
if __name__ == "__main__":
|
||||
os.chdir("../../")
|
||||
try:
|
||||
raise FileNotFoundError('abc')
|
||||
raise FileNotFoundError("abc")
|
||||
except FileNotFoundError:
|
||||
create_crash_report()
|
||||
|
@ -19,7 +19,7 @@ __all__ = [
|
||||
"CommandQMarkPosError",
|
||||
"CommandQMarkConflict",
|
||||
"CommandQMarkSufMissing",
|
||||
"CommandQMarkPreMissing"
|
||||
"CommandQMarkPreMissing",
|
||||
]
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ class CommandParseError(CommandError):
|
||||
# QMark -> Quotation marks
|
||||
# Pos -> Position
|
||||
|
||||
|
||||
class CommandQMarkPosError(CommandParseError):
|
||||
"""命令中,引号位置不正确
|
||||
例如: /command "aabcc "awdawd"""
|
||||
@ -41,12 +42,13 @@ class CommandQMarkPosError(CommandParseError):
|
||||
|
||||
class CommandQMarkMissing(CommandParseError):
|
||||
"""命令中引号缺失
|
||||
例如: /command "aawwdawda awdaw """
|
||||
例如: /command "aawwdawda awdaw"""
|
||||
|
||||
|
||||
class CommandQMarkConflict(CommandParseError):
|
||||
"""命令中引号位置冲突
|
||||
例如: /command "aaaa "aaaa aaaa"""
|
||||
|
||||
first_qmark_pos = None
|
||||
conflict_qmark_pos = None
|
||||
|
||||
@ -54,10 +56,12 @@ class CommandQMarkConflict(CommandParseError):
|
||||
class CommandQMarkPreMissing(CommandQMarkMissing):
|
||||
"""命令中 前面的引号缺失
|
||||
例如: /command aaaa" aaaaaa"""
|
||||
|
||||
suf_qmark_pos = None
|
||||
|
||||
|
||||
class CommandQMarkSufMissing(CommandQMarkMissing):
|
||||
"""命令中 后面的引号缺失(引号未闭合)
|
||||
例如: /command "aaaawaa some command"""
|
||||
|
||||
pre_qmark_pos = None
|
||||
|
@ -6,10 +6,12 @@
|
||||
|
||||
from Difficult_Rocket.exception import BaseError
|
||||
|
||||
__all__ = ['LanguageNotFound',
|
||||
'TranslateError',
|
||||
'TranslateKeyNotFound',
|
||||
'TranslateFileError']
|
||||
__all__ = [
|
||||
"LanguageNotFound",
|
||||
"TranslateError",
|
||||
"TranslateKeyNotFound",
|
||||
"TranslateFileError",
|
||||
]
|
||||
|
||||
|
||||
class LanguageNotFound(BaseError):
|
||||
@ -22,6 +24,7 @@ class TranslateError(BaseError):
|
||||
|
||||
class TranslateKeyNotFound(TranslateError):
|
||||
"""语言文件某项缺失"""
|
||||
|
||||
def __init__(self, value: dict = None, item_names: list = None):
|
||||
self.item_names: list = item_names
|
||||
self.value: dict = value
|
||||
@ -32,6 +35,3 @@ class TranslateKeyNotFound(TranslateError):
|
||||
|
||||
class TranslateFileError(TranslateError):
|
||||
"""翻译文件错误"""
|
||||
|
||||
|
||||
|
||||
|
@ -13,12 +13,12 @@ gitee: @shenjackyuanjie
|
||||
from Difficult_Rocket.exception import BaseError, BaseRuntimeError
|
||||
|
||||
__all__ = [
|
||||
'NoMoreJson5',
|
||||
'Nope418ImATeapot',
|
||||
'ThinkError',
|
||||
'BrainError',
|
||||
'BigBrainError',
|
||||
'GrammarError'
|
||||
"NoMoreJson5",
|
||||
"Nope418ImATeapot",
|
||||
"ThinkError",
|
||||
"BrainError",
|
||||
"BigBrainError",
|
||||
"GrammarError",
|
||||
]
|
||||
|
||||
|
||||
|
@ -11,8 +11,10 @@ import pyglet
|
||||
from pyglet.text import Label
|
||||
from pyglet.gui import widgets
|
||||
from pyglet.window import mouse
|
||||
|
||||
# from pyglet.sprite import Sprite
|
||||
from pyglet.shapes import Rectangle
|
||||
|
||||
# from pyglet.image import AbstractImage
|
||||
from pyglet.graphics import Batch, Group
|
||||
|
||||
@ -28,11 +30,10 @@ class ButtonDrawTheme:
|
||||
"""
|
||||
直接绘制按钮的风格
|
||||
"""
|
||||
name = 'ButtonDrawTheme'
|
||||
|
||||
def __init__(self,
|
||||
batch: Batch,
|
||||
group: Group):
|
||||
name = "ButtonDrawTheme"
|
||||
|
||||
def __init__(self, batch: Batch, group: Group):
|
||||
self.batch = batch
|
||||
self.group = group
|
||||
a = (72, 73, 74)
|
||||
@ -74,10 +75,10 @@ class ButtonDrawTheme:
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class ButtonThemeOptions(Options):
|
||||
""" 基于 Options 写的 ButtonTheme """
|
||||
name = 'ButtonTheme'
|
||||
"""基于 Options 写的 ButtonTheme"""
|
||||
|
||||
name = "ButtonTheme"
|
||||
untouched_color: RGBA = (39, 73, 114, 255)
|
||||
touched_color: RGBA = (66, 150, 250, 255)
|
||||
hit_color: RGBA = (15, 135, 250, 255)
|
||||
@ -92,16 +93,17 @@ class PressTextButton(widgets.WidgetBase):
|
||||
自带 字符 + 材质 的按钮,就不用单独做材质了
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
x: int,
|
||||
y: int,
|
||||
width: int,
|
||||
height: int,
|
||||
text: str,
|
||||
batch: Optional[Batch] = None,
|
||||
group: Optional[Group] = None,
|
||||
theme: Optional[ButtonThemeOptions] = None,
|
||||
):
|
||||
def __init__(
|
||||
self,
|
||||
x: int,
|
||||
y: int,
|
||||
width: int,
|
||||
height: int,
|
||||
text: str,
|
||||
batch: Optional[Batch] = None,
|
||||
group: Optional[Group] = None,
|
||||
theme: Optional[ButtonThemeOptions] = None,
|
||||
):
|
||||
super().__init__(x, y, width, height)
|
||||
self.main_batch = batch or Batch()
|
||||
self.user_batch = batch is not None
|
||||
@ -117,20 +119,33 @@ class PressTextButton(widgets.WidgetBase):
|
||||
# from ImGui
|
||||
|
||||
self.text = text
|
||||
self.text_label = Label(font_name=self.theme.font_theme.font_name, font_size=self.theme.font_theme.font_size,
|
||||
batch=self.main_batch, group=self.front_group,
|
||||
x=self._x, y=self._y, width=self._width,
|
||||
height=self._height,)
|
||||
self.font = pyglet.font.load(self.theme.font_theme.font_name,
|
||||
self.theme.font_theme.font_size,
|
||||
bold=self.theme.font_theme.bold,
|
||||
italic=self.theme.font_theme.italic,
|
||||
stretch=self.theme.font_theme.stretch)
|
||||
self.text_label = Label(
|
||||
font_name=self.theme.font_theme.font_name,
|
||||
font_size=self.theme.font_theme.font_size,
|
||||
batch=self.main_batch,
|
||||
group=self.front_group,
|
||||
x=self._x,
|
||||
y=self._y,
|
||||
width=self._width,
|
||||
height=self._height,
|
||||
)
|
||||
self.font = pyglet.font.load(
|
||||
self.theme.font_theme.font_name,
|
||||
self.theme.font_theme.font_size,
|
||||
bold=self.theme.font_theme.bold,
|
||||
italic=self.theme.font_theme.italic,
|
||||
stretch=self.theme.font_theme.stretch,
|
||||
)
|
||||
self.font_height = self.font.ascent - self.font.descent
|
||||
self.back_rec = Rectangle(x=self._x, y=self._y,
|
||||
width=self._width, height=self._height,
|
||||
color=self.untouched_color, # ImGui color
|
||||
batch=self.main_batch, group=self.back_ground_group)
|
||||
self.back_rec = Rectangle(
|
||||
x=self._x,
|
||||
y=self._y,
|
||||
width=self._width,
|
||||
height=self._height,
|
||||
color=self.untouched_color, # ImGui color
|
||||
batch=self.main_batch,
|
||||
group=self.back_ground_group,
|
||||
)
|
||||
|
||||
self.value = text # 重新分配一下高度和宽度的位置
|
||||
|
||||
@ -144,7 +159,9 @@ class PressTextButton(widgets.WidgetBase):
|
||||
self.text_label.text = value
|
||||
text_width = self.text_label.content_width
|
||||
self.text_label.x = self._x + (self.width - text_width) // 2
|
||||
self.text_label.y = self._y + (self.height - self.font_height) // 2 + (self.font_height * 0.2) # 修正一下位置
|
||||
self.text_label.y = (
|
||||
self._y + (self.height - self.font_height) // 2 + (self.font_height * 0.2)
|
||||
) # 修正一下位置
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.back_rec
|
||||
@ -163,7 +180,7 @@ class PressTextButton(widgets.WidgetBase):
|
||||
def on_mouse_press(self, x, y, buttons, modifiers) -> bool:
|
||||
if (x, y) in self and buttons == mouse.LEFT:
|
||||
self.back_rec.color = self.hit_color
|
||||
self.dispatch_event('on_press', x, y)
|
||||
self.dispatch_event("on_press", x, y)
|
||||
self.pressed = True
|
||||
return True
|
||||
return False
|
||||
@ -180,4 +197,4 @@ class PressTextButton(widgets.WidgetBase):
|
||||
self.back_rec.height = self._height
|
||||
|
||||
|
||||
PressTextButton.register_event_type('on_press')
|
||||
PressTextButton.register_event_type("on_press")
|
||||
|
@ -13,7 +13,8 @@ class BaseTheme(dict):
|
||||
"""
|
||||
Base class of themes
|
||||
"""
|
||||
theme_name = 'BaseTheme'
|
||||
|
||||
theme_name = "BaseTheme"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@ -22,10 +23,8 @@ class BaseTheme(dict):
|
||||
setattr(self, k, v)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
def init(self,
|
||||
batch: Batch,
|
||||
group: Group,
|
||||
**kwargs) -> None:
|
||||
|
||||
def init(self, batch: Batch, group: Group, **kwargs) -> None:
|
||||
"""
|
||||
Init theme
|
||||
:param batch: batch
|
||||
@ -39,12 +38,12 @@ class FontTheme(BaseTheme):
|
||||
"""
|
||||
Base class of font themes
|
||||
"""
|
||||
theme_name = 'FontTheme'
|
||||
font_name: Optional[str] = 'Times New Roman'
|
||||
|
||||
theme_name = "FontTheme"
|
||||
font_name: Optional[str] = "Times New Roman"
|
||||
font_size: Optional[int] = 12
|
||||
bold: Optional[bool] = False
|
||||
italic: Optional[bool] = False
|
||||
stretch: Optional[bool] = False
|
||||
color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255)
|
||||
align: Optional[str] = 'center'
|
||||
|
||||
align: Optional[str] = "center"
|
||||
|
@ -20,7 +20,8 @@ class ButtonBaseTheme(BaseTheme):
|
||||
按钮的基础主题
|
||||
继承了 BaseTheme 和 dict
|
||||
"""
|
||||
theme_name = 'Button Base Theme'
|
||||
|
||||
theme_name = "Button Base Theme"
|
||||
|
||||
def init(self, batch: Batch, group: Group, **kwargs) -> None:
|
||||
"""
|
||||
@ -39,10 +40,10 @@ class BlockTheme(ButtonBaseTheme):
|
||||
"""
|
||||
button theme: Block like button
|
||||
"""
|
||||
theme_name = 'Block Theme(button)'
|
||||
|
||||
theme_name = "Block Theme(button)"
|
||||
main_color: _RGBA = (39, 73, 114, 255)
|
||||
touch_color: _RGBA = (66, 150, 250, 255)
|
||||
hit_color: _RGBA = (15, 135, 250, 255)
|
||||
|
||||
font_theme: FontTheme = FontTheme()
|
||||
|
||||
|
@ -13,6 +13,7 @@ gitee: @shenjackyuanjie
|
||||
|
||||
# import time
|
||||
import logging
|
||||
|
||||
# import traceback
|
||||
import logging.config
|
||||
import multiprocessing
|
||||
@ -23,29 +24,31 @@ from typing import List, Optional, Dict
|
||||
|
||||
# from Difficult_Rocket.utils import tools
|
||||
from Difficult_Rocket.api.types import Options
|
||||
|
||||
# from Difficult_Rocket.utils.translate import tr
|
||||
# from Difficult_Rocket.runtime import DR_runtime
|
||||
from Difficult_Rocket.mod.loader import ModManager
|
||||
from Difficult_Rocket.utils.thread import new_thread
|
||||
|
||||
# from Difficult_Rocket.crash import write_info_to_cache
|
||||
from Difficult_Rocket import client, server, DR_status
|
||||
|
||||
|
||||
class Console(Options):
|
||||
name = 'python stdin console'
|
||||
name = "python stdin console"
|
||||
|
||||
running: bool = False
|
||||
caches: List[str] = []
|
||||
|
||||
@new_thread('python console', daemon=True, log_thread=True)
|
||||
@new_thread("python console", daemon=True, log_thread=True)
|
||||
def main(self):
|
||||
while self.running:
|
||||
try:
|
||||
get_str = input('>>>')
|
||||
get_str = input(">>>")
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
get_str = 'stop'
|
||||
get_str = "stop"
|
||||
self.caches.append(get_str)
|
||||
if get_str == 'stop':
|
||||
if get_str == "stop":
|
||||
self.running = False
|
||||
break
|
||||
|
||||
@ -64,7 +67,7 @@ class Console(Options):
|
||||
|
||||
|
||||
class Game(Options):
|
||||
name = 'MainGame'
|
||||
name = "MainGame"
|
||||
|
||||
client: client.Client
|
||||
server: server.Server
|
||||
@ -82,11 +85,12 @@ class Game(Options):
|
||||
def init_mods(self) -> None:
|
||||
"""验证/加载 mod"""
|
||||
from Difficult_Rocket.mod import loader as mod_loader
|
||||
mod_loader.logger = logging.getLogger('mod_manager')
|
||||
|
||||
mod_loader.logger = logging.getLogger("mod_manager")
|
||||
self.mod_manager = ModManager()
|
||||
mod_class = self.mod_manager.load_mods()
|
||||
self.mod_manager.init_mods(mod_class)
|
||||
self.dispatch_mod_event('on_load', game=self)
|
||||
self.dispatch_mod_event("on_load", game=self)
|
||||
|
||||
def init_console(self) -> None:
|
||||
self.console = self.console_class()
|
||||
@ -96,7 +100,9 @@ class Game(Options):
|
||||
self.server.run()
|
||||
if DR_status.use_multiprocess:
|
||||
try:
|
||||
game_process = multiprocessing.Process(target=self.client.start, name='pyglet app')
|
||||
game_process = multiprocessing.Process(
|
||||
target=self.client.start, name="pyglet app"
|
||||
)
|
||||
game_process.start()
|
||||
game_process.join()
|
||||
except Exception:
|
||||
@ -107,14 +113,14 @@ class Game(Options):
|
||||
self.client.start()
|
||||
|
||||
def log_env(self) -> None:
|
||||
self.logger.info(f'\n{self.as_markdown()}')
|
||||
self.logger.info(f"\n{self.as_markdown()}")
|
||||
|
||||
def setup(self) -> None:
|
||||
self.client = client.Client(game=self, net_mode='local')
|
||||
self.server = server.Server(net_mode='local')
|
||||
self.client = client.Client(game=self, net_mode="local")
|
||||
self.server = server.Server(net_mode="local")
|
||||
|
||||
def init(self, **kwargs) -> bool:
|
||||
self.logger = logging.getLogger('main')
|
||||
self.logger = logging.getLogger("main")
|
||||
self.load_file()
|
||||
self.setup()
|
||||
self.log_env()
|
||||
|
@ -35,6 +35,7 @@ class ModInfo(Options):
|
||||
"""
|
||||
加载mod时候的参数
|
||||
"""
|
||||
|
||||
"""基本信息"""
|
||||
mod_id: str # mod id
|
||||
name: str # mod 名称
|
||||
@ -47,9 +48,17 @@ class ModInfo(Options):
|
||||
info: str = "" # 其他信息 (可以很多很多)
|
||||
|
||||
"""版本相关信息"""
|
||||
DR_version: RequireVersion = (DR_status.DR_version, DR_status.DR_version) # DR SDK 兼容版本
|
||||
DR_Api_version: RequireVersion = (DR_status.API_version, DR_status.API_version) # DR Api版本
|
||||
Mod_Require_version: List[Tuple[str, ForceRequire, RequireVersion]] = [] # mod 依赖版本
|
||||
DR_version: RequireVersion = (
|
||||
DR_status.DR_version,
|
||||
DR_status.DR_version,
|
||||
) # DR SDK 兼容版本
|
||||
DR_Api_version: RequireVersion = (
|
||||
DR_status.API_version,
|
||||
DR_status.API_version,
|
||||
) # DR Api版本
|
||||
Mod_Require_version: List[
|
||||
Tuple[str, ForceRequire, RequireVersion]
|
||||
] = [] # mod 依赖版本
|
||||
|
||||
"""mod 状态"""
|
||||
is_enable: bool = True # 是否启用
|
||||
@ -61,34 +70,37 @@ class ModInfo(Options):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if not self.DR_version[0] <= DR_status.DR_version <= self.DR_version[1]:
|
||||
warnings.warn(f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.DR_version}\n"
|
||||
f"DR {self.DR_version} is required")
|
||||
warnings.warn(
|
||||
f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.DR_version}\n"
|
||||
f"DR {self.DR_version} is required"
|
||||
)
|
||||
if not self.DR_Api_version[0] <= DR_status.API_version <= self.DR_Api_version[1]:
|
||||
warnings.warn(f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.API_version}\n"
|
||||
f"DR {self.DR_Api_version} is required")
|
||||
warnings.warn(
|
||||
f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.API_version}\n"
|
||||
f"DR {self.DR_Api_version} is required"
|
||||
)
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def on_load(self, game: Game, old_self: Optional["ModInfo"] = None) -> bool:
|
||||
""" 加载时调用 """
|
||||
"""加载时调用"""
|
||||
return True
|
||||
|
||||
def on_client_start(self, game: Game, client: ClientWindow):
|
||||
""" 客户端启动时调用 """
|
||||
print(f'Mod {self.mod_id} client start')
|
||||
"""客户端启动时调用"""
|
||||
print(f"Mod {self.mod_id} client start")
|
||||
|
||||
def on_client_stop(self, game: Game, client: ClientWindow, source: str = 'window'):
|
||||
""" 客户端停止时调用 """
|
||||
print(f'Mod {self.mod_id} client stop')
|
||||
def on_client_stop(self, game: Game, client: ClientWindow, source: str = "window"):
|
||||
"""客户端停止时调用"""
|
||||
print(f"Mod {self.mod_id} client stop")
|
||||
|
||||
def on_server_start(self, game: Game):
|
||||
""" 服务器启动时调用 """
|
||||
print(f'Mod {self.mod_id} server start')
|
||||
"""服务器启动时调用"""
|
||||
print(f"Mod {self.mod_id} server start")
|
||||
|
||||
def on_server_stop(self, game: Game):
|
||||
""" 服务器停止时调用 """
|
||||
print(f'Mod {self.mod_id} server stop')
|
||||
"""服务器停止时调用"""
|
||||
print(f"Mod {self.mod_id} server stop")
|
||||
|
||||
def on_unload(self, game: Game):
|
||||
""" 卸载时调用 """
|
||||
print(f'Mod {self.mod_id} unloaded')
|
||||
|
||||
"""卸载时调用"""
|
||||
print(f"Mod {self.mod_id} unloaded")
|
||||
|
@ -16,11 +16,11 @@ from Difficult_Rocket.mod.api import ModInfo
|
||||
from Difficult_Rocket.utils.translate import tr
|
||||
from Difficult_Rocket.api.types import Options
|
||||
|
||||
Game = TypeVar('Game')
|
||||
Game = TypeVar("Game")
|
||||
|
||||
logger = logging.getLogger('mod_manager')
|
||||
ONE_FILE_SUFFIX = ('.py', '.pyc', '.pyd')
|
||||
PACKAGE_SUFFIX = ('.pyz', '.zip', '.dr_mod')
|
||||
logger = logging.getLogger("mod_manager")
|
||||
ONE_FILE_SUFFIX = (".py", ".pyc", ".pyd")
|
||||
PACKAGE_SUFFIX = (".pyz", ".zip", ".dr_mod")
|
||||
|
||||
|
||||
def _add_path_to_sys(paths: List[Path]):
|
||||
@ -30,9 +30,9 @@ def _add_path_to_sys(paths: List[Path]):
|
||||
|
||||
|
||||
class ModManager(Options):
|
||||
name = 'Mod Manager'
|
||||
name = "Mod Manager"
|
||||
|
||||
mods_path: List[Path] = [Path('./mods')]
|
||||
mods_path: List[Path] = [Path("./mods")]
|
||||
find_mod_paths: Dict[str, Path] = {}
|
||||
loaded_mod_modules: Dict[str, ModInfo] = {}
|
||||
|
||||
@ -60,7 +60,11 @@ class ModManager(Options):
|
||||
try:
|
||||
getattr(mod, event_name)(*args, **kwargs)
|
||||
except Exception as e:
|
||||
logger.error(tr().mod.event.error().format(mod, event_name, e, traceback.format_exc()))
|
||||
logger.error(
|
||||
tr()
|
||||
.mod.event.error()
|
||||
.format(mod, event_name, e, traceback.format_exc())
|
||||
)
|
||||
|
||||
def load_mod(self, mod_path: Path) -> Optional[type(ModInfo)]:
|
||||
"""
|
||||
@ -73,14 +77,20 @@ class ModManager(Options):
|
||||
return None
|
||||
_add_path_to_sys([mod_path.parent])
|
||||
try:
|
||||
if mod_path.name == '__pycache__':
|
||||
if mod_path.name == "__pycache__":
|
||||
# 忽略 __pycache__ 文件夹 (Python 编译文件)
|
||||
return None
|
||||
logger.info(tr().mod.load.loading().format(mod_path))
|
||||
if mod_path.is_dir() or mod_path.suffix in PACKAGE_SUFFIX or mod_path.suffix in ONE_FILE_SUFFIX:
|
||||
if (
|
||||
mod_path.is_dir()
|
||||
or mod_path.suffix in PACKAGE_SUFFIX
|
||||
or mod_path.suffix in ONE_FILE_SUFFIX
|
||||
):
|
||||
# 文件夹 mod
|
||||
loading_mod = importlib.import_module(mod_path.name)
|
||||
if not hasattr(loading_mod, 'mod_class') or not issubclass(loading_mod.mod_class, ModInfo):
|
||||
if not hasattr(loading_mod, "mod_class") or not issubclass(
|
||||
loading_mod.mod_class, ModInfo
|
||||
):
|
||||
logger.warning(tr().mod.load.faild.no_mod_class().format(mod_path))
|
||||
return None
|
||||
mod_class: type(ModInfo) = loading_mod.mod_class # 获取 mod 类
|
||||
@ -88,15 +98,21 @@ class ModManager(Options):
|
||||
self.find_mod_paths[mod_class.mod_id] = mod_path
|
||||
return mod_class
|
||||
except ImportError:
|
||||
logger.warning(tr().mod.load.faild.error().format(mod_path, traceback.format_exc()))
|
||||
logger.warning(
|
||||
tr().mod.load.faild.error().format(mod_path, traceback.format_exc())
|
||||
)
|
||||
return None
|
||||
|
||||
def find_mods_in_path(self, extra_mods_path: Optional[List[Path]] = None) -> List[Path]:
|
||||
def find_mods_in_path(
|
||||
self, extra_mods_path: Optional[List[Path]] = None
|
||||
) -> List[Path]:
|
||||
"""
|
||||
查找所有 mod 路径
|
||||
:return: 找到的 mod 的路径 (未校验)
|
||||
"""
|
||||
find_path = self.mods_path + (extra_mods_path if extra_mods_path is not None else [])
|
||||
find_path = self.mods_path + (
|
||||
extra_mods_path if extra_mods_path is not None else []
|
||||
)
|
||||
mods_path = []
|
||||
start_time = time.time()
|
||||
for path in find_path:
|
||||
@ -104,18 +120,24 @@ class ModManager(Options):
|
||||
path.mkdir(parents=True)
|
||||
continue
|
||||
for mod in path.iterdir():
|
||||
if mod.name == '__pycache__':
|
||||
if mod.name == "__pycache__":
|
||||
# 忽略 __pycache__ 文件夹 (Python 编译文件)
|
||||
continue
|
||||
if mod.is_dir() or mod.suffix in PACKAGE_SUFFIX or mod.suffix in ONE_FILE_SUFFIX:
|
||||
if (
|
||||
mod.is_dir()
|
||||
or mod.suffix in PACKAGE_SUFFIX
|
||||
or mod.suffix in ONE_FILE_SUFFIX
|
||||
):
|
||||
# 文件夹 mod
|
||||
mods_path.append(mod)
|
||||
logger.info(tr().mod.finded().format(len(mods_path), time.time() - start_time))
|
||||
return mods_path
|
||||
|
||||
def load_mods(self,
|
||||
extra_path: Optional[List[Path]] = None,
|
||||
extra_mod_path: Optional[List[Path]] = None) -> List[type(ModInfo)]:
|
||||
def load_mods(
|
||||
self,
|
||||
extra_path: Optional[List[Path]] = None,
|
||||
extra_mod_path: Optional[List[Path]] = None,
|
||||
) -> List[type(ModInfo)]:
|
||||
"""
|
||||
加载所有 mod (可提供额外的 mod 路径)
|
||||
:param extra_path: 额外的 mod 路径
|
||||
@ -154,7 +176,9 @@ class ModManager(Options):
|
||||
self.loaded_mod_modules[init_mod.mod_id] = init_mod
|
||||
logger.info(tr().mod.init.success().format(init_mod, init_mod.version))
|
||||
except Exception as e:
|
||||
logger.error(tr().mod.init.faild().format(mod_class, e, traceback.format_exc()))
|
||||
logger.error(
|
||||
tr().mod.init.faild().format(mod_class, e, traceback.format_exc())
|
||||
)
|
||||
continue
|
||||
logger.info(tr().mod.init.use_time().format(time.time() - start_time))
|
||||
|
||||
@ -165,7 +189,10 @@ class ModManager(Options):
|
||||
:param game: 游戏实例
|
||||
:return: 卸载的 mod 的 ModInfo 类
|
||||
"""
|
||||
if not (mod_class := self.loaded_mod_modules.get(mod_id)) and (mod_class := self.get_mod_module(mod_id)) is None:
|
||||
if (
|
||||
not (mod_class := self.loaded_mod_modules.get(mod_id))
|
||||
and (mod_class := self.get_mod_module(mod_id)) is None
|
||||
):
|
||||
logger.warning(tr().mod.unload.faild.not_find().format(mod_id))
|
||||
return None
|
||||
try:
|
||||
@ -174,7 +201,9 @@ class ModManager(Options):
|
||||
logger.info(tr().mod.unload.success().format(mod_id))
|
||||
return mod_class
|
||||
except Exception as e:
|
||||
logger.error(tr().mod.unload.faild.error().format(mod_id, e, traceback.format_exc()))
|
||||
logger.error(
|
||||
tr().mod.unload.faild.error().format(mod_id, e, traceback.format_exc())
|
||||
)
|
||||
return None
|
||||
|
||||
def reload_mod(self, mod_id: str, game: Game):
|
||||
@ -203,4 +232,3 @@ class ModManager(Options):
|
||||
if mod_id in self.loaded_mod_modules and mod_class is not None:
|
||||
self.loaded_mod_modules[mod_id].on_load(game=game, old_self=mod_class)
|
||||
logger.info(tr().mod.reload.success().format(mod_id))
|
||||
|
||||
|
@ -15,19 +15,18 @@ from typing import Optional, List, Tuple
|
||||
from Difficult_Rocket.api.types import Options, Version
|
||||
|
||||
|
||||
__all__ = [
|
||||
'DR_runtime'
|
||||
]
|
||||
__all__ = ["DR_runtime"]
|
||||
|
||||
|
||||
class _DR_runtime(Options):
|
||||
"""
|
||||
DR 的运行时配置 / 状态
|
||||
"""
|
||||
name = 'DR Runtime'
|
||||
|
||||
language: str = 'zh-CN'
|
||||
mod_path: str = './mods'
|
||||
name = "DR Runtime"
|
||||
|
||||
language: str = "zh-CN"
|
||||
mod_path: str = "./mods"
|
||||
DR_Mod_List: List[Tuple[str, Version]] = [] # DR Mod 列表 (name, version)
|
||||
|
||||
# run status
|
||||
@ -37,11 +36,12 @@ class _DR_runtime(Options):
|
||||
|
||||
def load_file(self) -> bool:
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
with open('./config/main.toml', 'r', encoding='utf-8') as f:
|
||||
with open("./config/main.toml", "r", encoding="utf-8") as f:
|
||||
import rtoml
|
||||
|
||||
config_file = rtoml.load(f)
|
||||
self.language = config_file['runtime']['language']
|
||||
self.mod_path = config_file['game']['mods']['path']
|
||||
self.language = config_file["runtime"]["language"]
|
||||
self.mod_path = config_file["game"]["mods"]["path"]
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -55,23 +55,25 @@ class _DR_runtime(Options):
|
||||
sys.path.append(self.mod_path)
|
||||
for mod_path in paths:
|
||||
try:
|
||||
if mod_path.is_dir() and mod_path.name != '__pycache__': # 处理文件夹 mod
|
||||
if mod_path.is_dir() and mod_path.name != "__pycache__": # 处理文件夹 mod
|
||||
if importlib.util.find_spec(mod_path.name) is not None:
|
||||
mods.append(mod_path.name)
|
||||
else:
|
||||
print(f'can not import mod {mod_path} because importlib can not find spec')
|
||||
elif mod_path.suffix in ('.pyz', '.zip'): # 处理压缩包 mod
|
||||
print(
|
||||
f"can not import mod {mod_path} because importlib can not find spec"
|
||||
)
|
||||
elif mod_path.suffix in (".pyz", ".zip"): # 处理压缩包 mod
|
||||
if importlib.util.find_spec(mod_path.name) is not None:
|
||||
mods.append(mod_path.name)
|
||||
elif mod_path.suffix == '.pyd': # pyd 扩展 mod
|
||||
elif mod_path.suffix == ".pyd": # pyd 扩展 mod
|
||||
if importlib.util.find_spec(mod_path.name) is not None:
|
||||
mods.append(mod_path.name)
|
||||
elif mod_path.suffix == '.py': # 处理单文件 mod
|
||||
print(f'importing mod {mod_path=} {mod_path.stem}')
|
||||
elif mod_path.suffix == ".py": # 处理单文件 mod
|
||||
print(f"importing mod {mod_path=} {mod_path.stem}")
|
||||
if importlib.util.find_spec(mod_path.stem) is not None:
|
||||
mods.append(mod_path.stem)
|
||||
except ImportError:
|
||||
print(f'ImportError when loading mod {mod_path}')
|
||||
print(f"ImportError when loading mod {mod_path}")
|
||||
traceback.print_exc()
|
||||
return mods
|
||||
|
||||
|
@ -26,17 +26,17 @@ from Difficult_Rocket.utils.translate import tr
|
||||
|
||||
|
||||
class Server:
|
||||
def __init__(self, net_mode='local'):
|
||||
def __init__(self, net_mode="local"):
|
||||
start_time = time.time()
|
||||
# logging
|
||||
self.logger = logging.getLogger('server')
|
||||
self.logger = logging.getLogger("server")
|
||||
self.logger.info(tr().server.setup.start())
|
||||
# value
|
||||
self.process_id = os.getpid()
|
||||
# os.set
|
||||
self.process_name = 'server process'
|
||||
self.process_name = "server process"
|
||||
# config
|
||||
self.config = tools.load_file('config/main.toml')
|
||||
self.config = tools.load_file("config/main.toml")
|
||||
# self.dev = Dev
|
||||
# self.net_mode = net_mode
|
||||
self.logger.info(tr().server.setup.use_time().format(time.time() - start_time))
|
||||
@ -45,4 +45,4 @@ class Server:
|
||||
self.logger.info(tr().server.os.pid_is().format(os.getpid(), os.getppid()))
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Server {self.process_name} {self.process_id}>'
|
||||
return f"<Server {self.process_name} {self.process_id}>"
|
||||
|
@ -4,9 +4,4 @@
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
__all__ = [
|
||||
'camera',
|
||||
'thread',
|
||||
'tools',
|
||||
'translate'
|
||||
]
|
||||
__all__ = ["camera", "thread", "tools", "translate"]
|
||||
|
@ -14,27 +14,29 @@ from pyglet.graphics import Group
|
||||
|
||||
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:
|
||||
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
|
||||
@ -89,13 +91,13 @@ class Camera:
|
||||
class CenterCamera(Camera):
|
||||
"""
|
||||
A camera that centers the view in the center of the window
|
||||
|
||||
|
||||
>>> from pyglet.window import Window
|
||||
>>> window = Window()
|
||||
|
||||
|
||||
>>> camera = CenterCamera(window)
|
||||
>>> @window.event
|
||||
|
||||
|
||||
>>> def on_draw():
|
||||
>>> camera.begin()
|
||||
>>> window.clear()
|
||||
@ -123,15 +125,17 @@ class GroupCamera(Group):
|
||||
can be used by just added to your widget
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
window,
|
||||
order: int = 0,
|
||||
parent: Optional[Group] = None,
|
||||
view_x: Optional[int] = 0,
|
||||
view_y: Optional[int] = 0,
|
||||
zoom: Optional[float] = 1.0,
|
||||
min_zoom: Optional[float] = 1.0,
|
||||
max_zoom: Optional[float] = 1.0):
|
||||
def __init__(
|
||||
self,
|
||||
window,
|
||||
order: int = 0,
|
||||
parent: Optional[Group] = None,
|
||||
view_x: Optional[int] = 0,
|
||||
view_y: Optional[int] = 0,
|
||||
zoom: Optional[float] = 1.0,
|
||||
min_zoom: Optional[float] = 1.0,
|
||||
max_zoom: Optional[float] = 1.0,
|
||||
):
|
||||
super().__init__(order=order, parent=parent)
|
||||
self._window = window
|
||||
self._previous_view = None
|
||||
@ -214,17 +218,19 @@ class CenterGroupFrame(Group):
|
||||
can be used by just added to your widget
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
window,
|
||||
order: int = 0,
|
||||
parent: Optional[Group] = None,
|
||||
dx: Optional[int] = 0,
|
||||
dy: Optional[int] = 0,
|
||||
width: Optional[int] = 0,
|
||||
height: Optional[int] = 0,
|
||||
zoom: Optional[float] = 1.0,
|
||||
min_zoom: Optional[float] = 1.0,
|
||||
max_zoom: Optional[float] = 1.0):
|
||||
def __init__(
|
||||
self,
|
||||
window,
|
||||
order: int = 0,
|
||||
parent: Optional[Group] = None,
|
||||
dx: Optional[int] = 0,
|
||||
dy: Optional[int] = 0,
|
||||
width: Optional[int] = 0,
|
||||
height: Optional[int] = 0,
|
||||
zoom: Optional[float] = 1.0,
|
||||
min_zoom: Optional[float] = 1.0,
|
||||
max_zoom: Optional[float] = 1.0,
|
||||
):
|
||||
super().__init__(order=order, parent=parent)
|
||||
self.window = window
|
||||
self.dx = dx
|
||||
@ -247,7 +253,9 @@ class CenterGroupFrame(Group):
|
||||
self._previous_view = self.window.view
|
||||
|
||||
gl.glScissor(int(self.dx), int(self.dy), int(self._width), int(self._height))
|
||||
gl.glViewport(int(self.dx), int(self.dy), int(self.window.width), int(self.window.height))
|
||||
gl.glViewport(
|
||||
int(self.dx), int(self.dy), int(self.window.width), int(self.window.height)
|
||||
)
|
||||
gl.glEnable(gl.GL_SCISSOR_TEST)
|
||||
|
||||
x = (self.window.width / 2) / self._zoom + (self.dx / self._zoom)
|
||||
|
@ -20,19 +20,18 @@ from typing import Optional, Callable, Union, List
|
||||
from Difficult_Rocket.exception.threading import LockTimeOutError
|
||||
|
||||
__all__ = [
|
||||
'new_thread',
|
||||
'FunctionThread',
|
||||
'ThreadLock',
|
||||
'record_thread',
|
||||
'record_destination',
|
||||
"new_thread",
|
||||
"FunctionThread",
|
||||
"ThreadLock",
|
||||
"record_thread",
|
||||
"record_destination",
|
||||
]
|
||||
|
||||
record_thread = False
|
||||
record_destination: List[Callable[['FunctionThread'], None]] = []
|
||||
record_destination: List[Callable[["FunctionThread"], None]] = []
|
||||
|
||||
|
||||
class ThreadLock:
|
||||
|
||||
def __init__(self, the_lock: Lock, time_out: Union[float, int] = 1 / 60) -> None:
|
||||
self.lock = the_lock
|
||||
self.time_out = time_out
|
||||
@ -40,7 +39,7 @@ class ThreadLock:
|
||||
def __enter__(self):
|
||||
self.lock.acquire(timeout=self.time_out)
|
||||
if not self.lock.locked():
|
||||
raise LockTimeOutError(f'Lock time Out with {self.time_out}')
|
||||
raise LockTimeOutError(f"Lock time Out with {self.time_out}")
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
@ -69,10 +68,13 @@ class FunctionThread(threading.Thread):
|
||||
"""
|
||||
A Thread subclass which is used in decorator :func:`new_thread` to wrap a synchronized function call
|
||||
"""
|
||||
|
||||
__NONE = object()
|
||||
|
||||
def __init__(self, target, name, args, kwargs, daemon):
|
||||
super().__init__(target=target, args=args, kwargs=kwargs, name=name, daemon=daemon)
|
||||
super().__init__(
|
||||
target=target, args=args, kwargs=kwargs, name=name, daemon=daemon
|
||||
)
|
||||
self.__return_value = self.__NONE
|
||||
self.__error = None
|
||||
|
||||
@ -112,14 +114,16 @@ class FunctionThread(threading.Thread):
|
||||
self.join(timeout)
|
||||
if self.__return_value is self.__NONE:
|
||||
if self.is_alive():
|
||||
raise RuntimeError('The thread is still running')
|
||||
raise RuntimeError("The thread is still running")
|
||||
raise self.__error
|
||||
return self.__return_value
|
||||
|
||||
|
||||
def new_thread(arg: Optional[Union[str, Callable]] = None,
|
||||
daemon: bool = False,
|
||||
log_thread: bool = True):
|
||||
def new_thread(
|
||||
arg: Optional[Union[str, Callable]] = None,
|
||||
daemon: bool = False,
|
||||
log_thread: bool = True,
|
||||
):
|
||||
"""
|
||||
This is a one line solution to make your function executes in parallels.
|
||||
When decorated with this decorator, functions will be executed in a new daemon thread
|
||||
@ -162,7 +166,9 @@ def new_thread(arg: Optional[Union[str, Callable]] = None,
|
||||
def wrapper(func):
|
||||
@functools.wraps(func) # to preserve the origin function information
|
||||
def wrap(*args, **kwargs):
|
||||
thread = FunctionThread(target=func, args=args, kwargs=kwargs, name=thread_name, daemon=daemon)
|
||||
thread = FunctionThread(
|
||||
target=func, args=args, kwargs=kwargs, name=thread_name, daemon=daemon
|
||||
)
|
||||
if record_thread:
|
||||
for destination in record_destination:
|
||||
destination(thread)
|
||||
@ -192,8 +198,8 @@ if __name__ == "__main__":
|
||||
|
||||
test_lock = ThreadLock(thread_lock)
|
||||
with test_lock:
|
||||
print('do some thing')
|
||||
print("do some thing")
|
||||
...
|
||||
with test_lock:
|
||||
print('do some error')
|
||||
raise TestError('ah lock test')
|
||||
print("do some error")
|
||||
raise TestError("ah lock test")
|
||||
|
@ -28,78 +28,91 @@ from defusedxml.ElementTree import parse
|
||||
from Difficult_Rocket.exception.unsupport import NoMoreJson5
|
||||
|
||||
# logger
|
||||
tools_logger = logging.getLogger('tools')
|
||||
tools_logger = logging.getLogger("tools")
|
||||
"""
|
||||
file config
|
||||
"""
|
||||
|
||||
file_error = {FileNotFoundError: 'no {filetype} file was founded!:\n file name: {filename}\n file_type: {filetype}\n stack: {stack}',
|
||||
KeyError: 'no stack in {filetype} file {filename} was found! \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}'}
|
||||
file_error = {
|
||||
FileNotFoundError: "no {filetype} file was founded!:\n file name: {filename}\n file_type: {filetype}\n stack: {stack}",
|
||||
KeyError: "no stack in {filetype} file {filename} was found! \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: Union[str, Path],
|
||||
stack: Optional[Union[str, list, dict]] = None,
|
||||
raise_error: Optional[bool] = True,
|
||||
encoding: Optional[str] = 'utf-8') -> Union[dict, ElementTree.ElementTree]:
|
||||
def load_file(
|
||||
file_name: Union[str, Path],
|
||||
stack: Optional[Union[str, list, dict]] = None,
|
||||
raise_error: Optional[bool] = True,
|
||||
encoding: Optional[str] = "utf-8",
|
||||
) -> Union[dict, ElementTree.ElementTree]:
|
||||
if isinstance(file_name, Path):
|
||||
file_name = str(file_name)
|
||||
f_type = file_name[file_name.rfind('.') + 1:] # 从最后一个.到末尾 (截取文件格式)
|
||||
get_file = NotImplementedError('解析失败,请检查文件类型/文件内容/文件是否存在!')
|
||||
f_type = file_name[file_name.rfind(".") + 1 :] # 从最后一个.到末尾 (截取文件格式)
|
||||
get_file = NotImplementedError("解析失败,请检查文件类型/文件内容/文件是否存在!")
|
||||
try:
|
||||
if f_type == 'xml':
|
||||
if f_type == "xml":
|
||||
xml_load: ElementTree.ElementTree = parse(file_name)
|
||||
if stack is not None:
|
||||
get_file = xml_load.findall(stack)
|
||||
elif (f_type == 'config') or (f_type == 'conf') or (f_type == 'ini'):
|
||||
elif (f_type == "config") or (f_type == "conf") or (f_type == "ini"):
|
||||
get_file = configparser.ConfigParser()
|
||||
get_file.read(file_name)
|
||||
if stack:
|
||||
get_file = get_file[stack]
|
||||
elif f_type == 'toml':
|
||||
with open(file_name, mode='r', encoding=encoding) as file:
|
||||
elif f_type == "toml":
|
||||
with open(file_name, mode="r", encoding=encoding) as file:
|
||||
get_file = rtoml.load(file)
|
||||
if stack is not None:
|
||||
get_file = get_file[stack]
|
||||
elif f_type == 'json':
|
||||
with open(file_name, mode='r', encoding=encoding) as file:
|
||||
elif f_type == "json":
|
||||
with open(file_name, mode="r", encoding=encoding) as file:
|
||||
get_file = json.load(file)
|
||||
if stack is not None:
|
||||
get_file = get_file[stack]
|
||||
elif f_type == 'json5':
|
||||
elif f_type == "json5":
|
||||
raise NoMoreJson5("我说什么也不用json5了!喵的")
|
||||
except Exception as exp:
|
||||
error_type = type(exp)
|
||||
if error_type in file_error:
|
||||
tools_logger.error(file_error[error_type].format(filetype=f_type, filename=file_name, stack=stack))
|
||||
tools_logger.error(
|
||||
file_error[error_type].format(
|
||||
filetype=f_type, filename=file_name, stack=stack
|
||||
)
|
||||
)
|
||||
else:
|
||||
tools_logger.error(file_error[Exception].format(error_type=error_type, filetype=f_type, filename=file_name, stack=stack))
|
||||
tools_logger.error(
|
||||
file_error[Exception].format(
|
||||
error_type=error_type,
|
||||
filetype=f_type,
|
||||
filename=file_name,
|
||||
stack=stack,
|
||||
)
|
||||
)
|
||||
if raise_error:
|
||||
raise exp from None
|
||||
return get_file
|
||||
|
||||
|
||||
def save_dict_file(file_name: str,
|
||||
data: dict,
|
||||
encoding: str = 'utf-8') -> bool:
|
||||
f_type = file_name[file_name.rfind('.') + 1:] # 从最后一个.到末尾 (截取文件格式)
|
||||
def save_dict_file(file_name: str, data: dict, encoding: str = "utf-8") -> bool:
|
||||
f_type = file_name[file_name.rfind(".") + 1 :] # 从最后一个.到末尾 (截取文件格式)
|
||||
try:
|
||||
if (f_type == 'config') or (f_type == 'conf') or (f_type == 'ini'):
|
||||
if (f_type == "config") or (f_type == "conf") or (f_type == "ini"):
|
||||
return False
|
||||
elif f_type == 'toml':
|
||||
with open(file_name, mode='w', encoding=encoding) as file:
|
||||
elif f_type == "toml":
|
||||
with open(file_name, mode="w", encoding=encoding) as file:
|
||||
rtoml.dump(data, file)
|
||||
elif f_type == 'json':
|
||||
with open(file_name, mode='w', encoding=encoding) as file:
|
||||
elif f_type == "json":
|
||||
with open(file_name, mode="w", encoding=encoding) as file:
|
||||
json.dump(data, file)
|
||||
elif f_type == 'json5':
|
||||
elif f_type == "json5":
|
||||
raise NoMoreJson5("我说什么也不用json5了!喵的")
|
||||
except Exception as exp:
|
||||
raise exp
|
||||
|
||||
|
||||
# main config
|
||||
main_config_file = load_file('./config/main.toml')
|
||||
main_config_file = load_file("./config/main.toml")
|
||||
|
||||
|
||||
def get_At(name, in_xml, need_type=str):
|
||||
@ -124,7 +137,9 @@ def get_At(name, in_xml, need_type=str):
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
raise TypeError('only str and list type is ok but you give me a' + name_type + 'type')
|
||||
raise TypeError(
|
||||
"only str and list type is ok but you give me a" + name_type + "type"
|
||||
)
|
||||
return need_type(attr)
|
||||
|
||||
|
||||
@ -134,11 +149,11 @@ def default_name_handler(name_: str) -> str:
|
||||
just return one
|
||||
"""
|
||||
name = name_
|
||||
name = name.replace('{time.time}', str(time.time()))
|
||||
name = name.replace('{dir}', str(os.getcwd()))
|
||||
name = name.replace('{py_v}', str(sys.version.split(' ')[0]))
|
||||
name = name.replace('{version}', str(main_config_file['runtime']['version']))
|
||||
name = name.replace('{write_v}', str(main_config_file['runtime']['write_py_v']))
|
||||
name = name.replace("{time.time}", str(time.time()))
|
||||
name = name.replace("{dir}", str(os.getcwd()))
|
||||
name = name.replace("{py_v}", str(sys.version.split(" ")[0]))
|
||||
name = name.replace("{version}", str(main_config_file["runtime"]["version"]))
|
||||
name = name.replace("{write_v}", str(main_config_file["runtime"]["write_py_v"]))
|
||||
return name
|
||||
|
||||
|
||||
@ -148,11 +163,13 @@ def name_handler(name: str, formats: dict = None) -> str:
|
||||
name = default_name_handler(name)
|
||||
for need_replace in formats:
|
||||
replace = formats[need_replace]
|
||||
if need_replace == '{date}':
|
||||
if '{date}' in formats:
|
||||
replace = time.strftime(formats['{date}'], time.gmtime(time.time()))
|
||||
if need_replace == "{date}":
|
||||
if "{date}" in formats:
|
||||
replace = time.strftime(formats["{date}"], time.gmtime(time.time()))
|
||||
else:
|
||||
replace = time.strftime(main_config_file['runtime']['date_fmt'], time.gmtime(time.time()))
|
||||
replace = time.strftime(
|
||||
main_config_file["runtime"]["date_fmt"], time.gmtime(time.time())
|
||||
)
|
||||
name = name.replace(need_replace, replace)
|
||||
return name
|
||||
|
||||
@ -161,8 +178,8 @@ def name_handler(name: str, formats: dict = None) -> str:
|
||||
some tools
|
||||
"""
|
||||
|
||||
yes = ['true', '1', 1, 1.0, True]
|
||||
no = ['false', '0', 0, 0.0, False, None]
|
||||
yes = ["true", "1", 1, 1.0, True]
|
||||
no = ["false", "0", 0, 0.0, False, None]
|
||||
|
||||
|
||||
def format_bool(thing) -> bool:
|
||||
@ -184,28 +201,39 @@ def format_bool(thing) -> bool:
|
||||
raise TypeError("Need a 'like bool' not a {}".format(thing))
|
||||
|
||||
|
||||
level_ = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL',
|
||||
logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]
|
||||
level_ = [
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"WARNING",
|
||||
"ERROR",
|
||||
"CRITICAL",
|
||||
logging.DEBUG,
|
||||
logging.INFO,
|
||||
logging.WARNING,
|
||||
logging.ERROR,
|
||||
logging.CRITICAL,
|
||||
]
|
||||
|
||||
|
||||
def log_level(level):
|
||||
if level in level_:
|
||||
if (level == 'DEBUG') or (level == logging.DEBUG):
|
||||
if (level == "DEBUG") or (level == logging.DEBUG):
|
||||
return logging.DEBUG
|
||||
if (level == 'INFO') or (level == logging.INFO):
|
||||
if (level == "INFO") or (level == logging.INFO):
|
||||
return logging.INFO
|
||||
if (level == 'WARNING') or (level == logging.WARNING):
|
||||
if (level == "WARNING") or (level == logging.WARNING):
|
||||
return logging.WARNING
|
||||
if (level == 'ERROR') or (level == logging.ERROR):
|
||||
if (level == "ERROR") or (level == logging.ERROR):
|
||||
return logging.ERROR
|
||||
if (level == 'CRITICAL') or (level == logging.CRITICAL):
|
||||
if (level == "CRITICAL") or (level == logging.CRITICAL):
|
||||
return logging.CRITICAL
|
||||
else:
|
||||
raise ValueError('Need a like logging.level thing not anything else')
|
||||
raise ValueError("Need a like logging.level thing not anything else")
|
||||
|
||||
|
||||
# linear_algebra
|
||||
|
||||
|
||||
def C_R_P(position, degrees): # stand for calculation
|
||||
"""
|
||||
very thanks for lenny from pyglet developer
|
||||
@ -215,5 +243,8 @@ def C_R_P(position, degrees): # stand for calculation
|
||||
radians = degrees * (math.pi / 180)
|
||||
cos = math.cos(radians)
|
||||
sin = math.sin(radians)
|
||||
rotated_pos = (position[0] * cos - position[1] * sin, position[0] * sin + position[1] * cos)
|
||||
rotated_pos = (
|
||||
position[0] * cos - position[1] * sin,
|
||||
position[0] * sin + position[1] * cos,
|
||||
)
|
||||
return rotated_pos
|
||||
|
@ -21,8 +21,7 @@ from typing import Union, Tuple, Any, List, Dict, Hashable, Optional
|
||||
from Difficult_Rocket import DR_status
|
||||
from Difficult_Rocket.utils import tools
|
||||
from Difficult_Rocket.runtime import DR_runtime
|
||||
from Difficult_Rocket.exception.language import (LanguageNotFound,
|
||||
TranslateKeyNotFound)
|
||||
from Difficult_Rocket.exception.language import LanguageNotFound, TranslateKeyNotFound
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -35,22 +34,26 @@ class TranslateConfig:
|
||||
always_copy: bool = False # 是否一直新建 Translate (为 True 会降低性能)
|
||||
source: Optional[Union["Tr", "Translates"]] = None # 翻译来源 (用于默认翻译)
|
||||
|
||||
def set(self, item: str, value: Union[bool, "Tr", "Translates"]) -> 'TranslateConfig':
|
||||
assert getattr(self, item, None) is not None, f'Config {item} is not in TranslateConfig'
|
||||
def set(self, item: str, value: Union[bool, "Tr", "Translates"]) -> "TranslateConfig":
|
||||
assert (
|
||||
getattr(self, item, None) is not None
|
||||
), f"Config {item} is not in TranslateConfig"
|
||||
assert isinstance(value, bool)
|
||||
setattr(self, item, value)
|
||||
return self
|
||||
|
||||
def __copy__(self) -> 'TranslateConfig':
|
||||
return TranslateConfig(raise_error=self.raise_error,
|
||||
crack_normal=self.crack_normal,
|
||||
insert_crack=self.insert_crack,
|
||||
is_final=self.is_final,
|
||||
keep_get=self.keep_get,
|
||||
always_copy=self.always_copy,
|
||||
source=self.source)
|
||||
def __copy__(self) -> "TranslateConfig":
|
||||
return TranslateConfig(
|
||||
raise_error=self.raise_error,
|
||||
crack_normal=self.crack_normal,
|
||||
insert_crack=self.insert_crack,
|
||||
is_final=self.is_final,
|
||||
keep_get=self.keep_get,
|
||||
always_copy=self.always_copy,
|
||||
source=self.source,
|
||||
)
|
||||
|
||||
def copy(self) -> 'TranslateConfig':
|
||||
def copy(self) -> "TranslateConfig":
|
||||
return self.__copy__()
|
||||
|
||||
|
||||
@ -58,11 +61,13 @@ key_type = Union[str, int, Hashable]
|
||||
|
||||
|
||||
class Translates:
|
||||
|
||||
def __init__(self, value: Union[Dict[str, Any], list, tuple, str],
|
||||
config: Optional[TranslateConfig] = None,
|
||||
get_list: Optional[List[Tuple[bool, str]]] = None):
|
||||
""" 一个用于翻译的东西
|
||||
def __init__(
|
||||
self,
|
||||
value: Union[Dict[str, Any], list, tuple, str],
|
||||
config: Optional[TranslateConfig] = None,
|
||||
get_list: Optional[List[Tuple[bool, str]]] = None,
|
||||
):
|
||||
"""一个用于翻译的东西
|
||||
:param value: 翻译键节点
|
||||
:param config: 配置
|
||||
:param get_list: 获取列表
|
||||
@ -71,8 +76,11 @@ class Translates:
|
||||
self._config = config or TranslateConfig()
|
||||
self._get_list = get_list or []
|
||||
|
||||
def set_conf_(self, option: Union[str, TranslateConfig],
|
||||
value: Optional[Union[bool, List[str]]] = None) -> 'Translates':
|
||||
def set_conf_(
|
||||
self,
|
||||
option: Union[str, TranslateConfig],
|
||||
value: Optional[Union[bool, List[str]]] = None,
|
||||
) -> "Translates":
|
||||
assert isinstance(option, (TranslateConfig, str))
|
||||
if isinstance(option, TranslateConfig):
|
||||
self._config = option
|
||||
@ -82,26 +90,35 @@ class Translates:
|
||||
|
||||
def _raise_no_value(self, e: Exception, item: key_type):
|
||||
if self._config.raise_error:
|
||||
raise TranslateKeyNotFound(self._value, [x[1] for x in self._get_list]) from None
|
||||
raise TranslateKeyNotFound(
|
||||
self._value, [x[1] for x in self._get_list]
|
||||
) from None
|
||||
elif DR_status.report_translate_not_found:
|
||||
frame = inspect.currentframe()
|
||||
if frame is not None:
|
||||
frame = frame.f_back.f_back
|
||||
code_list = [self.__getitem__.__code__, self.__getattr__.__code__,
|
||||
self.__copy__.__code__, self.copy.__code__,
|
||||
Tr.lang.__code__, Tr.__getitem__.__code__,
|
||||
Tr.__call__.__code__] # 调用堆栈上的不需要的东西
|
||||
code_list = [
|
||||
self.__getitem__.__code__,
|
||||
self.__getattr__.__code__,
|
||||
self.__copy__.__code__,
|
||||
self.copy.__code__,
|
||||
Tr.lang.__code__,
|
||||
Tr.__getitem__.__code__,
|
||||
Tr.__call__.__code__,
|
||||
] # 调用堆栈上的不需要的东西
|
||||
while True:
|
||||
if frame.f_code not in code_list: # 直到调用堆栈不是不需要的东西
|
||||
break
|
||||
frame = frame.f_back # 继续向上寻找
|
||||
frame = f'call at {frame.f_code.co_filename}:{frame.f_lineno}'
|
||||
frame = f"call at {frame.f_code.co_filename}:{frame.f_lineno}"
|
||||
else:
|
||||
frame = 'but No Frame environment'
|
||||
frame = "but No Frame environment"
|
||||
raise_info = f"{self.name} Cause a error when getting {item} {frame}"
|
||||
print(raise_info)
|
||||
|
||||
def __getitem__(self, item: Union[key_type, List[key_type], Tuple[key_type]]) -> "Translates":
|
||||
def __getitem__(
|
||||
self, item: Union[key_type, List[key_type], Tuple[key_type]]
|
||||
) -> "Translates":
|
||||
try:
|
||||
if isinstance(item, (str, int, Hashable)):
|
||||
cache_value = self._value[item]
|
||||
@ -109,11 +126,19 @@ class Translates:
|
||||
cache_value = self._value
|
||||
for a_item in item:
|
||||
cache_value = cache_value[a_item]
|
||||
if isinstance(cache_value, (int, str,)):
|
||||
if isinstance(
|
||||
cache_value,
|
||||
(
|
||||
int,
|
||||
str,
|
||||
),
|
||||
):
|
||||
self._config.is_final = True
|
||||
self._get_list.append((True, item))
|
||||
if self._config.always_copy:
|
||||
return Translates(value=cache_value, config=self._config, get_list=self._get_list)
|
||||
return Translates(
|
||||
value=cache_value, config=self._config, get_list=self._get_list
|
||||
)
|
||||
self._value = cache_value
|
||||
except (KeyError, TypeError, AttributeError) as e:
|
||||
self._get_list.append((False, item))
|
||||
@ -128,11 +153,13 @@ class Translates:
|
||||
def copy(self):
|
||||
return self.__copy__()
|
||||
|
||||
def __copy__(self) -> 'Translates':
|
||||
def __copy__(self) -> "Translates":
|
||||
return Translates(value=self._value, config=self._config, get_list=self._get_list)
|
||||
|
||||
def __getattr__(self, item: key_type) -> "Translates":
|
||||
if (self._config.is_final or any(x[0] for x in self._get_list)) and hasattr(self._value, item):
|
||||
if (self._config.is_final or any(x[0] for x in self._get_list)) and hasattr(
|
||||
self._value, item
|
||||
):
|
||||
return getattr(self._value, item)
|
||||
# 实际上我这里完全不需要处理正常需求,因为 __getattribute__ 已经帮我处理过了
|
||||
return self.__getitem__(item)
|
||||
@ -153,10 +180,12 @@ class Tr:
|
||||
GOOD
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
language: str = None,
|
||||
config: Optional[TranslateConfig] = None,
|
||||
lang_path: Optional[Path] = None):
|
||||
def __init__(
|
||||
self,
|
||||
language: str = None,
|
||||
config: Optional[TranslateConfig] = None,
|
||||
lang_path: Optional[Path] = None,
|
||||
):
|
||||
"""
|
||||
诶嘿,我抄的MCDR
|
||||
:param language: Tr 所使用的的语言
|
||||
@ -164,11 +193,21 @@ class Tr:
|
||||
:param lang_path: 语言文件夹路径
|
||||
"""
|
||||
self.language_name = language if language is not None else DR_runtime.language
|
||||
self.language_path = lang_path if lang_path is not None else Path('assets/lang')
|
||||
self.translates: Dict[str, Union[str, Dict]] = tools.load_file(self.language_path / f'{self.language_name}.toml')
|
||||
self.default_translate: Dict = tools.load_file(f'{self.language_path}/{DR_status.default_language}.toml')
|
||||
self.default_config = config.set('source', self) if config is not None else TranslateConfig(source=self)
|
||||
self.translates_cache = Translates(value=self.translates, config=self.default_config.copy())
|
||||
self.language_path = lang_path if lang_path is not None else Path("assets/lang")
|
||||
self.translates: Dict[str, Union[str, Dict]] = tools.load_file(
|
||||
self.language_path / f"{self.language_name}.toml"
|
||||
)
|
||||
self.default_translate: Dict = tools.load_file(
|
||||
f"{self.language_path}/{DR_status.default_language}.toml"
|
||||
)
|
||||
self.default_config = (
|
||||
config.set("source", self)
|
||||
if config is not None
|
||||
else TranslateConfig(source=self)
|
||||
)
|
||||
self.translates_cache = Translates(
|
||||
value=self.translates, config=self.default_config.copy()
|
||||
)
|
||||
|
||||
@property
|
||||
def _language(self) -> str:
|
||||
@ -187,15 +226,23 @@ class Tr:
|
||||
# 首先判定是否存在对应的语言文件
|
||||
if lang == self.language_name:
|
||||
return False
|
||||
if lang == ' ' or lang == '':
|
||||
raise LanguageNotFound('Can not be empty')
|
||||
if lang == " " or lang == "":
|
||||
raise LanguageNotFound("Can not be empty")
|
||||
lang = lang or self.language_name
|
||||
if not os.path.exists(f'{self.language_path}/{lang}.toml'):
|
||||
print(f"lang: {os.path.exists(f'{self.language_path}/{lang}.toml')} language = {lang} {self.language_name=}")
|
||||
if not os.path.exists(f"{self.language_path}/{lang}.toml"):
|
||||
print(
|
||||
f"lang: {os.path.exists(f'{self.language_path}/{lang}.toml')} language = {lang} {self.language_name=}"
|
||||
)
|
||||
raise LanguageNotFound(lang)
|
||||
self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'{self.language_path}/{lang}.toml')
|
||||
self.default_translate: Dict = tools.load_file(f'{self.language_path}/{DR_runtime.default_language}.toml')
|
||||
self.translates_cache = Translates(value=self.translates, config=self.default_config.copy())
|
||||
self.translates: Dict[str, Union[str, Dict]] = tools.load_file(
|
||||
f"{self.language_path}/{lang}.toml"
|
||||
)
|
||||
self.default_translate: Dict = tools.load_file(
|
||||
f"{self.language_path}/{DR_runtime.default_language}.toml"
|
||||
)
|
||||
self.translates_cache = Translates(
|
||||
value=self.translates, config=self.default_config.copy()
|
||||
)
|
||||
self.language_name = lang
|
||||
DR_runtime.language = self.language_name
|
||||
return True
|
||||
|
@ -20,14 +20,16 @@ def ensure_cmd_readable(cmd: str) -> str:
|
||||
:param cmd: 要格式化的命令行参数
|
||||
:return: 格式化后的命令行参数
|
||||
"""
|
||||
if ' ' in str(cmd):
|
||||
if " " in str(cmd):
|
||||
return f'"{cmd}"'
|
||||
return cmd
|
||||
|
||||
|
||||
def format_cmd(arg_name: Optional[str] = None,
|
||||
arg_value: Optional[Union[str, List[str]]] = None,
|
||||
write: Optional[Any] = True) -> List[str]:
|
||||
def format_cmd(
|
||||
arg_name: Optional[str] = None,
|
||||
arg_value: Optional[Union[str, List[str]]] = None,
|
||||
write: Optional[Any] = True,
|
||||
) -> List[str]:
|
||||
"""
|
||||
用来格式化输出命令行参数
|
||||
:param arg_name: 类似 --show-memory 之类的主项
|
||||
@ -42,10 +44,10 @@ def format_cmd(arg_name: Optional[str] = None,
|
||||
if arg_value is None:
|
||||
return [arg_name]
|
||||
if isinstance(arg_value, list):
|
||||
arg_value = ','.join([ensure_cmd_readable(value) for value in arg_value])
|
||||
return [f'{arg_name}{arg_value}']
|
||||
arg_value = ",".join([ensure_cmd_readable(value) for value in arg_value])
|
||||
return [f"{arg_name}{arg_value}"]
|
||||
arg_value = ensure_cmd_readable(arg_value)
|
||||
return [f'{arg_name}{arg_value}']
|
||||
return [f"{arg_name}{arg_value}"]
|
||||
|
||||
|
||||
def _add_cmd(cmd: List[str], string: Optional[str]) -> List[str]:
|
||||
@ -58,15 +60,18 @@ class CompilerHelper(Options):
|
||||
"""
|
||||
用于帮助生成 nuitka 构建脚本的类
|
||||
Use to help generate nuitka build script
|
||||
|
||||
|
||||
"""
|
||||
name = 'Nuitka Compiler Helper'
|
||||
|
||||
name = "Nuitka Compiler Helper"
|
||||
|
||||
output_path: Path = Path("./build/nuitka")
|
||||
src_file: Path = Path('DR.py')
|
||||
src_file: Path = Path("DR.py")
|
||||
|
||||
python_cmd: str = 'python'
|
||||
compat_nuitka_version: VersionRequirement = VersionRequirement("~1.8.1") # STATIC VERSION
|
||||
python_cmd: str = "python"
|
||||
compat_nuitka_version: VersionRequirement = VersionRequirement(
|
||||
"~1.8.1"
|
||||
) # STATIC VERSION
|
||||
|
||||
# 以下为 nuitka 的参数
|
||||
use_lto: bool = False # --lto=yes (no is faster)
|
||||
@ -75,7 +80,7 @@ class CompilerHelper(Options):
|
||||
use_mingw: bool = False # --mingw64
|
||||
|
||||
onefile: bool = False # --onefile
|
||||
onefile_tempdir: Optional[str] = '' # --onefile-tempdir-spec=
|
||||
onefile_tempdir: Optional[str] = "" # --onefile-tempdir-spec=
|
||||
standalone: bool = True # --standalone
|
||||
use_ccache: bool = True # not --disable-ccache
|
||||
enable_console: bool = True # --enable-console / --disable-console
|
||||
@ -84,43 +89,59 @@ class CompilerHelper(Options):
|
||||
show_memory: bool = False # --show-memory
|
||||
remove_output: bool = True # --remove-output
|
||||
save_xml: bool = False # --xml
|
||||
xml_path: Path = Path('build/compile_data.xml')
|
||||
xml_path: Path = Path("build/compile_data.xml")
|
||||
save_report: bool = False # --report
|
||||
report_path: Path = Path('build/compile_report.xml')
|
||||
report_path: Path = Path("build/compile_report.xml")
|
||||
|
||||
download_confirm: bool = True # --assume-yes-for-download
|
||||
run_after_build: bool = False # --run
|
||||
|
||||
company_name: str = 'tool-shenjack-workshop'
|
||||
product_name: str = 'Difficult-Rocket'
|
||||
company_name: str = "tool-shenjack-workshop"
|
||||
product_name: str = "Difficult-Rocket"
|
||||
file_version: Version
|
||||
product_version: Version
|
||||
file_description: str = 'Difficult Rocket' # --file-description
|
||||
file_description: str = "Difficult Rocket" # --file-description
|
||||
|
||||
copy_right: str = 'Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com' # --copyright
|
||||
copy_right: str = (
|
||||
"Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com" # --copyright
|
||||
)
|
||||
|
||||
icon_path: Path = Path('assets/textures/icon.png')
|
||||
icon_path: Path = Path("assets/textures/icon.png")
|
||||
|
||||
follow_import: List[str] = ['pyglet']
|
||||
no_follow_import: List[str] = ['objprint', 'pillow', 'PIL', 'cffi', 'pydoc', 'numpy', 'email', 'win32con',
|
||||
'smtplib', 'win32evtlog', 'win32evtlogutil', 'win32api']
|
||||
follow_import: List[str] = ["pyglet"]
|
||||
no_follow_import: List[str] = [
|
||||
"objprint",
|
||||
"pillow",
|
||||
"PIL",
|
||||
"cffi",
|
||||
"pydoc",
|
||||
"numpy",
|
||||
"email",
|
||||
"win32con",
|
||||
"smtplib",
|
||||
"win32evtlog",
|
||||
"win32evtlogutil",
|
||||
"win32api",
|
||||
]
|
||||
|
||||
include_data_dir: List[Tuple[str, str]] = [('./config', './config'),
|
||||
('./assets', './assets')]
|
||||
include_packages: List[str] = ['Difficult_Rocket.api']
|
||||
include_data_dir: List[Tuple[str, str]] = [
|
||||
("./config", "./config"),
|
||||
("./assets", "./assets"),
|
||||
]
|
||||
include_packages: List[str] = ["Difficult_Rocket.api"]
|
||||
|
||||
enable_plugin: List[str] = [] # --enable-plugin=xxx,xxx
|
||||
disable_plugin: List[str] = ['pyqt5', 'tk-inter'] # --disable-plugin=xxx,xxx
|
||||
disable_plugin: List[str] = ["pyqt5", "tk-inter"] # --disable-plugin=xxx,xxx
|
||||
|
||||
def init(self, **kwargs) -> None:
|
||||
if (compat_version := kwargs.get('compat_nuitka_version')) is not None:
|
||||
if (compat_version := kwargs.get("compat_nuitka_version")) is not None:
|
||||
if not self.compat_nuitka_version.accept(compat_version):
|
||||
warnings.warn(
|
||||
f"Nuitka version may not compat with {compat_version}\n"
|
||||
f"requirement: {self.compat_nuitka_version}"
|
||||
)
|
||||
# 非 windows 平台不使用 msvc
|
||||
if platform.system() != 'Windows':
|
||||
if platform.system() != "Windows":
|
||||
self.use_msvc = False
|
||||
self.use_mingw = False
|
||||
else:
|
||||
@ -130,6 +151,7 @@ class CompilerHelper(Options):
|
||||
def load_file(self) -> bool:
|
||||
try:
|
||||
from Difficult_Rocket import DR_status
|
||||
|
||||
self.product_version = DR_status.DR_version
|
||||
self.file_version = DR_status.Build_version
|
||||
return True
|
||||
@ -144,10 +166,10 @@ class CompilerHelper(Options):
|
||||
"""
|
||||
输出编译器帮助信息
|
||||
Output compiler help information
|
||||
|
||||
|
||||
Args:
|
||||
longest (Optional[int], optional):
|
||||
输出信息的最大长度限制 The maximum length of output information.
|
||||
longest (Optional[int], optional):
|
||||
输出信息的最大长度限制 The maximum length of output information.
|
||||
Defaults to None.
|
||||
|
||||
Returns:
|
||||
@ -164,55 +186,89 @@ class CompilerHelper(Options):
|
||||
Generate nuitka build script
|
||||
|
||||
Returns:
|
||||
List[str]:
|
||||
List[str]:
|
||||
生成的 nuitka 构建脚本
|
||||
Generated nuitka build script
|
||||
"""
|
||||
cmd_list = [self.python_cmd, '-m', 'nuitka']
|
||||
cmd_list = [self.python_cmd, "-m", "nuitka"]
|
||||
# macos 和 非 macos icon 参数不同
|
||||
if platform.system() == 'Darwin':
|
||||
cmd_list += format_cmd('--macos-app-version=', self.product_version, self.product_version) # noqa
|
||||
cmd_list += format_cmd('--macos-app-icon=', self.icon_path.absolute(), self.icon_path) # noqa
|
||||
elif platform.system() == 'Windows':
|
||||
cmd_list += format_cmd('--windows-icon-from-ico=', self.icon_path.absolute(), self.icon_path) # noqa
|
||||
elif platform.system() == 'Linux':
|
||||
cmd_list += format_cmd('--linux-icon=', self.icon_path.absolute(), self.icon_path) # noqa
|
||||
if platform.system() == "Darwin":
|
||||
cmd_list += format_cmd(
|
||||
"--macos-app-version=", self.product_version, self.product_version
|
||||
) # noqa
|
||||
cmd_list += format_cmd(
|
||||
"--macos-app-icon=", self.icon_path.absolute(), self.icon_path
|
||||
) # noqa
|
||||
elif platform.system() == "Windows":
|
||||
cmd_list += format_cmd(
|
||||
"--windows-icon-from-ico=", self.icon_path.absolute(), self.icon_path
|
||||
) # noqa
|
||||
elif platform.system() == "Linux":
|
||||
cmd_list += format_cmd(
|
||||
"--linux-icon=", self.icon_path.absolute(), self.icon_path
|
||||
) # noqa
|
||||
|
||||
cmd_list += format_cmd('--lto=', 'yes' if self.use_lto else 'no')
|
||||
cmd_list += format_cmd('--clang' if self.use_clang else None)
|
||||
cmd_list += format_cmd('--msvc=latest' if self.use_msvc else None)
|
||||
cmd_list += format_cmd('--mingw64' if self.use_mingw else None)
|
||||
cmd_list += format_cmd('--standalone' if self.standalone else None)
|
||||
cmd_list += format_cmd('--onefile' if self.onefile else None)
|
||||
cmd_list += format_cmd('--onefile-tempdir-spec=', self.onefile_tempdir, self.onefile_tempdir)
|
||||
cmd_list += format_cmd("--lto=", "yes" if self.use_lto else "no")
|
||||
cmd_list += format_cmd("--clang" if self.use_clang else None)
|
||||
cmd_list += format_cmd("--msvc=latest" if self.use_msvc else None)
|
||||
cmd_list += format_cmd("--mingw64" if self.use_mingw else None)
|
||||
cmd_list += format_cmd("--standalone" if self.standalone else None)
|
||||
cmd_list += format_cmd("--onefile" if self.onefile else None)
|
||||
cmd_list += format_cmd(
|
||||
"--onefile-tempdir-spec=", self.onefile_tempdir, self.onefile_tempdir
|
||||
)
|
||||
|
||||
cmd_list += format_cmd('--disable-ccache' if not self.use_ccache else None)
|
||||
cmd_list += format_cmd('--show-progress' if self.show_progress else None)
|
||||
cmd_list += format_cmd('--show-memory' if self.show_memory else None)
|
||||
cmd_list += format_cmd('--remove-output' if self.remove_output else None)
|
||||
cmd_list += format_cmd('--assume-yes-for-download' if self.download_confirm else None)
|
||||
cmd_list += format_cmd('--run' if self.run_after_build else None)
|
||||
cmd_list += format_cmd('--enable-console' if self.enable_console else '--disable-console')
|
||||
cmd_list += format_cmd("--disable-ccache" if not self.use_ccache else None)
|
||||
cmd_list += format_cmd("--show-progress" if self.show_progress else None)
|
||||
cmd_list += format_cmd("--show-memory" if self.show_memory else None)
|
||||
cmd_list += format_cmd("--remove-output" if self.remove_output else None)
|
||||
cmd_list += format_cmd(
|
||||
"--assume-yes-for-download" if self.download_confirm else None
|
||||
)
|
||||
cmd_list += format_cmd("--run" if self.run_after_build else None)
|
||||
cmd_list += format_cmd(
|
||||
"--enable-console" if self.enable_console else "--disable-console"
|
||||
)
|
||||
|
||||
cmd_list += format_cmd('--xml=', str(self.xml_path.absolute()), self.save_xml)
|
||||
cmd_list += format_cmd('--report=', str(self.report_path.absolute()), self.save_report)
|
||||
cmd_list += format_cmd('--output-dir=', str(self.output_path.absolute()), self.output_path)
|
||||
cmd_list += format_cmd('--company-name=', self.company_name, self.company_name)
|
||||
cmd_list += format_cmd('--product-name=', self.product_name, self.product_name)
|
||||
cmd_list += format_cmd('--file-version=', str(self.file_version), self.file_version)
|
||||
cmd_list += format_cmd('--product-version=', str(self.product_version), self.product_version)
|
||||
cmd_list += format_cmd('--file-description=', self.file_description, self.file_description)
|
||||
cmd_list += format_cmd('--copyright=', self.copy_right, self.copy_right)
|
||||
cmd_list += format_cmd("--xml=", str(self.xml_path.absolute()), self.save_xml)
|
||||
cmd_list += format_cmd(
|
||||
"--report=", str(self.report_path.absolute()), self.save_report
|
||||
)
|
||||
cmd_list += format_cmd(
|
||||
"--output-dir=", str(self.output_path.absolute()), self.output_path
|
||||
)
|
||||
cmd_list += format_cmd("--company-name=", self.company_name, self.company_name)
|
||||
cmd_list += format_cmd("--product-name=", self.product_name, self.product_name)
|
||||
cmd_list += format_cmd(
|
||||
"--file-version=", str(self.file_version), self.file_version
|
||||
)
|
||||
cmd_list += format_cmd(
|
||||
"--product-version=", str(self.product_version), self.product_version
|
||||
)
|
||||
cmd_list += format_cmd(
|
||||
"--file-description=", self.file_description, self.file_description
|
||||
)
|
||||
cmd_list += format_cmd("--copyright=", self.copy_right, self.copy_right)
|
||||
|
||||
cmd_list += format_cmd('--follow-import-to=', self.follow_import, self.follow_import)
|
||||
cmd_list += format_cmd('--nofollow-import-to=', self.no_follow_import, self.no_follow_import)
|
||||
cmd_list += format_cmd('--enable-plugin=', self.enable_plugin, self.enable_plugin)
|
||||
cmd_list += format_cmd('--disable-plugin=', self.disable_plugin, self.disable_plugin)
|
||||
cmd_list += format_cmd(
|
||||
"--follow-import-to=", self.follow_import, self.follow_import
|
||||
)
|
||||
cmd_list += format_cmd(
|
||||
"--nofollow-import-to=", self.no_follow_import, self.no_follow_import
|
||||
)
|
||||
cmd_list += format_cmd("--enable-plugin=", self.enable_plugin, self.enable_plugin)
|
||||
cmd_list += format_cmd(
|
||||
"--disable-plugin=", self.disable_plugin, self.disable_plugin
|
||||
)
|
||||
|
||||
if self.include_data_dir:
|
||||
cmd_list += [f"--include-data-dir={src}={dst}" for src, dst in self.include_data_dir]
|
||||
cmd_list += [
|
||||
f"--include-data-dir={src}={dst}" for src, dst in self.include_data_dir
|
||||
]
|
||||
if self.include_packages:
|
||||
cmd_list += [f"--include-package={package}" for package in self.include_packages]
|
||||
cmd_list += [
|
||||
f"--include-package={package}" for package in self.include_packages
|
||||
]
|
||||
|
||||
cmd_list.append(f"--main={self.src_file}")
|
||||
return cmd_list
|
||||
|
@ -4,8 +4,8 @@ import sys
|
||||
|
||||
import rtoml as toml
|
||||
|
||||
with open(sys.argv[1], encoding='utf-8', mode='r') as f:
|
||||
if sys.argv[2] == 'parse':
|
||||
with open(sys.argv[1], encoding="utf-8", mode="r") as f:
|
||||
if sys.argv[2] == "parse":
|
||||
a = toml.load(f)
|
||||
b = json.dumps(a)
|
||||
print(b)
|
||||
|
@ -9,26 +9,26 @@ from .lib import * # noqa: F403
|
||||
from typing import TYPE_CHECKING, Dict, Tuple, Optional, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
def test_call(py_obj) -> bool:
|
||||
""" 这里展示的代码实际上就是实际的等效实现 """
|
||||
"""这里展示的代码实际上就是实际的等效实现"""
|
||||
py_obj.draw()
|
||||
return True
|
||||
|
||||
|
||||
def get_version_str() -> str:
|
||||
"""
|
||||
获取版本号
|
||||
:return: 版本号
|
||||
"""
|
||||
|
||||
|
||||
def part_list_read_test(file_name: Optional[str] = "./assets/builtin/PartList.xml") -> None:
|
||||
def part_list_read_test(
|
||||
file_name: Optional[str] = "./assets/builtin/PartList.xml"
|
||||
) -> None:
|
||||
"""
|
||||
PartList 读取测试
|
||||
:param file_name:
|
||||
"""
|
||||
|
||||
|
||||
def read_ship_test(path: Optional[str] = "./assets/builtin/dock1.xml") -> None:
|
||||
"""
|
||||
飞船存档读取测试
|
||||
@ -36,7 +36,6 @@ if TYPE_CHECKING:
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
||||
def map_ptype_textures(part_type: str) -> str:
|
||||
"""
|
||||
获取零件的贴图 (写死的)
|
||||
@ -44,7 +43,6 @@ if TYPE_CHECKING:
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
||||
class SR1PartType_rs: # NOQA
|
||||
"""
|
||||
用于从 rust 中读取 SR1PartType
|
||||
@ -54,51 +52,55 @@ if TYPE_CHECKING:
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
""" 零件的名字 """
|
||||
"""零件的名字"""
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
""" 零件的描述 """
|
||||
"""零件的描述"""
|
||||
|
||||
@property
|
||||
def sprite(self) -> str:
|
||||
""" 零件的贴图 """
|
||||
"""零件的贴图"""
|
||||
|
||||
@property
|
||||
def mass(self) -> float:
|
||||
""" 零件的质量 """
|
||||
"""零件的质量"""
|
||||
|
||||
@property
|
||||
def width(self) -> int:
|
||||
""" 零件的宽度 """
|
||||
"""零件的宽度"""
|
||||
|
||||
@property
|
||||
def height(self) -> int:
|
||||
""" 零件的高度 """
|
||||
"""零件的高度"""
|
||||
|
||||
@property
|
||||
def friction(self) -> float:
|
||||
""" 零件的摩擦系数 """
|
||||
"""零件的摩擦系数"""
|
||||
|
||||
@property
|
||||
def hidden(self) -> bool:
|
||||
""" 零件是否隐藏 """
|
||||
"""零件是否隐藏"""
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
""" 零件的类型 """
|
||||
|
||||
"""零件的类型"""
|
||||
|
||||
class SR1PartList_rs: # NOQA
|
||||
""" 用于从 rust 中读取 SR1PartList """
|
||||
"""用于从 rust 中读取 SR1PartList"""
|
||||
|
||||
def __init__(self, file_name: Optional[str] = "./assets/builtin/PartList.xml",
|
||||
list_name: Optional[str] = 'NewPartList'): ...
|
||||
def __init__(
|
||||
self,
|
||||
file_name: Optional[str] = "./assets/builtin/PartList.xml",
|
||||
list_name: Optional[str] = "NewPartList",
|
||||
):
|
||||
...
|
||||
|
||||
def as_dict(self) -> Dict[str, SR1PartType_rs]: ...
|
||||
|
||||
def get_part_type(self, name: str) -> SR1PartType_rs: ...
|
||||
def as_dict(self) -> Dict[str, SR1PartType_rs]:
|
||||
...
|
||||
|
||||
def get_part_type(self, name: str) -> SR1PartType_rs:
|
||||
...
|
||||
|
||||
class SR1PartData_rs: # NOQA
|
||||
"""
|
||||
@ -106,53 +108,66 @@ if TYPE_CHECKING:
|
||||
"""
|
||||
|
||||
@property
|
||||
def id(self) -> int: ...
|
||||
def id(self) -> int:
|
||||
...
|
||||
|
||||
@property
|
||||
def part_type_id(self) -> str: ...
|
||||
def part_type_id(self) -> str:
|
||||
...
|
||||
|
||||
@property
|
||||
def pos(self) -> Tuple[float, float]: ...
|
||||
def pos(self) -> Tuple[float, float]:
|
||||
...
|
||||
|
||||
@property
|
||||
def x(self) -> float: ...
|
||||
def x(self) -> float:
|
||||
...
|
||||
|
||||
@property
|
||||
def y(self) -> float: ...
|
||||
def y(self) -> float:
|
||||
...
|
||||
|
||||
@property
|
||||
def activate(self) -> bool: ...
|
||||
def activate(self) -> bool:
|
||||
...
|
||||
|
||||
@property
|
||||
def angle(self) -> float: ...
|
||||
def angle(self) -> float:
|
||||
...
|
||||
|
||||
@property
|
||||
def angle_r(self) -> float: ...
|
||||
def angle_r(self) -> float:
|
||||
...
|
||||
|
||||
@property
|
||||
def angle_v(self) -> float: ...
|
||||
def angle_v(self) -> float:
|
||||
...
|
||||
|
||||
@property
|
||||
def explode(self) -> bool: ...
|
||||
def explode(self) -> bool:
|
||||
...
|
||||
|
||||
@property
|
||||
def flip_x(self) -> bool: ...
|
||||
def flip_x(self) -> bool:
|
||||
...
|
||||
|
||||
@property
|
||||
def flip_y(self) -> bool: ...
|
||||
|
||||
def flip_y(self) -> bool:
|
||||
...
|
||||
|
||||
class SaveStatus_rs: # NOQA
|
||||
def __init__(self, save_default: Optional[bool] = False) -> None: ...
|
||||
|
||||
def __init__(self, save_default: Optional[bool] = False) -> None:
|
||||
...
|
||||
|
||||
class SR1Ship_rs: # NOQA
|
||||
""" 用于高效且省内存的读取 SR1Ship """
|
||||
"""用于高效且省内存的读取 SR1Ship"""
|
||||
|
||||
def __init__(self,
|
||||
file_path: Optional[str] = './assets/builtin/dock1.xml',
|
||||
part_list: Optional[SR1PartList_rs] = None,
|
||||
ship_name: Optional[str] = 'NewShip'):
|
||||
def __init__(
|
||||
self,
|
||||
file_path: Optional[str] = "./assets/builtin/dock1.xml",
|
||||
part_list: Optional[SR1PartList_rs] = None,
|
||||
ship_name: Optional[str] = "NewShip",
|
||||
):
|
||||
"""
|
||||
读取 SR1Ship
|
||||
:raise ValueError: 读取失败
|
||||
@ -162,30 +177,36 @@ if TYPE_CHECKING:
|
||||
"""
|
||||
|
||||
@property
|
||||
def name(self) -> str: ...
|
||||
def name(self) -> str:
|
||||
...
|
||||
|
||||
@property
|
||||
def description(self) -> str: ...
|
||||
def description(self) -> str:
|
||||
...
|
||||
|
||||
@property
|
||||
def lift_off(self) -> bool: ...
|
||||
def lift_off(self) -> bool:
|
||||
...
|
||||
|
||||
@property
|
||||
def touch_ground(self) -> bool: ...
|
||||
def touch_ground(self) -> bool:
|
||||
...
|
||||
|
||||
@property
|
||||
def mass(self) -> float:
|
||||
""" 获取整搜船的质量 """
|
||||
"""获取整搜船的质量"""
|
||||
|
||||
@property
|
||||
def img_pos(self) -> Tuple[int, int, int, int]:
|
||||
""" -x -y +x +y 左下右上 """
|
||||
"""-x -y +x +y 左下右上"""
|
||||
|
||||
@property
|
||||
def connection(self) -> List[Tuple[int, int, int, int]]:
|
||||
"""获取所有连接信息"""
|
||||
|
||||
def get_part_box(self, part_id: int) -> Optional[Tuple[Tuple[int, int], Tuple[int, int]]]:
|
||||
def get_part_box(
|
||||
self, part_id: int
|
||||
) -> Optional[Tuple[Tuple[int, int], Tuple[int, int]]]:
|
||||
"""获取所有零件的盒子"""
|
||||
|
||||
def as_list(self) -> List[Tuple[SR1PartType_rs, SR1PartData_rs]]:
|
||||
@ -194,16 +215,23 @@ if TYPE_CHECKING:
|
||||
def as_dict(self) -> Dict[int, List[Tuple[SR1PartType_rs, SR1PartData_rs]]]:
|
||||
"""用于返回一个包含所有已连接零件的字典"""
|
||||
|
||||
def save(self, file_path: str, save_status: Optional[SaveStatus_rs] = None) -> None: ...
|
||||
|
||||
def save(
|
||||
self, file_path: str, save_status: Optional[SaveStatus_rs] = None
|
||||
) -> None:
|
||||
...
|
||||
|
||||
class Console_rs: # NOQA
|
||||
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: ...
|
||||
def new_command(self) -> bool:
|
||||
...
|
||||
|
@ -9,30 +9,32 @@ import warnings
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
|
||||
package_path = 'Difficult_Rocket_rs'
|
||||
lib_path = Path('../lib').resolve()
|
||||
build_path = 'build'
|
||||
package_path = "Difficult_Rocket_rs"
|
||||
lib_path = Path("../lib").resolve()
|
||||
build_path = "build"
|
||||
|
||||
if not os.path.exists(lib_path):
|
||||
os.mkdir(lib_path)
|
||||
|
||||
builds = os.listdir(build_path)
|
||||
print(os.path.abspath('.'))
|
||||
print(os.path.abspath("."))
|
||||
|
||||
try:
|
||||
shutil.copy('src/__init__.py', os.path.join(lib_path, '__init__.py'))
|
||||
shutil.copy("src/__init__.py", os.path.join(lib_path, "__init__.py"))
|
||||
except shutil.SameFileError:
|
||||
traceback.print_exc()
|
||||
|
||||
for build_dir in builds:
|
||||
if not os.path.exists(os.path.join(build_path, build_dir, package_path)):
|
||||
warnings.warn(f'package not found at {build_path}/{build_dir}')
|
||||
warnings.warn(f"package not found at {build_path}/{build_dir}")
|
||||
continue
|
||||
for file in os.listdir(os.path.join(build_path, build_dir, package_path)):
|
||||
file_name = os.path.join(lib_path, file)
|
||||
shutil.rmtree(file_name, ignore_errors=True)
|
||||
try:
|
||||
shutil.copy(os.path.join(build_path, build_dir, package_path, file), file_name)
|
||||
shutil.copy(
|
||||
os.path.join(build_path, build_dir, package_path, file), file_name
|
||||
)
|
||||
except (shutil.SameFileError, PermissionError):
|
||||
# print(os.path.exists(os.path))
|
||||
print(os.listdir(lib_path))
|
||||
|
@ -8,23 +8,27 @@ import shutil
|
||||
from setuptools import setup
|
||||
from setuptools_rust import Binding, RustExtension, Strip
|
||||
|
||||
package_path = 'Difficult_Rocket_rs'
|
||||
package_path = "Difficult_Rocket_rs"
|
||||
|
||||
setup(
|
||||
name='Difficult_Rocket_rs',
|
||||
name="Difficult_Rocket_rs",
|
||||
version="0.2.21.0",
|
||||
author='shenjackyuanjie',
|
||||
author_email='3695888@qq.com',
|
||||
rust_extensions=[RustExtension(target="Difficult_Rocket_rs.Difficult_Rocket_rs",
|
||||
binding=Binding.PyO3,
|
||||
strip=Strip.All)],
|
||||
author="shenjackyuanjie",
|
||||
author_email="3695888@qq.com",
|
||||
rust_extensions=[
|
||||
RustExtension(
|
||||
target="Difficult_Rocket_rs.Difficult_Rocket_rs",
|
||||
binding=Binding.PyO3,
|
||||
strip=Strip.All,
|
||||
)
|
||||
],
|
||||
zip_safe=False,
|
||||
)
|
||||
|
||||
lib_path = '../lib'
|
||||
build_path = 'build'
|
||||
lib_path = "../lib"
|
||||
build_path = "build"
|
||||
|
||||
if 'clean' in sys.argv:
|
||||
if "clean" in sys.argv:
|
||||
shutil.rmtree(build_path, ignore_errors=True)
|
||||
shutil.rmtree(f'{package_path}.egg-info', ignore_errors=True)
|
||||
shutil.rmtree(f"{package_path}.egg-info", ignore_errors=True)
|
||||
sys.exit(0)
|
||||
|
@ -18,11 +18,11 @@ from Difficult_Rocket.api.types import Options, Version
|
||||
|
||||
DR_rust_version = Version("0.2.23.0") # DR_mod 的 Rust 编写部分的兼容版本
|
||||
|
||||
logger = logging.getLogger('client.dr_game')
|
||||
logger = logging.getLogger("client.dr_game")
|
||||
|
||||
|
||||
class _DR_mod_runtime(Options): # NOQA
|
||||
name = 'DR mod runtime'
|
||||
name = "DR mod runtime"
|
||||
|
||||
use_DR_rust: bool = True
|
||||
DR_rust_available: bool = False
|
||||
@ -32,13 +32,17 @@ class _DR_mod_runtime(Options): # NOQA
|
||||
def init(self) -> None:
|
||||
try:
|
||||
from .Difficult_Rocket_rs import get_version_str
|
||||
|
||||
self.DR_rust_get_version = Version(get_version_str())
|
||||
self.DR_rust_available = True
|
||||
if self.DR_rust_get_version != self.DR_rust_version:
|
||||
relationship = 'larger' if self.DR_rust_version > self.DR_rust_version else 'smaller'
|
||||
relationship = (
|
||||
"larger" if self.DR_rust_version > self.DR_rust_version else "smaller"
|
||||
)
|
||||
warnings.warn(
|
||||
f'DR_rust builtin version is {self.DR_rust_version} but true version is {get_version_str()}.\n'
|
||||
f'Builtin version {relationship} than true version')
|
||||
f"DR_rust builtin version is {self.DR_rust_version} but true version is {get_version_str()}.\n"
|
||||
f"Builtin version {relationship} than true version"
|
||||
)
|
||||
self.use_DR_rust = self.use_DR_rust and self.DR_rust_available
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
@ -77,6 +81,7 @@ class DR_mod(ModInfo): # NOQA
|
||||
|
||||
if old_self:
|
||||
from .sr1_ship import SR1ShipRender
|
||||
|
||||
game.client.window.add_sub_screen("SR1_ship", SR1ShipRender)
|
||||
else:
|
||||
self.config.flush_option()
|
||||
@ -86,8 +91,9 @@ class DR_mod(ModInfo): # NOQA
|
||||
|
||||
def on_client_start(self, game: Game, client: ClientWindow):
|
||||
from .sr1_ship import SR1ShipRender
|
||||
|
||||
client.add_sub_screen("SR1_ship", SR1ShipRender)
|
||||
logger.info('on_client_start added sub screen')
|
||||
logger.info("on_client_start added sub screen")
|
||||
|
||||
def on_unload(self, game: Game):
|
||||
game.client.window.screen_list.pop("SR1_ship")
|
||||
|
@ -6,7 +6,7 @@ if DR_mod_runtime.use_DR_rust:
|
||||
|
||||
|
||||
class RustConsole(Console):
|
||||
name = 'Rust stdin Console'
|
||||
name = "Rust stdin Console"
|
||||
|
||||
running: bool = False
|
||||
console: Console_rs
|
||||
|
@ -16,10 +16,10 @@ class Menu(BaseScreen):
|
||||
"""
|
||||
DR game 的 菜单
|
||||
"""
|
||||
name = 'DR_game_menu'
|
||||
|
||||
def __init__(self,
|
||||
main_window: ClientWindow):
|
||||
name = "DR_game_menu"
|
||||
|
||||
def __init__(self, main_window: ClientWindow):
|
||||
super().__init__(main_window)
|
||||
self.main_batch = Batch()
|
||||
self.main_group = Group(parent=main_window.main_group, order=1)
|
||||
|
@ -33,14 +33,16 @@ from Difficult_Rocket.api.camera import CenterGroupCamera
|
||||
from Difficult_Rocket.api.gui.widget import PressTextButton
|
||||
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
from .Difficult_Rocket_rs import (SR1PartList_rs,
|
||||
SR1Ship_rs,
|
||||
SR1PartData_rs,
|
||||
SR1PartType_rs)
|
||||
from .Difficult_Rocket_rs import (
|
||||
SR1PartList_rs,
|
||||
SR1Ship_rs,
|
||||
SR1PartData_rs,
|
||||
SR1PartType_rs,
|
||||
)
|
||||
|
||||
logger = logging.getLogger('client.dr_game_sr1_ship')
|
||||
logger = logging.getLogger("client.dr_game_sr1_ship")
|
||||
logger.level = logging.DEBUG
|
||||
sr_tr = Tr(lang_path=Path(__file__).parent / 'lang')
|
||||
sr_tr = Tr(lang_path=Path(__file__).parent / "lang")
|
||||
|
||||
|
||||
class SR1ShipRenderStatus(Options): # NOQA
|
||||
@ -66,10 +68,9 @@ class SR1ShipRenderStatus(Options): # NOQA
|
||||
class SR1ShipRender(BaseScreen):
|
||||
"""用于渲染 sr1 船的类"""
|
||||
|
||||
name = 'DR_game_sr1_ship_render'
|
||||
name = "DR_game_sr1_ship_render"
|
||||
|
||||
def __init__(self,
|
||||
main_window: ClientWindow):
|
||||
def __init__(self, main_window: ClientWindow):
|
||||
super().__init__(main_window)
|
||||
self.logger = logger
|
||||
logger.info(sr_tr().mod.info.setup.start())
|
||||
@ -83,27 +84,56 @@ class SR1ShipRender(BaseScreen):
|
||||
self.height = main_window.height
|
||||
|
||||
self.main_batch = Batch()
|
||||
self.group_camera = CenterGroupCamera(window=main_window,
|
||||
order=10,
|
||||
parent=main_window.main_group,
|
||||
min_zoom=(1 / 2) ** 10,
|
||||
max_zoom=10)
|
||||
self.group_camera = CenterGroupCamera(
|
||||
window=main_window,
|
||||
order=10,
|
||||
parent=main_window.main_group,
|
||||
min_zoom=(1 / 2) ** 10,
|
||||
max_zoom=10,
|
||||
)
|
||||
self.part_group = Group(0, parent=self.group_camera)
|
||||
|
||||
self.debug_label = Label(x=20, y=main_window.height - 100, font_size=DR_status.std_font_size,
|
||||
text='SR1 render!', font_name=Fonts.微软等宽无线,
|
||||
width=main_window.width - 20, height=20,
|
||||
anchor_x='left', anchor_y='top',
|
||||
batch=self.main_batch, group=Group(5, parent=self.part_group))
|
||||
self.render_d_line = Line(0, 0, 0, 0, width=5, color=(200, 200, 10, 255),
|
||||
batch=self.main_batch, group=Group(5, parent=self.part_group))
|
||||
self.debug_label = Label(
|
||||
x=20,
|
||||
y=main_window.height - 100,
|
||||
font_size=DR_status.std_font_size,
|
||||
text="SR1 render!",
|
||||
font_name=Fonts.微软等宽无线,
|
||||
width=main_window.width - 20,
|
||||
height=20,
|
||||
anchor_x="left",
|
||||
anchor_y="top",
|
||||
batch=self.main_batch,
|
||||
group=Group(5, parent=self.part_group),
|
||||
)
|
||||
self.render_d_line = Line(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
width=5,
|
||||
color=(200, 200, 10, 255),
|
||||
batch=self.main_batch,
|
||||
group=Group(5, parent=self.part_group),
|
||||
)
|
||||
self.render_d_line.visible = self.status.draw_d_pos
|
||||
self.render_d_label = Label('debug label NODATA', font_name=Fonts.微软等宽无线,
|
||||
x=main_window.width / 2, y=main_window.height / 2)
|
||||
self.render_d_label = Label(
|
||||
"debug label NODATA",
|
||||
font_name=Fonts.微软等宽无线,
|
||||
x=main_window.width / 2,
|
||||
y=main_window.height / 2,
|
||||
)
|
||||
self.render_d_label.visible = self.status.draw_d_pos
|
||||
|
||||
self.test_button = PressTextButton(x=100, y=100, width=150, height=30, text='test button',
|
||||
batch=self.main_batch, group=Group(5, parent=main_window.main_group))
|
||||
self.test_button = PressTextButton(
|
||||
x=100,
|
||||
y=100,
|
||||
width=150,
|
||||
height=30,
|
||||
text="test button",
|
||||
batch=self.main_batch,
|
||||
group=Group(5, parent=main_window.main_group),
|
||||
)
|
||||
# self.test_button.push_handlers(main_window)
|
||||
main_window.push_handlers(self.test_button)
|
||||
|
||||
@ -121,16 +151,22 @@ class SR1ShipRender(BaseScreen):
|
||||
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
self.rust_parts = None
|
||||
self.part_list_rs = SR1PartList_rs('assets/builtin/PartList.xml', 'builtin_part_list')
|
||||
self.part_list_rs = SR1PartList_rs(
|
||||
"assets/builtin/PartList.xml", "builtin_part_list"
|
||||
)
|
||||
|
||||
self.load_xml('assets/builtin/dock1.xml')
|
||||
self.load_xml("assets/builtin/dock1.xml")
|
||||
|
||||
load_end_time = time.time_ns()
|
||||
logger.info(sr_tr().mod.info.setup.use_time().format((load_end_time - load_start_time) / 1000000000))
|
||||
logger.info(
|
||||
sr_tr()
|
||||
.mod.info.setup.use_time()
|
||||
.format((load_end_time - load_start_time) / 1000000000)
|
||||
)
|
||||
|
||||
@property
|
||||
def size(self) -> Tuple[int, int]:
|
||||
""" 渲染器的渲染大小 """
|
||||
"""渲染器的渲染大小"""
|
||||
return self.width, self.height
|
||||
|
||||
@size.setter
|
||||
@ -147,12 +183,15 @@ class SR1ShipRender(BaseScreen):
|
||||
try:
|
||||
start_time = time.time_ns()
|
||||
logger.info(sr_tr().sr1.ship.xml.loading().format(file_path))
|
||||
self.ship_name = file_path.split('/')[-1].split('.')[0]
|
||||
self.ship_name = file_path.split("/")[-1].split(".")[0]
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
self.rust_ship = SR1Ship_rs(file_path, self.part_list_rs, 'a_new_ship')
|
||||
self.rust_ship = SR1Ship_rs(file_path, self.part_list_rs, "a_new_ship")
|
||||
logger.info(sr_tr().sr1.ship.xml.load_done())
|
||||
logger.info(sr_tr().sr1.ship.xml.load_time().format(
|
||||
(time.time_ns() - start_time) / 1000000000))
|
||||
logger.info(
|
||||
sr_tr()
|
||||
.sr1.ship.xml.load_time()
|
||||
.format((time.time_ns() - start_time) / 1000000000)
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
@ -178,10 +217,17 @@ class SR1ShipRender(BaseScreen):
|
||||
parts: List[Tuple[SR1PartType_rs, SR1PartData_rs]]
|
||||
batch = []
|
||||
for p_type, p_data in parts:
|
||||
sprite_name = self.part_list_rs.get_part_type(p_data.part_type_id).sprite
|
||||
part_sprite = Sprite(img=self.textures.get_texture(sprite_name),
|
||||
x=p_data.x * 60, y=p_data.y * 60, z=random.random(),
|
||||
batch=self.main_batch, group=part_group)
|
||||
sprite_name = self.part_list_rs.get_part_type(
|
||||
p_data.part_type_id
|
||||
).sprite
|
||||
part_sprite = Sprite(
|
||||
img=self.textures.get_texture(sprite_name),
|
||||
x=p_data.x * 60,
|
||||
y=p_data.y * 60,
|
||||
z=random.random(),
|
||||
batch=self.main_batch,
|
||||
group=part_group,
|
||||
)
|
||||
part_sprite.rotation = p_data.angle_r
|
||||
part_sprite.scale_x = -1 if p_data.flip_x else 1
|
||||
part_sprite.scale_y = -1 if p_data.flip_y else 1
|
||||
@ -192,17 +238,61 @@ class SR1ShipRender(BaseScreen):
|
||||
# 线框
|
||||
part_line_box = []
|
||||
width = 4
|
||||
color = (random.randrange(0, 255), random.randrange(0, 255), random.randrange(0, 255),
|
||||
random.randrange(100, 200))
|
||||
color = (
|
||||
random.randrange(0, 255),
|
||||
random.randrange(0, 255),
|
||||
random.randrange(0, 255),
|
||||
random.randrange(100, 200),
|
||||
)
|
||||
(x, y), (x2, y2) = part_box
|
||||
part_line_box.append(Line(x=x * 30, y=y * 30, x2=x * 30, y2=y2 * 30,
|
||||
batch=self.main_batch, width=width, color=color, group=line_box_group))
|
||||
part_line_box.append(Line(x=x * 30, y=y2 * 30, x2=x2 * 30, y2=y2 * 30,
|
||||
batch=self.main_batch, width=width, color=color, group=line_box_group))
|
||||
part_line_box.append(Line(x=x2 * 30, y=y2 * 30, x2=x2 * 30, y2=y * 30,
|
||||
batch=self.main_batch, width=width, color=color, group=line_box_group))
|
||||
part_line_box.append(Line(x=x2 * 30, y=y * 30, x2=x * 30, y2=y * 30,
|
||||
batch=self.main_batch, width=width, color=color, group=line_box_group))
|
||||
part_line_box.append(
|
||||
Line(
|
||||
x=x * 30,
|
||||
y=y * 30,
|
||||
x2=x * 30,
|
||||
y2=y2 * 30,
|
||||
batch=self.main_batch,
|
||||
width=width,
|
||||
color=color,
|
||||
group=line_box_group,
|
||||
)
|
||||
)
|
||||
part_line_box.append(
|
||||
Line(
|
||||
x=x * 30,
|
||||
y=y2 * 30,
|
||||
x2=x2 * 30,
|
||||
y2=y2 * 30,
|
||||
batch=self.main_batch,
|
||||
width=width,
|
||||
color=color,
|
||||
group=line_box_group,
|
||||
)
|
||||
)
|
||||
part_line_box.append(
|
||||
Line(
|
||||
x=x2 * 30,
|
||||
y=y2 * 30,
|
||||
x2=x2 * 30,
|
||||
y2=y * 30,
|
||||
batch=self.main_batch,
|
||||
width=width,
|
||||
color=color,
|
||||
group=line_box_group,
|
||||
)
|
||||
)
|
||||
part_line_box.append(
|
||||
Line(
|
||||
x=x2 * 30,
|
||||
y=y * 30,
|
||||
x2=x * 30,
|
||||
y2=y * 30,
|
||||
batch=self.main_batch,
|
||||
width=width,
|
||||
color=color,
|
||||
group=line_box_group,
|
||||
)
|
||||
)
|
||||
# 直接用循环得了
|
||||
self.part_line_box[p_id] = part_line_box
|
||||
self.parts_sprite[p_id] = batch
|
||||
@ -215,11 +305,24 @@ class SR1ShipRender(BaseScreen):
|
||||
# 连接线
|
||||
parent_part_data = cache[connect[2]][0][1]
|
||||
child_part_data = cache[connect[3]][0][1]
|
||||
color = (random.randrange(100, 255), random.randrange(0, 255), random.randrange(0, 255), 255)
|
||||
self.part_line_list.append(Line(x=parent_part_data.x * 60, y=parent_part_data.y * 60,
|
||||
x2=child_part_data.x * 60, y2=child_part_data.y * 60,
|
||||
batch=self.main_batch, group=connect_line_group,
|
||||
width=1, color=color))
|
||||
color = (
|
||||
random.randrange(100, 255),
|
||||
random.randrange(0, 255),
|
||||
random.randrange(0, 255),
|
||||
255,
|
||||
)
|
||||
self.part_line_list.append(
|
||||
Line(
|
||||
x=parent_part_data.x * 60,
|
||||
y=parent_part_data.y * 60,
|
||||
x2=child_part_data.x * 60,
|
||||
y2=child_part_data.y * 60,
|
||||
batch=self.main_batch,
|
||||
group=connect_line_group,
|
||||
width=1,
|
||||
color=color,
|
||||
)
|
||||
)
|
||||
count += 1
|
||||
if count >= each_count * 3:
|
||||
count = 0
|
||||
@ -274,24 +377,43 @@ class SR1ShipRender(BaseScreen):
|
||||
full_mass = 0
|
||||
if DR_mod_runtime.use_DR_rust:
|
||||
full_mass = self.rust_ship.mass
|
||||
logger.info(sr_tr().sr1.ship.ship.load_time().format(
|
||||
(time.perf_counter_ns() - start_time) / 1000000000))
|
||||
logger.info(sr_tr().sr1.ship.ship.info().format(
|
||||
len(self.rust_ship.as_list()),
|
||||
f'{full_mass}kg' if DR_mod_runtime.use_DR_rust else sr_tr().game.require_DR_rs()))
|
||||
logger.info(
|
||||
sr_tr()
|
||||
.sr1.ship.ship.load_time()
|
||||
.format((time.perf_counter_ns() - start_time) / 1000000000)
|
||||
)
|
||||
logger.info(
|
||||
sr_tr()
|
||||
.sr1.ship.ship.info()
|
||||
.format(
|
||||
len(self.rust_ship.as_list()),
|
||||
f"{full_mass}kg"
|
||||
if DR_mod_runtime.use_DR_rust
|
||||
else sr_tr().game.require_DR_rs(),
|
||||
)
|
||||
)
|
||||
|
||||
def draw_batch(self, window: ClientWindow):
|
||||
if self.status.draw_done:
|
||||
self.render_d_label.text = f'x: {self.group_camera.view_x} y: {self.group_camera.view_y}'
|
||||
self.render_d_label.position = self.group_camera.view_x + (
|
||||
self.window_pointer.width / 2), self.group_camera.view_y + (
|
||||
self.window_pointer.height / 2) + 10, 0 # 0 for z
|
||||
self.render_d_label.text = (
|
||||
f"x: {self.group_camera.view_x} y: {self.group_camera.view_y}"
|
||||
)
|
||||
self.render_d_label.position = (
|
||||
self.group_camera.view_x + (self.window_pointer.width / 2),
|
||||
self.group_camera.view_y + (self.window_pointer.height / 2) + 10,
|
||||
0,
|
||||
) # 0 for z
|
||||
self.render_d_line.x2 = self.group_camera.view_x
|
||||
self.render_d_line.y2 = self.group_camera.view_y
|
||||
|
||||
gl.glEnable(gl.GL_SCISSOR_TEST)
|
||||
gl.glScissor(int(self.dx), int(self.dy), int(self.width), int(self.height))
|
||||
gl.glViewport(int(self.dx), int(self.dy), self.window_pointer.width, self.window_pointer.height)
|
||||
gl.glViewport(
|
||||
int(self.dx),
|
||||
int(self.dy),
|
||||
self.window_pointer.width,
|
||||
self.window_pointer.height,
|
||||
)
|
||||
self.main_batch.draw() # use group camera, no need to with
|
||||
gl.glViewport(0, 0, self.window_pointer.width, self.window_pointer.height)
|
||||
gl.glScissor(0, 0, self.window_pointer.width, self.window_pointer.height)
|
||||
@ -321,7 +443,9 @@ class SR1ShipRender(BaseScreen):
|
||||
self.render_d_line.y2 = height // 2
|
||||
self.test_button._update_position()
|
||||
|
||||
def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int, window: ClientWindow):
|
||||
def on_mouse_scroll(
|
||||
self, x: int, y: int, scroll_x: int, scroll_y: int, window: ClientWindow
|
||||
):
|
||||
if not self.status.draw_done:
|
||||
return
|
||||
if self.status.focus:
|
||||
@ -334,7 +458,7 @@ class SR1ShipRender(BaseScreen):
|
||||
if scroll_y == 0:
|
||||
zoom_d = 1
|
||||
else:
|
||||
zoom_d = ((2 ** scroll_y) - 1) * 0.5 + 1
|
||||
zoom_d = ((2**scroll_y) - 1) * 0.5 + 1
|
||||
# 缩放的变换量
|
||||
if not (self.group_camera.zoom == 10 and scroll_y > 0):
|
||||
if self.group_camera.zoom * zoom_d >= 10:
|
||||
@ -342,8 +466,8 @@ class SR1ShipRender(BaseScreen):
|
||||
self.group_camera.zoom = 10
|
||||
else:
|
||||
self.group_camera.zoom *= zoom_d
|
||||
mouse_dx_d *= (1 - zoom_d)
|
||||
mouse_dy_d *= (1 - zoom_d)
|
||||
mouse_dx_d *= 1 - zoom_d
|
||||
mouse_dy_d *= 1 - zoom_d
|
||||
self.group_camera.view_x += mouse_dx_d
|
||||
self.group_camera.view_y += mouse_dy_d
|
||||
elif self.status.moving:
|
||||
@ -358,26 +482,26 @@ class SR1ShipRender(BaseScreen):
|
||||
self.size = size_x, size_y
|
||||
|
||||
def on_command(self, command: CommandText, window: ClientWindow):
|
||||
""" 解析命令 """
|
||||
self.logger.info(f'command: {command}')
|
||||
if command.find('render'):
|
||||
if command.find('reset'):
|
||||
"""解析命令"""
|
||||
self.logger.info(f"command: {command}")
|
||||
if command.find("render"):
|
||||
if command.find("reset"):
|
||||
self.group_camera.reset()
|
||||
else:
|
||||
self.status.draw_call = True
|
||||
print('应该渲染飞船的')
|
||||
print("应该渲染飞船的")
|
||||
|
||||
elif command.find('debug'):
|
||||
if command.find('delta'):
|
||||
elif command.find("debug"):
|
||||
if command.find("delta"):
|
||||
self.render_d_line.visible = not self.render_d_line.visible
|
||||
self.status.draw_mouse_d_pos = self.render_d_line.visible
|
||||
self.logger.info(f'sr1 mouse {self.status.draw_mouse_d_pos}')
|
||||
elif command.find('ship'):
|
||||
self.logger.info(f"sr1 mouse {self.status.draw_mouse_d_pos}")
|
||||
elif command.find("ship"):
|
||||
if self.status.draw_done:
|
||||
for index, sprite in self.parts_sprite.items():
|
||||
sprite.visible = not sprite.visible
|
||||
|
||||
elif command.find('get_buf'):
|
||||
elif command.find("get_buf"):
|
||||
|
||||
def screenshot(window):
|
||||
"""
|
||||
@ -387,14 +511,19 @@ class SR1ShipRender(BaseScreen):
|
||||
"""
|
||||
from pyglet.gl import GLubyte, GL_RGBA, GL_UNSIGNED_BYTE, glReadPixels
|
||||
import pyglet
|
||||
|
||||
format_str = "RGBA"
|
||||
buf = (GLubyte * (len(format_str) * window.width * window.height))()
|
||||
glReadPixels(0, 0, window.width, window.height, GL_RGBA, GL_UNSIGNED_BYTE, buf)
|
||||
return pyglet.image.ImageData(window.width, window.height, format_str, buf)
|
||||
glReadPixels(
|
||||
0, 0, window.width, window.height, GL_RGBA, GL_UNSIGNED_BYTE, buf
|
||||
)
|
||||
return pyglet.image.ImageData(
|
||||
window.width, window.height, format_str, buf
|
||||
)
|
||||
|
||||
image_data = screenshot(self.window_pointer)
|
||||
image_data.save('test.png')
|
||||
elif command.find('gen_img'):
|
||||
image_data.save("test.png")
|
||||
elif command.find("gen_img"):
|
||||
if not self.status.draw_done:
|
||||
return
|
||||
if not DR_mod_runtime.use_DR_rust:
|
||||
@ -408,46 +537,66 @@ class SR1ShipRender(BaseScreen):
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
traceback.print_exc()
|
||||
print('PIL not found')
|
||||
print("PIL not found")
|
||||
return
|
||||
img = Image.new('RGBA', img_size)
|
||||
img = Image.new("RGBA", img_size)
|
||||
part_data = self.rust_ship.as_dict()
|
||||
for part, sprites in self.parts_sprite.items():
|
||||
for index, sprite in enumerate(sprites):
|
||||
sprite_img = sprite.image
|
||||
print(
|
||||
f"sprite_img: {sprite_img} {part_data[part][index][1].x * 60} {part_data[part][index][1].y * 60}")
|
||||
f"sprite_img: {sprite_img} {part_data[part][index][1].x * 60} {part_data[part][index][1].y * 60}"
|
||||
)
|
||||
img_data = sprite_img.get_image_data()
|
||||
fmt = img_data.format
|
||||
if fmt != 'RGB':
|
||||
fmt = 'RGBA'
|
||||
if fmt != "RGB":
|
||||
fmt = "RGBA"
|
||||
pitch = -(img_data.width * len(fmt))
|
||||
pil_image = Image.frombytes(fmt, (img_data.width, img_data.height), img_data.get_data(fmt, pitch))
|
||||
pil_image = Image.frombytes(
|
||||
fmt,
|
||||
(img_data.width, img_data.height),
|
||||
img_data.get_data(fmt, pitch),
|
||||
)
|
||||
|
||||
pil_image = pil_image.rotate(-SR1Rotation.get_rotation(part_data[part][index][1].angle),
|
||||
expand=True)
|
||||
pil_image = pil_image.rotate(
|
||||
-SR1Rotation.get_rotation(part_data[part][index][1].angle),
|
||||
expand=True,
|
||||
)
|
||||
|
||||
if part_data[part][index][1].flip_y:
|
||||
pil_image.transpose(Image.FLIP_TOP_BOTTOM)
|
||||
if part_data[part][index][1].flip_x:
|
||||
pil_image.transpose(Image.FLIP_LEFT_RIGHT)
|
||||
|
||||
img.paste(pil_image, (
|
||||
int(part_data[part][index][1].x * 60 + img_center[0]),
|
||||
int(-part_data[part][index][1].y * 60 + img_center[1])))
|
||||
img.paste(
|
||||
pil_image,
|
||||
(
|
||||
int(part_data[part][index][1].x * 60 + img_center[0]),
|
||||
int(-part_data[part][index][1].y * 60 + img_center[1]),
|
||||
),
|
||||
)
|
||||
|
||||
img.save(f'test{time.time()}.png', 'PNG')
|
||||
img.save(f"test{time.time()}.png", "PNG")
|
||||
|
||||
elif command.find('test'):
|
||||
if command.find('save'):
|
||||
elif command.find("test"):
|
||||
if command.find("save"):
|
||||
if not self.status.draw_done:
|
||||
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')
|
||||
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):
|
||||
def on_mouse_drag(
|
||||
self,
|
||||
x: int,
|
||||
y: int,
|
||||
dx: int,
|
||||
dy: int,
|
||||
buttons: int,
|
||||
modifiers: int,
|
||||
window: ClientWindow,
|
||||
):
|
||||
if self.status.focus:
|
||||
self.group_camera.view_x += dx
|
||||
self.group_camera.view_y += dy
|
||||
@ -466,7 +615,7 @@ class SR1ShipRender(BaseScreen):
|
||||
traceback.print_exc()
|
||||
else:
|
||||
if Path(paths[0]).is_dir():
|
||||
for path in Path(paths[0]).glob('*.xml'):
|
||||
for path in Path(paths[0]).glob("*.xml"):
|
||||
try:
|
||||
self.load_xml(str(path))
|
||||
except ValueError:
|
||||
@ -487,7 +636,7 @@ class SR1ShipRender(BaseScreen):
|
||||
self.window_pointer.view = value
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
from objprint import op
|
||||
|
||||
op(SR1ShipRenderStatus())
|
||||
|
@ -15,10 +15,11 @@ from Difficult_Rocket.api.types import Options
|
||||
|
||||
|
||||
class SR1Textures(Options):
|
||||
""" 存储 sr1 的材质 img """
|
||||
"""存储 sr1 的材质 img"""
|
||||
|
||||
def load_file(self, **kwargs):
|
||||
for image_name in self.flush_option():
|
||||
img = load(f'assets/textures/parts/{image_name}.png')
|
||||
img = load(f"assets/textures/parts/{image_name}.png")
|
||||
img.anchor_x = img.width // 2
|
||||
img.anchor_y = img.height // 2
|
||||
setattr(self, image_name, img)
|
||||
@ -32,81 +33,83 @@ class SR1Textures(Options):
|
||||
"""
|
||||
if name in self.cached_options:
|
||||
return self.cached_options.get(name)
|
||||
elif name.split('.')[0] in self.cached_options:
|
||||
return self.cached_options.get(name.split('.')[0])
|
||||
elif name.split(".")[0] in self.cached_options:
|
||||
return self.cached_options.get(name.split(".")[0])
|
||||
else:
|
||||
img = load(f'assets/textures/parts/{name}')
|
||||
img = load(f"assets/textures/parts/{name}")
|
||||
img.anchor_x = img.width // 2
|
||||
img.anchor_y = img.height // 2
|
||||
setattr(self, name, img)
|
||||
return img
|
||||
|
||||
Battery: AbstractImage = None
|
||||
Beam: AbstractImage = None
|
||||
CoverBottom: AbstractImage = None
|
||||
CoverStretch: AbstractImage = None
|
||||
CoverTop: AbstractImage = None
|
||||
DetacherRadial: AbstractImage = None
|
||||
DetacherVertical: AbstractImage = None
|
||||
DockingConnector: AbstractImage = None
|
||||
DockingPort: AbstractImage = None
|
||||
EngineIon: AbstractImage = None
|
||||
EngineLarge: AbstractImage = None
|
||||
EngineMedium: AbstractImage = None
|
||||
EngineSmall: AbstractImage = None
|
||||
EngineTiny: AbstractImage = None
|
||||
Fuselage: AbstractImage = None
|
||||
LanderLegJoint: AbstractImage = None
|
||||
LanderLegLower: AbstractImage = None
|
||||
LanderLegPreview: AbstractImage = None
|
||||
LanderLegUpper: AbstractImage = None
|
||||
NoseCone: AbstractImage = None
|
||||
Parachute: AbstractImage = None
|
||||
ParachuteCanister: AbstractImage = None
|
||||
Battery: AbstractImage = None
|
||||
Beam: AbstractImage = None
|
||||
CoverBottom: AbstractImage = None
|
||||
CoverStretch: AbstractImage = None
|
||||
CoverTop: AbstractImage = None
|
||||
DetacherRadial: AbstractImage = None
|
||||
DetacherVertical: AbstractImage = None
|
||||
DockingConnector: AbstractImage = None
|
||||
DockingPort: AbstractImage = None
|
||||
EngineIon: AbstractImage = None
|
||||
EngineLarge: AbstractImage = None
|
||||
EngineMedium: AbstractImage = None
|
||||
EngineSmall: AbstractImage = None
|
||||
EngineTiny: AbstractImage = None
|
||||
Fuselage: AbstractImage = None
|
||||
LanderLegJoint: AbstractImage = None
|
||||
LanderLegLower: AbstractImage = None
|
||||
LanderLegPreview: AbstractImage = None
|
||||
LanderLegUpper: AbstractImage = None
|
||||
NoseCone: AbstractImage = None
|
||||
Parachute: AbstractImage = None
|
||||
ParachuteCanister: AbstractImage = None
|
||||
ParachuteCanisterSide: AbstractImage = None
|
||||
Pod: AbstractImage = None
|
||||
Puffy750: AbstractImage = None
|
||||
RcsBlock: AbstractImage = None
|
||||
SideTank: AbstractImage = None
|
||||
SolarPanel: AbstractImage = None
|
||||
SolarPanelBase: AbstractImage = None
|
||||
SolidRocketBooster: AbstractImage = None
|
||||
TankLarge: AbstractImage = None
|
||||
TankMedium: AbstractImage = None
|
||||
TankSmall: AbstractImage = None
|
||||
TankTiny: AbstractImage = None
|
||||
Wheel: AbstractImage = None
|
||||
Wing: AbstractImage = None
|
||||
Pod: AbstractImage = None
|
||||
Puffy750: AbstractImage = None
|
||||
RcsBlock: AbstractImage = None
|
||||
SideTank: AbstractImage = None
|
||||
SolarPanel: AbstractImage = None
|
||||
SolarPanelBase: AbstractImage = None
|
||||
SolidRocketBooster: AbstractImage = None
|
||||
TankLarge: AbstractImage = None
|
||||
TankMedium: AbstractImage = None
|
||||
TankSmall: AbstractImage = None
|
||||
TankTiny: AbstractImage = None
|
||||
Wheel: AbstractImage = None
|
||||
Wing: AbstractImage = None
|
||||
|
||||
|
||||
class SR1PartTexture:
|
||||
part_type_sprite: Dict[str, str] = {'pod-1': 'Pod',
|
||||
'detacher-1': 'DetacherVertical',
|
||||
'detacher-2': 'DetacherRadial',
|
||||
'wheel-1': 'Wheel',
|
||||
'wheel-2': 'Wheel',
|
||||
'fuselage-1': 'Fuselage',
|
||||
'strut-1': 'Beam',
|
||||
'fueltank-0': 'TankTiny',
|
||||
'fueltank-1': 'TankSmall',
|
||||
'fueltank-2': 'TankMedium',
|
||||
'fueltank-3': 'TankLarge',
|
||||
'fueltank-4': 'Puffy750',
|
||||
'fueltank-5': 'SideTank',
|
||||
'engine-0': 'EngineTiny',
|
||||
'engine-1': 'EngineSmall',
|
||||
'engine-2': 'EngineMedium',
|
||||
'engine-3': 'EngineLarge',
|
||||
'engine-4': 'SolidRocketBooster',
|
||||
'ion-0': 'EngineIon',
|
||||
'parachute-1': 'ParachuteCanister',
|
||||
'nosecone-1': 'NoseCone',
|
||||
'rcs-1': 'RcsBlock',
|
||||
'solar-1': 'SolarPanelBase',
|
||||
'battery-0': 'Battery',
|
||||
'dock-1': 'DockingConnector',
|
||||
'port-1': 'DockingPort',
|
||||
'lander-1': 'LanderLegPreview'}
|
||||
part_type_sprite: Dict[str, str] = {
|
||||
"pod-1": "Pod",
|
||||
"detacher-1": "DetacherVertical",
|
||||
"detacher-2": "DetacherRadial",
|
||||
"wheel-1": "Wheel",
|
||||
"wheel-2": "Wheel",
|
||||
"fuselage-1": "Fuselage",
|
||||
"strut-1": "Beam",
|
||||
"fueltank-0": "TankTiny",
|
||||
"fueltank-1": "TankSmall",
|
||||
"fueltank-2": "TankMedium",
|
||||
"fueltank-3": "TankLarge",
|
||||
"fueltank-4": "Puffy750",
|
||||
"fueltank-5": "SideTank",
|
||||
"engine-0": "EngineTiny",
|
||||
"engine-1": "EngineSmall",
|
||||
"engine-2": "EngineMedium",
|
||||
"engine-3": "EngineLarge",
|
||||
"engine-4": "SolidRocketBooster",
|
||||
"ion-0": "EngineIon",
|
||||
"parachute-1": "ParachuteCanister",
|
||||
"nosecone-1": "NoseCone",
|
||||
"rcs-1": "RcsBlock",
|
||||
"solar-1": "SolarPanelBase",
|
||||
"battery-0": "Battery",
|
||||
"dock-1": "DockingConnector",
|
||||
"port-1": "DockingPort",
|
||||
"lander-1": "LanderLegPreview",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_textures_from_type(cls, name: str) -> Union[None, str]:
|
||||
@ -118,7 +121,7 @@ class SR1Rotation(Options):
|
||||
0.0: 0,
|
||||
1.570796: 270,
|
||||
3.141593: 180,
|
||||
4.712389: 90
|
||||
4.712389: 90,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@ -131,4 +134,4 @@ class SR1Rotation(Options):
|
||||
if radian in cls.radian_angle_map:
|
||||
return cls.radian_angle_map[radian]
|
||||
else:
|
||||
return (radian / math.pi) * 180
|
||||
return (radian / math.pi) * 180
|
||||
|
@ -16,20 +16,23 @@ import unittest
|
||||
from Difficult_Rocket.client.guis.format import html
|
||||
|
||||
try_texts = [
|
||||
'明天天气很好',
|
||||
'从前有座山,山里有座庙, **is it**?',
|
||||
'啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。阿巴巴巴',
|
||||
'阿瓦达达瓦的,aiwdhaihdwia.awdaiwhdahwido[12312](123131)',
|
||||
'1231231dawdawd65ewwe56er56*awdadad*aaa**阿伟大的阿瓦打我的**',
|
||||
'adwiuahiaa奥迪帮我auawuawdawdadw阿达达瓦aawd 2313',
|
||||
'阿松大阿瓦达达娃啊aawadaawdawd阿瓦达达娃'
|
||||
"明天天气很好",
|
||||
"从前有座山,山里有座庙, **is it**?",
|
||||
"啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。阿巴巴巴",
|
||||
"阿瓦达达瓦的,aiwdhaihdwia.awdaiwhdahwido[12312](123131)",
|
||||
"1231231dawdawd65ewwe56er56*awdadad*aaa**阿伟大的阿瓦打我的**",
|
||||
"adwiuahiaa奥迪帮我auawuawdawdadw阿达达瓦aawd 2313",
|
||||
"阿松大阿瓦达达娃啊aawadaawdawd阿瓦达达娃",
|
||||
]
|
||||
|
||||
|
||||
class HtmlFormatTest(unittest.TestCase):
|
||||
def test1_format_texts(self):
|
||||
self.assertEqual(html.decode_text2HTML('明天天气很好'), '<font face="" color=white>明天天气很好</font>')
|
||||
self.assertEqual(
|
||||
html.decode_text2HTML("明天天气很好"),
|
||||
'<font face="" color=white>明天天气很好</font>',
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user