first part for phy simluation #34

Merged
shenjackyuanjie merged 19 commits from dr_game/phy_simluation into main 2023-06-22 02:11:47 +08:00
50 changed files with 1206 additions and 2086 deletions
Showing only changes of commit 0673ba6981 - Show all commits

View File

@ -10,13 +10,10 @@ import rtoml
sys.path.append(os.path.abspath(os.curdir)) sys.path.append(os.path.abspath(os.curdir))
from Difficult_Rocket import DR_runtime from Difficult_Rocket import DR_status
args = ['-env', '-github-dev'] args = ['-env', '-github-dev']
# print(sys.argv)
if sys.argv == [__file__]: # 没有输入参数,直接输出默认信息并输出 if sys.argv == [__file__]: # 没有输入参数,直接输出默认信息并输出
print(sys.version) print(sys.version)
@ -29,13 +26,9 @@ if sys.argv == [__file__]: # 没有输入参数,直接输出默认信息并
elif os.path.abspath(os.curdir) in sys.path and '-env' in sys.argv: 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: with open('./.github/workflows/env.ps1', encoding='utf-8', mode='w') as env_file:
print(f'$env:DR_version = "{DR_runtime.DR_version}"', file=env_file) print(f'$env:DR_version = "{DR_status.DR_version}"', file=env_file)
print(f'$env:DR_language = "{DR_runtime.language}"', file=env_file) print(f'$env:Build_version = "{DR_status.Build_version}"', file=env_file)
print(f'$env:DR_long_version = "{DR_runtime.DR_long_version}"', file=env_file)
print(f'$env:Build_version = "{DR_runtime.Build_version}"', file=env_file)
elif os.path.abspath(os.curdir) in sys.path and '-github' in sys.argv: elif os.path.abspath(os.curdir) in sys.path and '-github' in sys.argv:
print(f'DR_version={DR_runtime.DR_version}') print(f'DR_version={DR_status.DR_version}')
print(f'DR_language={DR_runtime.language}') print(f'Build_version={DR_status.Build_version}')
print(f'DR_long_version={DR_runtime.DR_long_version}')
print(f'Build_version={DR_runtime.Build_version}')

15
DR.py
View File

@ -52,21 +52,14 @@ def main() -> int:
from Difficult_Rocket.exception import TestError from Difficult_Rocket.exception import TestError
from Difficult_Rocket import crash from Difficult_Rocket import crash
from Difficult_Rocket import DR_option from Difficult_Rocket import DR_status
try:
from libs.pyglet_rs import get_version_str, patch_vector
print('pyglet_rs available:', get_version_str())
print('trying to patch pyglet_rs')
patch_vector()
except ImportError:
print('pyglet_rs import error')
traceback.print_exc()
try: try:
from libs import pyglet # 导入pyglet from libs import pyglet # 导入pyglet
pyglet.resource.path = ['/textures/'] pyglet.resource.path = ['/textures/']
pyglet.resource.reindex() pyglet.resource.reindex()
from Difficult_Rocket import main, DR_runtime from Difficult_Rocket import main
from Difficult_Rocket.runtime import DR_runtime
DR_runtime.start_time_ns = start_time_ns DR_runtime.start_time_ns = start_time_ns
# from pyglet.gl import glClearColor # 调整背景颜色 # from pyglet.gl import glClearColor # 调整背景颜色
@ -80,7 +73,7 @@ def main() -> int:
cProfile.run('game.start()', sort='calls') # 使用 cprofile 启动 cProfile.run('game.start()', sort='calls') # 使用 cprofile 启动
else: else:
game.start() # 直接启动 game.start() # 直接启动
if DR_option.crash_report_test: if DR_status.crash_report_test:
raise TestError('debugging') # debug 嘛试试crash raise TestError('debugging') # debug 嘛试试crash
except Exception as exp: # 出毛病了 except Exception as exp: # 出毛病了
# 解析错误信息 # 解析错误信息

View File

@ -4,58 +4,46 @@
# All rights reserved # All rights reserved
# ------------------------------- # -------------------------------
import sys
import importlib
import traceback
import contextlib
import importlib.util
from pathlib import Path
from typing import Optional, List, Tuple
from Difficult_Rocket.api.types import Options, Version from Difficult_Rocket.api.types import Options, Version
game_version = Version("0.8.2.0") # 游戏版本 game_version = Version("0.8.3.0") # 游戏版本
build_version = Version("2.1.0.0") # 编译文件版本(与游戏本体无关) build_version = Version("2.1.0.0") # 编译文件版本(与游戏本体无关)
Api_version = Version("0.1.1.0") # API 版本 Api_version = Version("0.1.1.0") # API 版本
__version__ = game_version __version__ = game_version
long_version: int = 15
""" __all__ = [
long_version: 一个用于标记内部协议的整数 # __init__
15: 完全移除 DR_rust 相关内容 解耦完成 'DR_status',
14: BaseScreen 的每一个函数都添加了一个参数: window: "ClientWindow" # folder
13: DR_runtime 添加 API_version 'api',
12: 去除 DR_runtime global_logger 'client',
logging 自己拿去 'server',
11: DR_option 添加 use_DR_rust 'command',
修复了一些拼写错误 'crash',
10: DR_runtime 添加 DR_Rust_get_version 'exception',
9 : DR_option 添加 pyglet_macosx_dev_test 'mod',
8 : DR_runtime 添加 DR_rust_version 'utils',
DR_option 添加 DR_rust_available # file
以后就有 DR_rust 'main',
7 : DR_option 添加 std_font_size 'runtime',
6 : 事实证明, 不如直接用int ]
5 : 添加 build_version 信息,用于标记编译文件版本,
游戏版本改为四位数终于有一个可以让我随便刷的版本号位数了
4 : translate 的字体常量位置改了一下,顺便调换顺序
3 : 就是试试改一下正好 compiler 要用
2 : longlong 好耶
1 : 我可算想起来还有这回事了 v0.6.4
"""
class _DR_option(Options): class _DR_status(Options):
""" """
DR 一般配置/状态 DR 的特性开关 / 基本状态
""" """
name = 'DR Option' name = 'DR Option'
# runtime options # run status
client_running: bool = False
server_running: bool = False
# feature switch
InputBox_use_TextEntry: bool = True InputBox_use_TextEntry: bool = True
record_threads: bool = True record_threads: bool = True
report_translate_not_found: bool = True report_translate_not_found: bool = True
use_multiprocess: bool = False use_multiprocess: bool = False
DR_rust_available: bool = False
use_cProfile: bool = False use_cProfile: bool = False
use_local_logging: bool = False use_local_logging: bool = False
@ -64,6 +52,14 @@ class _DR_option(Options):
debugging: bool = False debugging: bool = False
crash_report_test: bool = False crash_report_test: bool = False
# game version status
DR_version: Version = game_version # DR SDK 版本
Build_version: Version = build_version # DR 构建 版本
API_version: Version = Api_version # DR SDK API 版本
# game options
default_language: str = 'zh-CN'
# window option # window option
gui_scale: float = 1.0 # default 1.0 2.0 -> 2x 3 -> 3x gui_scale: float = 1.0 # default 1.0 2.0 -> 2x 3 -> 3x
@ -72,79 +68,9 @@ class _DR_option(Options):
return round(12 * self.gui_scale) return round(12 * self.gui_scale)
class _DR_runtime(Options): DR_status = _DR_status()
"""
DR 的运行时配置/状态
"""
name = 'DR Runtime'
# game version status
DR_version: Version = game_version # DR SDK 版本
Build_version: Version = build_version # DR 构建 版本
API_version: Version = Api_version # DR SDK API 版本 if DR_status.playing:
DR_long_version: int = long_version # DR SDK 内部协议版本 (不要问我为什么不用 Version我也在考虑
DR_Mod_List: List[Tuple[str, Version]] = [] # DR Mod 列表 (name, version)
# run status
running: bool = False
start_time_ns: Optional[int] = None
client_setup_cause_ns: Optional[int] = None
server_setup_cause_ns: Optional[int] = None
# game runtimes
# global_logger: logging.Logger
# game options
mod_path: str = './mods'
language: str = 'zh-CN'
default_language: str = 'zh-CN'
def load_file(self) -> bool:
with contextlib.suppress(FileNotFoundError):
with open('./configs/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']
return True
return False
def find_mods(self) -> List[str]:
mods = []
mod_path = Path(self.mod_path)
if not mod_path.exists():
mod_path.mkdir()
return []
paths = mod_path.iterdir()
sys.path.append(self.mod_path)
for mod_path in paths:
try:
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
if importlib.util.find_spec(mod_path.name) is not None:
mods.append(mod_path.name)
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}')
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}')
traceback.print_exc()
return mods
DR_option = _DR_option()
DR_runtime = _DR_runtime()
if DR_option.playing:
from Difficult_Rocket.utils.thread import new_thread from Difficult_Rocket.utils.thread import new_thread
def think_it(something): def think_it(something):

View File

@ -12,6 +12,13 @@ gitee: @shenjackyuanjie
""" """
# from Difficult_Rocket.api import screen, mod, exception __all__ = [
'exception',
__all__ = ['screen', 'mod', 'exception'] # 错误类定义
'screen',
# screen api
'types',
# 类型定义
'mod',
# mod api
]

View File

@ -29,11 +29,12 @@ from pyglet.window import key, mouse
# Difficult_Rocket function # Difficult_Rocket function
if TYPE_CHECKING: if TYPE_CHECKING:
from Difficult_Rocket.main import Game from Difficult_Rocket.main import Game
from Difficult_Rocket import DR_status
from Difficult_Rocket.utils import tools from Difficult_Rocket.utils import tools
from Difficult_Rocket.api.types import Options
from Difficult_Rocket.command import line from Difficult_Rocket.command import line
from Difficult_Rocket.api.types import Options
from Difficult_Rocket.utils.translate import tr from Difficult_Rocket.utils.translate import tr
from Difficult_Rocket import DR_runtime from Difficult_Rocket.runtime import DR_runtime
from Difficult_Rocket.api.screen import BaseScreen from Difficult_Rocket.api.screen import BaseScreen
from Difficult_Rocket.utils.thread import new_thread from Difficult_Rocket.utils.thread import new_thread
from Difficult_Rocket.client.fps.fps_log import FpsLogger from Difficult_Rocket.client.fps.fps_log import FpsLogger
@ -42,6 +43,9 @@ from Difficult_Rocket.exception.language import LanguageNotFound
from Difficult_Rocket.client.screen import DRScreen, DRDEBUGScreen from Difficult_Rocket.client.screen import DRScreen, DRDEBUGScreen
logger = logging.getLogger('client')
class ClientOption(Options): class ClientOption(Options):
fps: int = 60 fps: int = 60
width: int = 1024 width: int = 1024
@ -51,7 +55,7 @@ class ClientOption(Options):
resizeable: bool = True resizeable: bool = True
visible: bool = True visible: bool = True
gui_scale: float = 1.0 gui_scale: float = 1.0
caption: str = "Difficult Rocket v{DR_version}|DR_rs v{DR_Rust_get_version}" caption: str = "Difficult Rocket v{DR_version}"
def load_file(self) -> None: def load_file(self) -> None:
file: dict = tools.load_file('./configs/main.toml') file: dict = tools.load_file('./configs/main.toml')
@ -61,7 +65,8 @@ class ClientOption(Options):
self.fullscreen = tools.format_bool(file['window']['full_screen']) self.fullscreen = tools.format_bool(file['window']['full_screen'])
self.resizeable = tools.format_bool(file['window']['resizable']) self.resizeable = tools.format_bool(file['window']['resizable'])
self.gui_scale = float(file['window']['gui_scale']) self.gui_scale = float(file['window']['gui_scale'])
self.caption = DR_runtime.format(file['window']['caption']) self.caption = DR_status.format(file['window']['caption'])
self.caption = DR_runtime.format(self.caption)
class Client: class Client:
@ -105,9 +110,15 @@ def pyglet_load_fonts_folder(folder) -> None:
file_folder_list = os.listdir(folder) file_folder_list = os.listdir(folder)
for obj in file_folder_list: for obj in file_folder_list:
if os.path.isfile(os.path.join(folder, obj)): if os.path.isfile(os.path.join(folder, obj)):
if obj[-4:] == '.ttf': if obj[-4:] == '.ttf' or obj[-4:] == '.otf':
logger.debug(f'loading font {os.path.join(folder, obj)}')
try:
pyglet.font.add_file(os.path.join(folder, obj)) pyglet.font.add_file(os.path.join(folder, obj))
except Exception:
logger.error(traceback.format_exc())
logger.error(f'loading font {os.path.join(folder, obj)} failed')
else: else:
logger.info(f'loading font folder {os.path.join(folder, obj)}')
pyglet_load_fonts_folder(os.path.join(folder, obj)) pyglet_load_fonts_folder(os.path.join(folder, obj))
@ -223,7 +234,7 @@ class ClientWindow(Window):
print("==========client stop. KeyboardInterrupt info==========") print("==========client stop. KeyboardInterrupt info==========")
traceback.print_exc() traceback.print_exc()
print("==========client stop. KeyboardInterrupt info end==========") print("==========client stop. KeyboardInterrupt info end==========")
self.dispatch_event("on_close") self.dispatch_event("on_close", 'input')
sys.exit(0) sys.exit(0)
@new_thread('window save_info') @new_thread('window save_info')
@ -388,7 +399,7 @@ class ClientWindow(Window):
if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK | if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
key.MOD_CAPSLOCK | key.MOD_CAPSLOCK |
key.MOD_SCROLLLOCK)): key.MOD_SCROLLLOCK)):
self.dispatch_event('on_close') self.dispatch_event('on_close', 'window')
if symbol == key.SLASH: if symbol == key.SLASH:
self.input_box._set_focus(True) self.input_box._set_focus(True)
self.logger.debug( self.logger.debug(

View File

@ -31,7 +31,7 @@ from pyglet.text.layout import IncrementalTextLayout
from Difficult_Rocket.api.types import FontData, Fonts from Difficult_Rocket.api.types import FontData, Fonts
# from Difficult_Rocket.client.guis.format import html # from Difficult_Rocket.client.guis.format import html
from Difficult_Rocket import DR_option from Difficult_Rocket import DR_status
__all__ = ['InputBox'] __all__ = ['InputBox']
@ -59,7 +59,7 @@ class TextButton(widgets.WidgetBase):
... ...
if not DR_option.InputBox_use_TextEntry: if not DR_status.InputBox_use_TextEntry:
class InputBox(widgets.TextEntry): class InputBox(widgets.TextEntry):
""" 自定义的输入框 """ """ 自定义的输入框 """
@ -134,7 +134,7 @@ if not DR_option.InputBox_use_TextEntry:
# dpi=font_dpi) # dpi=font_dpi)
# self.font_height = self.font.ascent - self.font.descent # self.font_height = self.font.ascent - self.font.descent
# self.out_bound = out_line # self.out_bound = out_line
# if DR_option.InputBox_use_TextEntry: # if DR_status.InputBox_use_TextEntry:
# # 基于IncrementalTextLayout的处理系统 # # 基于IncrementalTextLayout的处理系统
# self._doc = FormattedDocument(message) # self._doc = FormattedDocument(message)
# # self._doc.set_style() # # self._doc.set_style()

View File

@ -99,14 +99,15 @@ def write_cache(cache_stream, crash_info):
def write_info_to_cache(cache_stream): def write_info_to_cache(cache_stream):
# 运行状态信息 # 运行状态信息
from Difficult_Rocket import DR_option, DR_runtime from Difficult_Rocket import DR_status
from Difficult_Rocket.runtime import DR_runtime
cache_stream.write(Run_message) cache_stream.write(Run_message)
cache_stream.write(markdown_line_handler(f'DR Version: {Difficult_Rocket.game_version}', level=1)) cache_stream.write(markdown_line_handler(f'DR Version: {Difficult_Rocket.game_version}', level=1))
cache_stream.write(markdown_line_handler(f'DR language: {DR_runtime.language}', 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'Running Dir: {Path(os.curdir).resolve()}', level=1))
cache_stream.write(f"\n{DR_runtime.as_markdown()}") cache_stream.write(f"\n{DR_runtime.as_markdown()}")
cache_stream.write(DR_configs) cache_stream.write(DR_configs)
cache_stream.write(f"\n{DR_option.as_markdown()}") cache_stream.write(f"\n{DR_status.as_markdown()}")
cache_stream.write(Process_message) cache_stream.write(Process_message)
for process in all_process: for process in all_process:
process: multiprocessing.Process process: multiprocessing.Process

View File

@ -24,10 +24,6 @@ from io import StringIO
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, List, Optional, Dict, TypeVar from typing import TYPE_CHECKING, List, Optional, Dict, TypeVar
if __name__ == '__main__': # been start will not run this
sys.path.append('/bin/libs')
sys.path.append('/bin')
if TYPE_CHECKING: if TYPE_CHECKING:
from Difficult_Rocket.api.mod import ModInfo from Difficult_Rocket.api.mod import ModInfo
else: else:
@ -35,9 +31,10 @@ else:
from Difficult_Rocket.utils import tools from Difficult_Rocket.utils import tools
from Difficult_Rocket.api.types import Options from Difficult_Rocket.api.types import Options
from Difficult_Rocket.utils.translate import tr from Difficult_Rocket.utils.translate import tr
from Difficult_Rocket.runtime import DR_runtime
from Difficult_Rocket.utils.thread import new_thread from Difficult_Rocket.utils.thread import new_thread
from Difficult_Rocket.crash import write_info_to_cache from Difficult_Rocket.crash import write_info_to_cache
from Difficult_Rocket import client, server, DR_option, DR_runtime from Difficult_Rocket import client, server, DR_status
class Console(Options): class Console(Options):
@ -154,7 +151,7 @@ class Game(Options):
def start(self): def start(self):
self.server.run() self.server.run()
if DR_option.use_multiprocess: if DR_status.use_multiprocess:
try: 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.start()

View File

@ -12,9 +12,9 @@ gitee: @shenjackyuanjie
""" """
# system function # system function
import warnings
from typing import Tuple, List, Optional, TypeVar, TYPE_CHECKING from typing import Tuple, List, Optional, TypeVar, TYPE_CHECKING
# from DR # from DR
if TYPE_CHECKING: if TYPE_CHECKING:
from Difficult_Rocket.main import Game from Difficult_Rocket.main import Game
@ -22,7 +22,7 @@ if TYPE_CHECKING:
else: else:
Game = TypeVar("Game") Game = TypeVar("Game")
ClientWindow = TypeVar("ClientWindow") ClientWindow = TypeVar("ClientWindow")
from Difficult_Rocket import DR_runtime from Difficult_Rocket import DR_status
from Difficult_Rocket.api.types import Options, Version from Difficult_Rocket.api.types import Options, Version
RequireVersion = Tuple[Version, Version] RequireVersion = Tuple[Version, Version]
@ -47,8 +47,8 @@ class ModInfo(Options):
info: str = "" # 其他信息 (可以很多很多) info: str = "" # 其他信息 (可以很多很多)
"""版本相关信息""" """版本相关信息"""
DR_version: RequireVersion = (DR_runtime.DR_version, DR_runtime.DR_version) # DR SDK 兼容版本 DR_version: RequireVersion = (DR_status.DR_version, DR_status.DR_version) # DR SDK 兼容版本
DR_Api_version: RequireVersion = (DR_runtime.API_version, DR_runtime.API_version) # DR Api版本 DR_Api_version: RequireVersion = (DR_status.API_version, DR_status.API_version) # DR Api版本
Mod_Require_version: List[Tuple[str, ForceRequire, RequireVersion]] = [] # mod 依赖版本 Mod_Require_version: List[Tuple[str, ForceRequire, RequireVersion]] = [] # mod 依赖版本
"""mod 状态""" """mod 状态"""
@ -59,9 +59,15 @@ class ModInfo(Options):
config: Options = Options() # mod 配置存储 config: Options = Options() # mod 配置存储
old_mod: Optional["ModInfo"] = None # 旧的mod实例 old_mod: Optional["ModInfo"] = None # 旧的mod实例
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}\nDR {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}\nDR {self.DR_Api_version} is required")
super().__init__(**kwargs)
def on_load(self, game: Game, old_self: Optional["ModInfo"] = None) -> bool: def on_load(self, game: Game, old_self: Optional["ModInfo"] = None) -> bool:
""" 加载时调用 """ """ 加载时调用 """
print(f'Mod {self.mod_id} loaded')
return True return True
def on_client_start(self, game: Game, client: ClientWindow): def on_client_start(self, game: Game, client: ClientWindow):

View File

@ -11,12 +11,11 @@ from typing import List, Dict, Optional
from Difficult_Rocket.api.screen import BaseScreen from Difficult_Rocket.api.screen import BaseScreen
from Difficult_Rocket.api.types import Options, Version from Difficult_Rocket.api.types import Options, Version
from Difficult_Rocket.mod.api import ModInfo from Difficult_Rocket.mod.api import ModInfo
# from Difficult_Rocket import DR_option, DR_runtime # from Difficult_Rocket import DR_status, DR_runtime
class ModManager(Options): class ModManager(Options):
name = 'Mod Manager' name = 'Mod Manager'
logger: logging.Logger
mods_path: List[Path] = [Path('./mods')] mods_path: List[Path] = [Path('./mods')]
loaded_mod_modules: Dict[str, ModInfo] = {} loaded_mod_modules: Dict[str, ModInfo] = {}

View File

@ -0,0 +1,79 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import sys
import importlib
import traceback
import contextlib
import importlib.util
from pathlib import Path
from typing import Optional, List, Tuple
from Difficult_Rocket.api.types import Options, Version
__all__ = [
'DR_runtime'
]
class _DR_runtime(Options):
"""
DR 的运行时配置 / 状态
"""
name = 'DR Runtime'
language: str = 'zh-CN'
mod_path: str = './mods'
DR_Mod_List: List[Tuple[str, Version]] = [] # DR Mod 列表 (name, version)
# run status
start_time_ns: Optional[int] = None
client_setup_cause_ns: Optional[int] = None
server_setup_cause_ns: Optional[int] = None
def load_file(self) -> bool:
with contextlib.suppress(FileNotFoundError):
with open('./configs/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']
return True
return False
def find_mods(self) -> List[str]:
mods = []
mod_path = Path(self.mod_path)
if not mod_path.exists():
mod_path.mkdir()
return []
paths = mod_path.iterdir()
sys.path.append(self.mod_path)
for mod_path in paths:
try:
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
if importlib.util.find_spec(mod_path.name) is not None:
mods.append(mod_path.name)
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}')
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}')
traceback.print_exc()
return mods
DR_runtime = _DR_runtime()

View File

@ -9,13 +9,15 @@ from io import StringIO
from dataclasses import dataclass from dataclasses import dataclass
from typing import get_type_hints, Type, List, Union, Dict, Any, Callable, Tuple, Optional, TYPE_CHECKING, Iterable from typing import get_type_hints, Type, List, Union, Dict, Any, Callable, Tuple, Optional, TYPE_CHECKING, Iterable
__all__ = ['get_type_hints_', __all__ = [
'get_type_hints_',
'Options', 'Options',
'Fonts',
'FontData',
'OptionsError', 'OptionsError',
'OptionNotFound', 'OptionNotFound',
'OptionNameNotDefined'] 'OptionNameNotDefined',
'Fonts',
'FontData'
]
def get_type_hints_(cls: Type): def get_type_hints_(cls: Type):
@ -137,13 +139,22 @@ class Options:
raise OptionNotFound(f'Option {option} is not found in {self.name}') from None raise OptionNotFound(f'Option {option} is not found in {self.name}') from None
return values return values
def str_option(self) -> Dict[str, Union[str, Any]]: def str_option(self, shrink_to_long: Optional[int] = None) -> Dict[str, Union[str, Any]]:
""" """
获取配置类的所有配置 并将所有非 BuiltInType 的值转换为 str 获取配置类的所有配置 并将所有非 BuiltIn 类型的值转换为 str
:return: :return:
""" """
raw_option = self.option() raw_option = self.option()
return to_str_value_(raw_option) str_option = to_str_value_(raw_option)
if shrink_to_long is None:
return str_option
if not isinstance(shrink_to_long, int) or shrink_to_long <= 0:
return str_option
for option, value in str_option.items():
if value is not None:
if len(str(value)) > shrink_to_long:
str_option[option] = str(value)[:shrink_to_long] + '...'
return str_option
def format(self, text: str) -> str: def format(self, text: str) -> str:
""" """
@ -164,12 +175,15 @@ class Options:
self.cached_options = self.option() self.cached_options = self.option()
return self.cached_options return self.cached_options
def option_with_len(self) -> Tuple[List[Tuple[str, Union[Any, Type], Type]], int, int, int]: def option_with_len(self, longest: Optional[int] = None) -> Tuple[List[Tuple[str, Union[Any, Type], Type]], int, int, int]:
""" """
返回一个可以用于打印的 option 列表 返回一个可以用于打印的 option 列表
:return: :return:
""" """
if longest is None:
options = self.flush_option() options = self.flush_option()
else:
options = self.str_option(longest)
max_len_key = 1 max_len_key = 1
max_len_value = 1 max_len_value = 1
max_len_value_t = 1 max_len_value_t = 1
@ -182,12 +196,12 @@ class Options:
option_list.append((key, value, value_t)) option_list.append((key, value, value_t))
return option_list, max_len_key, max_len_value, max_len_value_t return option_list, max_len_key, max_len_value, max_len_value_t
def as_markdown(self) -> str: def as_markdown(self, longest: Optional[int] = None) -> str:
""" """
返回一个 markdown 格式的 option 字符串 返回一个 markdown 格式的 option 字符串
:return: markdown 格式的 option 字符串 :return: markdown 格式的 option 字符串
""" """
value = self.option_with_len() value = self.option_with_len(longest)
cache = StringIO() cache = StringIO()
option_len = max(value[1], len('Option')) option_len = max(value[1], len('Option'))
value_len = max(value[2], len('Value')) value_len = max(value[2], len('Value'))

View File

@ -17,8 +17,9 @@ import inspect
from dataclasses import dataclass from dataclasses import dataclass
from typing import Union, Tuple, Any, List, Dict, Hashable, Optional from typing import Union, Tuple, Any, List, Dict, Hashable, Optional
from Difficult_Rocket import DR_runtime, DR_option from Difficult_Rocket import DR_status
from Difficult_Rocket.utils import tools from Difficult_Rocket.utils import tools
from Difficult_Rocket.runtime import DR_runtime
from Difficult_Rocket.exception.language import (LanguageNotFound, from Difficult_Rocket.exception.language import (LanguageNotFound,
TranslateKeyNotFound) TranslateKeyNotFound)
@ -82,7 +83,7 @@ class Translates:
def _raise_no_value(self, e: Exception, item: key_type): def _raise_no_value(self, e: Exception, item: key_type):
if self._config.raise_error: 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_option.report_translate_not_found: elif DR_status.report_translate_not_found:
frame = inspect.currentframe() frame = inspect.currentframe()
if frame is not None: if frame is not None:
frame = frame.f_back.f_back frame = frame.f_back.f_back
@ -160,7 +161,7 @@ class Tr:
""" """
self.language_name = language if language is not None else DR_runtime.language self.language_name = language if language is not None else DR_runtime.language
self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'configs/lang/{self.language_name}.toml') self.translates: Dict[str, Union[str, Dict]] = tools.load_file(f'configs/lang/{self.language_name}.toml')
self.default_translate: Dict = tools.load_file(f'configs/lang/{DR_runtime.default_language}.toml') self.default_translate: Dict = tools.load_file(f'configs/lang/{DR_status.default_language}.toml')
self.default_config = config.set('source', self) if config is not None else TranslateConfig(source=self) self.default_config = config.set('source', self) if config is not None else TranslateConfig(source=self)
self.translates_cache = Translates(value=self.translates, config=self.default_config.copy()) self.translates_cache = Translates(value=self.translates, config=self.default_config.copy())

View File

@ -19,9 +19,9 @@
[关于版本号的说明](./docs/src/version.md) [关于版本号的说明](./docs/src/version.md)
[![Generic badge](https://img.shields.io/badge/Release-0.8.2.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases) [![Generic badge](https://img.shields.io/badge/Release-0.8.3.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![Generic badge](https://img.shields.io/badge/Pre_Release-0.8.2.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases) [![Generic badge](https://img.shields.io/badge/Pre_Release-0.8.3.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![Generic badge](https://img.shields.io/badge/Devloping-0.8.3-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases) [![Generic badge](https://img.shields.io/badge/Devloping-0.8.4-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![language badge](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark) [![language badge](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)

View File

@ -7,7 +7,6 @@ env.version.python = "Python version: {}"
env.version.DR = "Difficult_Rocket version: {}" env.version.DR = "Difficult_Rocket version: {}"
env.version.DR_rs = "Difficult_Rocket_rs version: {}" env.version.DR_rs = "Difficult_Rocket_rs version: {}"
env.version.pyglet = "pyglet version: {}" env.version.pyglet = "pyglet version: {}"
env.version.pyglet_rs = "pyglet_rs version: {}"
version.now_on = "Difficult Rocket is running on Python Vision" version.now_on = "Difficult Rocket is running on Python Vision"
version.need3p = "Difficult Rocket depends on Python vision 3.0+" version.need3p = "Difficult Rocket depends on Python vision 3.0+"
version.best38p = "Difficult Rocket is writen in Python {write_py_v}, and now is running on Python {py_v} may cause BUG" version.best38p = "Difficult Rocket is writen in Python {write_py_v}, and now is running on Python {py_v} may cause BUG"
@ -30,6 +29,7 @@ mod.load.info = "mod id: {} version: {}"
mod.load.faild.info = "Mod load failed: {} error info: {}" mod.load.faild.info = "Mod load failed: {} error info: {}"
mod.load.faild.no_mod_class = "Can't find Mod class" mod.load.faild.no_mod_class = "Can't find Mod class"
mod.load.done = "All Mod loaded" mod.load.done = "All Mod loaded"
mod.event.error = "Mod evenet {} caught error: {} Mod: {}"
[client] [client]
setup.start = "Client start loading" setup.start = "Client start loading"
@ -72,8 +72,8 @@ os.pid_is = "Server PID: {} PPID: {}"
[game] [game]
input = "console" input = "console"
command = "in game commands"
window = "window" window = "window"
command = "in game commands"
require_DR_rs = "require DR_rs module" require_DR_rs = "require DR_rs module"
[client.sr1_render] [client.sr1_render]

View File

@ -7,7 +7,6 @@ env.version.python = "Python 版本: {}"
env.version.DR = "Difficult_Rocket 版本: {}" env.version.DR = "Difficult_Rocket 版本: {}"
env.version.DR_rs = "Difficult_Rocket_rs 版本: {}" env.version.DR_rs = "Difficult_Rocket_rs 版本: {}"
env.version.pyglet = "pyglet 版本: {}" env.version.pyglet = "pyglet 版本: {}"
env.version.pyglet_rs = "pyglet_rs 版本: {}"
version.now_on = "困难火箭的运行 Python 环境为" version.now_on = "困难火箭的运行 Python 环境为"
version.need3p = "困难火箭需要 Python3.0+ 的环境" version.need3p = "困难火箭需要 Python3.0+ 的环境"
version.best38p = "困难火箭是在 Python {write_py_v} 的环境下编写的目前正在运行在Python {py_v}的环境下可能产生BUG" version.best38p = "困难火箭是在 Python {write_py_v} 的环境下编写的目前正在运行在Python {py_v}的环境下可能产生BUG"
@ -73,8 +72,8 @@ os.pid_is = "服务端 PID: {} PPID: {}"
[game] [game]
input = "控制台" input = "控制台"
command = "游戏内命令行"
window = "窗口" window = "窗口"
command = "游戏内命令行"
require_DR_rs = "需要 DR_rs 模块" require_DR_rs = "需要 DR_rs 模块"
[client.sr1_render] [client.sr1_render]

View File

@ -1,31 +0,0 @@
{
'language': 'zh-cn',
'textures': {
'back_ground_space': 'back_ground_space.png',
'planet': {
'earth_ground': 'earth_ground.png'
},
'flame': {
'liquid': 'liquid_engine_flame.png',
'solid': 'solid_engine_flame.png',
'ion': 'ion_engine_flame.png'
}
},
'basic_number': {
'G': [
6.67,
-11,
[
'N',
'm',
'm'
],
[
'kg',
'kg'
]
]
},
'default ship': [
]
}

View File

@ -1,49 +0,0 @@
{
/*
'part id': [
[
'part name', // part name can be reuse
'description', // 描述
], // about names and other
[ 'float', // mass
'bool', // hidden in part list
'bool', // hidden in mission (even thought that is not done yet)
'float' // buoyancy(浮力) in the water
], // about config
[ 'xxx.png', // texture file name
//可以为包含文件夹的 比如:./engine/xxx.png
[ 'float', // 贴图偏移量
'float' ] // 指的是部件的碰撞箱左上角到贴图左上角的距离
], // about texture
[ 'float',
'float' ],
// 碰撞箱大小 (暂时只支持方形碰撞箱)
// 坐标轴也是从左下开始
[
'特殊值(懒得写)'
]
],
*/
'test1': [
[
'test-1',
'一个测试用部件'
],
[
1.0,
false,
0.1
],
[
'parts/Beam.png',
[
0.0,
0.0
]
],
[
3.0,
2.0
]
]
}

View File

@ -1,17 +0,0 @@
{
'Solar System': {
'description': '',
'planets': {
'earth': {
'description': '',
'gravity': 9.81,
'radius': 63710000,
'map_color': [
103,
157,
255
]
}
}
}
}

View File

@ -1,27 +0,0 @@
[Runtime]
[Parts]
battery = "Battery.png"
beam = "Beam.png"
cover_bottom = "CoverBottom.png"
nose_cone = "NoseCone.png"
[Editor]
[[runtime]]
"toolbar.dark" = "ToolbarDark.png"
"toolbar.light" = "ToolbarLight.png"
"button_side.dark" = "ButtonDarkSide.png"
"button_side.light" = "ButtonLightSide.png"
[[toggle_button]]
stage = "ToolbarIconStaging.png"
add_part = "ToolbarIconAddPart.png"
menu = "ToolbarIconMenu.png"
[[push_button]]
zoom = "ToolbarIconZoom.png"
"zoom.in" = "ToolbarIconZoomIn.png"
"zoom.out" = "ToolbarIconZoomOut.png"
play = "ToolbarIconPlay.png"
rotate = "RotateButton.png"
trash_can = "TrashCan.png"

View File

@ -19,9 +19,9 @@
[About Versions](src/version.md) [About Versions](src/version.md)
[![Generic badge](https://img.shields.io/badge/Release-0.8.2.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases) [![Generic badge](https://img.shields.io/badge/Release-0.8.3.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![Generic badge](https://img.shields.io/badge/Pre_Release-0.8.2.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases) [![Generic badge](https://img.shields.io/badge/Pre_Release-0.8.3.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![Generic badge](https://img.shields.io/badge/Devloping-0.8.3-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases) [![Generic badge](https://img.shields.io/badge/Devloping-0.8.4-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![language badge](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark) [![language badge](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)](https://stats.deeptrain.net/repo/shenjackyuanjie/Difficult-Rocket?theme=dark)

View File

@ -17,6 +17,7 @@
- [nuitka performents test](./nuitka/20221121_nuitka_performs.md) - [nuitka performents test](./nuitka/20221121_nuitka_performs.md)
- [nuitka options](./nuitka/20230116_nuitka_options.md) - [nuitka options](./nuitka/20230116_nuitka_options.md)
- [nuitka 1.3.7 compile options](./nuitka/nuitka_options_137.md) - [nuitka 1.3.7 compile options](./nuitka/nuitka_options_137.md)
- [nuitka 1.6.1 compile options](./nuitka/nuitka_options_161.md)
- [计划特性](./plan_features/README.md) - [计划特性](./plan_features/README.md)
- [格式](./plan_features/格式.md) - [格式](./plan_features/格式.md)

View File

@ -2,9 +2,15 @@
# DR game/DR rs 更新日志 # DR game/DR rs 更新日志
- 最新版本号 - 最新版本号
- DR game: 0.1.1.0 - DR game: 0.2.0.0
- DR rs: 0.2.10.1 - DR rs: 0.2.10.1
## DR game 0.2.0.0
### 适配
- 适配了 `DR_sdk` `0.8.3.0` 的修改
## DR game 0.1.1.0 ## DR game 0.1.1.0
### 添加 ### 添加

View File

@ -2,7 +2,86 @@
# DR SDK 更新日志 # DR SDK 更新日志
- 最新版本号 - 最新版本号
- DR sdk: 0.8.2.0 - DR sdk: 0.8.3.0
## DR sdk 0.8.3.1
### Fix
- issue #33 (https://github.com/shenjackyuanjie/Difficult-Rocket/issues/33)
- 修复了实际上并不会加载 `.otf` 格式的字体文件的问题
## DR sdk 0.8.3.0
### 删除
- `pyglet_rs`
- 事实证明这玩意没啥用
- Removed pyglet_rs
### Fix
- issue #31 (https://github.com/shenjackyuanjie/Difficult-Rocket/issues/31)
- 窗口标题不正确 (实际上是因为只使用 `DR_runtime` 进行格式化)
- Window title is incorrect
### 添加
- `DR_status`
- 实际上就是 `DR_runtime`
- `DR_runtime` -> `DR_status`
- `client_running`
- 客户端是否在运行
- Is client running
- `server_running`
- 服务器是否在运行
- Is server running
- Mod loader
- 添加了对支持版本号的 warnings
- Added warnings for supporting version numbers
### 移动
- `Difficult_Rocket.DR_runtime`
- `DR_version` -> `DR_status.DR_version`
- `API_version` -> `DR_status.API_version`
- `Build_version` -> `DR_status.Build_version`
- `default_language` -> `DR_status.default_language`
### 删除
- `Diffiuclt_Rocket.long_version`
- 不再使用整数标记版本号 (反正 `Version` 有一个完整的版本号比较机制)
- No longer use integer to mark version number (since `Version` has a complete version comparison mechanism)
- `Difficult_Rocket.DR_rust_available`
- 似乎我忘记删掉这个 `DR_rs` 的耦合了
```python
long_version: int = 15
"""
long_version: 一个用于标记内部协议的整数
15: 完全移除 DR_rust 相关内容 解耦完成
14: BaseScreen 的每一个函数都添加了一个参数: window: "ClientWindow"
13: 为 DR_runtime 添加 API_version
12: 去除 DR_runtime 的 global_logger
要 logging 自己拿去(
11: 为 DR_option 添加 use_DR_rust
修复了一些拼写错误
10: 为 DR_runtime 添加 DR_Rust_get_version
9 : 为 DR_option 添加 pyglet_macosx_dev_test
8 : 为 DR_runtime 添加 DR_rust_version
为 DR_option 添加 DR_rust_available
以后就有 DR_rust 了
7 : 为 DR_option 添加 std_font_size
6 : 事实证明, 不如直接用int
5 : 添加 build_version 信息,用于标记编译文件版本,
游戏版本改为四位数,终于有一个可以让我随便刷的版本号位数了
4 : 把 translate 的字体常量位置改了一下,顺便调换顺序
3 : 就是试试改一下,正好 compiler 要用
2 : 哦,对 longlong 好耶!
1 : 我可算想起来还有这回事了 v0.6.4
"""
```
## DR sdk 0.8.2.0 ## DR sdk 0.8.2.0

View File

@ -0,0 +1,629 @@
# nuitka 1.6.1 --help
``` text
Usage: __main__.py [--module] [--run] [options] main_module.py
Options:
--help show this help message and exit
--version Show version information and important details for bug
reports, then exit. Defaults to off.
--module Create an extension module executable instead of a
program. Defaults to off.
--standalone Enable standalone mode for output. This allows you to
transfer the created binary to other machines without
it using an existing Python installation. This also
means it will become big. It implies these option: "--
follow-imports" and "--python-flag=no_site". Defaults
to off.
--onefile On top of standalone mode, enable onefile mode. This
means not a folder, but a compressed executable is
created and used. Defaults to off.
--python-debug Use debug version or not. Default uses what you are
using to run Nuitka, most likely a non-debug version.
--python-flag=FLAG Python flags to use. Default is what you are using to
run Nuitka, this enforces a specific mode. These are
options that also exist to standard Python executable.
Currently supported: "-S" (alias "no_site"),
"static_hashes" (do not use hash randomization),
"no_warnings" (do not give Python run time warnings),
"-O" (alias "no_asserts"), "no_docstrings" (do not use
doc strings), "-u" (alias "unbuffered") and "-m".
Default empty.
--python-for-scons=PATH
If using Python3.3 or Python3.4, provide the path of a
Python binary to use for Scons. Otherwise Nuitka can
use what you run Nuitka with or a Python installation
from Windows registry. On Windows Python 3.5 or higher
is needed. On non-Windows, Python 2.6 or 2.7 will do
as well.
Control the inclusion of modules and packages in result:
--include-package=PACKAGE
Include a whole package. Give as a Python namespace,
e.g. "some_package.sub_package" and Nuitka will then
find it and include it and all the modules found below
that disk location in the binary or extension module
it creates, and make it available for import by the
code. To avoid unwanted sub packages, e.g. tests you
can e.g. do this "--nofollow-import-to=*.tests".
Default empty.
--include-module=MODULE
Include a single module. Give as a Python namespace,
e.g. "some_package.some_module" and Nuitka will then
find it and include it in the binary or extension
module it creates, and make it available for import by
the code. Default empty.
--include-plugin-directory=MODULE/PACKAGE
Include also the code found in that directory,
considering as if they are each given as a main file.
Overrides all other inclusion options. You ought to
prefer other inclusion options, that go by names,
rather than filenames, those find things through being
in "sys.path". This option is for very special use
cases only. Can be given multiple times. Default
empty.
--include-plugin-files=PATTERN
Include into files matching the PATTERN. Overrides all
other follow options. Can be given multiple times.
Default empty.
--prefer-source-code
For already compiled extension modules, where there is
both a source file and an extension module, normally
the extension module is used, but it should be better
to compile the module from available source code for
best performance. If not desired, there is --no-
prefer-source-code to disable warnings about it.
Default off.
Control the following into imported modules:
--follow-imports Descend into all imported modules. Defaults to on in
standalone mode, otherwise off.
--follow-import-to=MODULE/PACKAGE
Follow to that module if used, or if a package, to the
whole package. Can be given multiple times. Default
empty.
--nofollow-import-to=MODULE/PACKAGE
Do not follow to that module name even if used, or if
a package name, to the whole package in any case,
overrides all other options. Can be given multiple
times. Default empty.
--nofollow-imports Do not descend into any imported modules at all,
overrides all other inclusion options and not usable
for standalone mode. Defaults to off.
--follow-stdlib Also descend into imported modules from standard
library. This will increase the compilation time by a
lot and is also not well tested at this time and
sometimes won't work. Defaults to off.
Onefile options:
--onefile-tempdir-spec=ONEFILE_TEMPDIR_SPEC
Use this as a folder to unpack to in onefile mode.
Defaults to '%TEMP%/onefile_%PID%_%TIME%', i.e. user
temporary directory and being non-static it's removed.
Use e.g. a string like
'%CACHE_DIR%/%COMPANY%/%PRODUCT%/%VERSION%' which is a
good static cache path, this will then not be removed.
--onefile-child-grace-time=GRACE_TIME_MS
When stopping the child, e.g. due to CTRL-C or
shutdown, etc. the Python code gets a
"KeyboardInterrupt", that it may handle e.g. to flush
data. This is the amount of time in ms, before the
child it killed in the hard way. Unit is ms, and
default 5000.
--onefile-no-compression
When creating the onefile, disable compression of the
payload. This is mostly for debug purposes, or to save
time. Default is off.
Data files:
--include-package-data=PACKAGE
Include data files for the given package name. DLLs
and extension modules are not data files and never
included like this. Can use patterns the filenames as
indicated below. Data files of packages are not
included by default, but package configuration can do
it. This will only include non-DLL, non-extension
modules, i.e. actual data files. After a ":"
optionally a filename pattern can be given as well,
selecting only matching files. Examples: "--include-
package-data=package_name" (all files) "--include-
package-data=package_name=*.txt" (only certain type) "
--include-package-data=package_name=some_filename.dat
(concrete file) Default empty.
--include-data-files=DESC
Include data files by filenames in the distribution.
There are many allowed forms. With '--include-data-
files=/path/to/file/*.txt=folder_name/some.txt' it
will copy a single file and complain if it's multiple.
With '--include-data-
files=/path/to/files/*.txt=folder_name/' it will put
all matching files into that folder. For recursive
copy there is a form with 3 values that '--include-
data-files=/path/to/scan=folder_name=**/*.txt' that
will preserve directory structure. Default empty.
--include-data-dir=DIRECTORY
Include data files from complete directory in the
distribution. This is recursive. Check '--include-
data-files' with patterns if you want non-recursive
inclusion. An example would be '--include-data-
dir=/path/some_dir=data/some_dir' for plain copy, of
the whole directory. All files are copied, if you want
to exclude files you need to remove them beforehand,
or use '--noinclude-data-files' option to remove them.
Default empty.
--noinclude-data-files=PATTERN
Do not include data files matching the filename
pattern given. This is against the target filename,
not source paths. So to ignore a file pattern from
package data for "package_name" should be matched as
"package_name/*.txt". Or for the whole directory
simply use "package_name". Default empty.
--list-package-data=LIST_PACKAGE_DATA
Output the data files found for a given package name.
Default not done.
Metadata support:
--include-distribution-metadata=DISTRIBUTION
Include metadata information for the given
distribution name. Some packages check metadata for
presence, version, entry points, etc. and without this
option given, it only works when it's recognized at
compile time which is not always happening. This of
course only makes sense for packages that are included
in the compilation. Default empty.
DLL files:
--noinclude-dlls=PATTERN
Do not include DLL files matching the filename pattern
given. This is against the target filename, not source
paths. So ignore a DLL "someDLL" contained in the
package "package_name" it should be matched as
"package_name/someDLL.*". Default empty.
--list-package-dlls=LIST_PACKAGE_DLLS
Output the DLLs found for a given package name.
Default not done.
Control the warnings to be given by Nuitka:
--warn-implicit-exceptions
Enable warnings for implicit exceptions detected at
compile time.
--warn-unusual-code
Enable warnings for unusual code detected at compile
time.
--assume-yes-for-downloads
Allow Nuitka to download external code if necessary,
e.g. dependency walker, ccache, and even gcc on
Windows. To disable, redirect input from nul device,
e.g. "</dev/null" or "<NUL:". Default is to prompt.
--nowarn-mnemonic=MNEMONIC
Disable warning for a given mnemonic. These are given
to make sure you are aware of certain topics, and
typically point to the Nuitka website. The mnemonic is
the part of the URL at the end, without the HTML
suffix. Can be given multiple times and accepts shell
pattern. Default empty.
Immediate execution after compilation:
--run Execute immediately the created binary (or import the
compiled module). Defaults to off.
--debugger Execute inside a debugger, e.g. "gdb" or "lldb" to
automatically get a stack trace. Defaults to off.
--execute-with-pythonpath
When immediately executing the created binary or
module using '--run', don't reset 'PYTHONPATH'
environment. When all modules are successfully
included, you ought to not need PYTHONPATH anymore,
and definitely not for standalone mode.
Compilation choices:
--user-package-configuration-file=YAML_FILENAME
User provided Yaml file with package configuration.
You can include DLLs, remove bloat, add hidden
dependencies. Check User Manual for a complete
description of the format to use. Can be given
multiple times. Defaults to empty.
--full-compat Enforce absolute compatibility with CPython. Do not
even allow minor deviations from CPython behavior,
e.g. not having better tracebacks or exception
messages which are not really incompatible, but only
different or worse. This is intended for tests only
and should *not* be used.
--file-reference-choice=MODE
Select what value "__file__" is going to be. With
"runtime" (default for standalone binary mode and
module mode), the created binaries and modules, use
the location of themselves to deduct the value of
"__file__". Included packages pretend to be in
directories below that location. This allows you to
include data files in deployments. If you merely seek
acceleration, it's better for you to use the
"original" value, where the source files location will
be used. With "frozen" a notation "<frozen
module_name>" is used. For compatibility reasons, the
"__file__" value will always have ".py" suffix
independent of what it really is.
--module-name-choice=MODE
Select what value "__name__" and "__package__" are
going to be. With "runtime" (default for module mode),
the created module uses the parent package to deduce
the value of "__package__", to be fully compatible.
The value "original" (default for other modes) allows
for more static optimization to happen, but is
incompatible for modules that normally can be loaded
into any package.
Output choices:
--output-filename=FILENAME
Specify how the executable should be named. For
extension modules there is no choice, also not for
standalone mode and using it will be an error. This
may include path information that needs to exist
though. Defaults to '<program_name>' on this platform.
.exe
--output-dir=DIRECTORY
Specify where intermediate and final output files
should be put. The DIRECTORY will be populated with
build folder, dist folder, binaries, etc. Defaults to
current directory.
--remove-output Removes the build directory after producing the module
or exe file. Defaults to off.
--no-pyi-file Do not create a ".pyi" file for extension modules
created by Nuitka. This is used to detect implicit
imports. Defaults to off.
Debug features:
--debug Executing all self checks possible to find errors in
Nuitka, do not use for production. Defaults to off.
--unstripped Keep debug info in the resulting object file for
better debugger interaction. Defaults to off.
--profile Enable vmprof based profiling of time spent. Not
working currently. Defaults to off.
--internal-graph Create graph of optimization process internals, do not
use for whole programs, but only for small test cases.
Defaults to off.
--trace-execution Traced execution output, output the line of code
before executing it. Defaults to off.
--recompile-c-only This is not incremental compilation, but for Nuitka
development only. Takes existing files and simply
compile them as C again. Allows compiling edited C
files for quick debugging changes to the generated
source, e.g. to see if code is passed by, values
output, etc, Defaults to off. Depends on compiling
Python source to determine which files it should look
at.
--xml=XML_FILENAME Write the internal program structure, result of
optimization in XML form to given filename.
--generate-c-only Generate only C source code, and do not compile it to
binary or module. This is for debugging and code
coverage analysis that doesn't waste CPU. Defaults to
off. Do not think you can use this directly.
--experimental=FLAG
Use features declared as 'experimental'. May have no
effect if no experimental features are present in the
code. Uses secret tags (check source) per experimented
feature.
--low-memory Attempt to use less memory, by forking less C
compilation jobs and using options that use less
memory. For use on embedded machines. Use this in case
of out of memory problems. Defaults to off.
--create-environment-from-report=CREATE_ENVIRONMENT_FROM_REPORT
Create a new virtualenv in that non-existing path from
the report file given with e.g. '--report=compilation-
report.xml'. Default not done.
Backend C compiler choice:
--clang Enforce the use of clang. On Windows this requires a
working Visual Studio version to piggy back on.
Defaults to off.
--mingw64 Enforce the use of MinGW64 on Windows. Defaults to off
unless MSYS2 with MinGW Python is used.
--msvc=MSVC_VERSION
Enforce the use of specific MSVC version on Windows.
Allowed values are e.g. "14.3" (MSVC 2022) and other
MSVC version numbers, specify "list" for a list of
installed compilers, or use "latest". Defaults to
latest MSVC being used if installed, otherwise MinGW64
is used.
--jobs=N Specify the allowed number of parallel C compiler
jobs. Defaults to the system CPU count.
--lto=choice Use link time optimizations (MSVC, gcc, clang).
Allowed values are "yes", "no", and "auto" (when it's
known to work). Defaults to "auto".
--static-libpython=choice
Use static link library of Python. Allowed values are
"yes", "no", and "auto" (when it's known to work).
Defaults to "auto".
Cache Control:
--disable-cache=DISABLED_CACHES
Disable selected caches, specify "all" for all cached.
Currently allowed values are:
"all","ccache","bytecode","dll-dependencies". can be
given multiple times or with comma separated values.
Default none.
--clean-cache=CLEAN_CACHES
Clean the given caches before executing, specify "all"
for all cached. Currently allowed values are:
"all","ccache","bytecode","dll-dependencies". can be
given multiple times or with comma separated values.
Default none.
--disable-bytecode-cache
Do not reuse dependency analysis results for modules,
esp. from standard library, that are included as
bytecode. Same as --disable-cache=bytecode.
--disable-ccache Do not attempt to use ccache (gcc, clang, etc.) or
clcache (MSVC, clangcl). Same as --disable-
cache=ccache.
--disable-dll-dependency-cache
Disable the dependency walker cache. Will result in
much longer times to create the distribution folder,
but might be used in case the cache is suspect to
cause errors. Same as --disable-cache=dll-
dependencies.
--force-dll-dependency-cache-update
For an update of the dependency walker cache. Will
result in much longer times to create the distribution
folder, but might be used in case the cache is suspect
to cause errors or known to need an update.
PGO compilation choices:
--pgo Enables C level profile guided optimization (PGO), by
executing a dedicated build first for a profiling run,
and then using the result to feedback into the C
compilation. Note: This is experimental and not
working with standalone modes of Nuitka yet. Defaults
to off.
--pgo-args=PGO_ARGS
Arguments to be passed in case of profile guided
optimization. These are passed to the special built
executable during the PGO profiling run. Default
empty.
--pgo-executable=PGO_EXECUTABLE
Command to execute when collecting profile
information. Use this only, if you need to launch it
through a script that prepares it to run. Default use
created program.
Tracing features:
--report=REPORT_FILENAME
Report module, data files, compilation, plugin, etc.
details in an XML output file. This is also super
useful for issue reporting. These reports can e.g. be
used to re-create the environment easily using it with
'--create-environment-from-report', but contain a lot
of information. Default is off.
--report-diffable Report data in diffable form, i.e. no timing or memory
usage values that vary from run to run. Default is
off.
--report-user-provided=KEY_VALUE
Report data from you. This can be given multiple times
and be anything in 'key=value' form, where key should
be an identifier, e.g. use '--report-user-
provided=pipenv-lock-hash=64a5e4' to track some input
values. Default is empty.
--report-template=REPORT_DESC
Report via template. Provide template and output
filename "template.rst.j2:output.rst". For built-in
templates, check the User Manual for what these are.
Can be given multiple times. Default is empty.
--quiet Disable all information outputs, but show warnings.
Defaults to off.
--show-scons Run the C building backend Scons with verbose
information, showing the executed commands, detected
compilers. Defaults to off.
--no-progressbar Disable progress bars. Defaults to off.
--show-progress Obsolete: Provide progress information and statistics.
Disables normal progress bar. Defaults to off.
--show-memory Provide memory information and statistics. Defaults to
off.
--show-modules Provide information for included modules and DLLs
Obsolete: You should use '--report' file instead.
Defaults to off.
--show-modules-output=PATH
Where to output '--show-modules', should be a
filename. Default is standard output.
--verbose Output details of actions taken, esp. in
optimizations. Can become a lot. Defaults to off.
--verbose-output=PATH
Where to output from '--verbose', should be a
filename. Default is standard output.
General OS controls:
--disable-console When compiling for Windows or macOS, disable the
console window and create a GUI application. Defaults
to off.
--enable-console When compiling for Windows or macOS, enable the
console window and create a console application. This
disables hints from certain modules, e.g. "PySide"
that suggest to disable it. Defaults to true.
--force-stdout-spec=FORCE_STDOUT_SPEC
Force standard output of the program to go to this
location. Useful for programs with disabled console
and programs using the Windows Services Plugin of
Nuitka commercial. Defaults to not active, use e.g.
'%PROGRAM%.out.txt', i.e. file near your program,
check User Manual for full list of available values.
--force-stderr-spec=FORCE_STDERR_SPEC
Force standard error of the program to go to this
location. Useful for programs with disabled console
and programs using the Windows Services Plugin of
Nuitka commercial. Defaults to not active, use e.g.
'%PROGRAM%.err.txt', i.e. file near your program,
check User Manual for full list of available values.
Windows specific controls:
--windows-icon-from-ico=ICON_PATH
Add executable icon. Can be given multiple times for
different resolutions or files with multiple icons
inside. In the later case, you may also suffix with
#<n> where n is an integer index starting from 1,
specifying a specific icon to be included, and all
others to be ignored.
--windows-icon-from-exe=ICON_EXE_PATH
Copy executable icons from this existing executable
(Windows only).
--onefile-windows-splash-screen-image=SPLASH_SCREEN_IMAGE
When compiling for Windows and onefile, show this
while loading the application. Defaults to off.
--windows-uac-admin
Request Windows User Control, to grant admin rights on
execution. (Windows only). Defaults to off.
--windows-uac-uiaccess
Request Windows User Control, to enforce running from
a few folders only, remote desktop access. (Windows
only). Defaults to off.
macOS specific controls:
--macos-target-arch=MACOS_TARGET_ARCH
What architectures is this to supposed to run on.
Default and limit is what the running Python allows
for. Default is "native" which is the architecture the
Python is run with.
--macos-create-app-bundle
When compiling for macOS, create a bundle rather than
a plain binary application. Currently experimental and
incomplete. Currently this is the only way to unlock
disabling of console.Defaults to off.
--macos-app-icon=ICON_PATH
Add icon for the application bundle to use. Can be
given only one time. Defaults to Python icon if
available.
--macos-signed-app-name=MACOS_SIGNED_APP_NAME
Name of the application to use for macOS signing.
Follow "com.YourCompany.AppName" naming results for
best results, as these have to be globally unique, and
will potentially grant protected API accesses.
--macos-app-name=MACOS_APP_NAME
Name of the product to use in macOS bundle
information. Defaults to base filename of the binary.
--macos-app-mode=MODE
Mode of application for the application bundle. When
launching a Window, and appearing in Docker is
desired, default value "gui" is a good fit. Without a
Window ever, the application is a "background"
application. For UI elements that get to display
later, "ui-element" is in-between. The application
will not appear in dock, but get full access to
desktop when it does open a Window later.
--macos-sign-identity=MACOS_APP_VERSION
When signing on macOS, by default an ad-hoc identify
will be used, but with this option your get to specify
another identity to use. The signing of code is now
mandatory on macOS and cannot be disabled. Default
"ad-hoc" if not given.
--macos-sign-notarization
When signing for notarization, using a proper TeamID
identity from Apple, use the required runtime signing
option, such that it can be accepted.
--macos-app-version=MACOS_APP_VERSION
Product version to use in macOS bundle information.
Defaults to "1.0" if not given.
--macos-app-protected-resource=RESOURCE_DESC
Request an entitlement for access to a macOS protected
resources, e.g.
"NSMicrophoneUsageDescription:Microphone access for
recording audio." requests access to the microphone
and provides an informative text for the user, why
that is needed. Before the colon, is an OS identifier
for an access right, then the informative text. Legal
values can be found on https://developer.apple.com/doc
umentation/bundleresources/information_property_list/p
rotected_resources and the option can be specified
multiple times. Default empty.
Linux specific controls:
--linux-icon=ICON_PATH
Add executable icon for onefile binary to use. Can be
given only one time. Defaults to Python icon if
available.
Binary Version Information:
--company-name=COMPANY_NAME
Name of the company to use in version information.
Defaults to unused.
--product-name=PRODUCT_NAME
Name of the product to use in version information.
Defaults to base filename of the binary.
--file-version=FILE_VERSION
File version to use in version information. Must be a
sequence of up to 4 numbers, e.g. 1.0 or 1.0.0.0, no
more digits are allowed, no strings are allowed.
Defaults to unused.
--product-version=PRODUCT_VERSION
Product version to use in version information. Same
rules as for file version. Defaults to unused.
--file-description=FILE_DESCRIPTION
Description of the file used in version information.
Windows only at this time. Defaults to binary
filename.
--copyright=COPYRIGHT_TEXT
Copyright used in version information. Windows only at
this time. Defaults to not present.
--trademarks=TRADEMARK_TEXT
Copyright used in version information. Windows only at
this time. Defaults to not present.
Plugin control:
--enable-plugin=PLUGIN_NAME
Enabled plugins. Must be plug-in names. Use '--plugin-
list' to query the full list and exit. Default empty.
--disable-plugin=PLUGIN_NAME
Disabled plugins. Must be plug-in names. Use '--
plugin-list' to query the full list and exit. Most
standard plugins are not a good idea to disable.
Default empty.
--plugin-no-detection
Plugins can detect if they might be used, and the you
can disable the warning via "--disable-plugin=plugin-
that-warned", or you can use this option to disable
the mechanism entirely, which also speeds up
compilation slightly of course as this detection code
is run in vain once you are certain of which plugins
to use. Defaults to off.
--plugin-list Show list of all available plugins and exit. Defaults
to off.
--user-plugin=PATH The file name of user plugin. Can be given multiple
times. Default empty.
--show-source-changes
Show source changes to original Python file content
before compilation. Mostly intended for developing
plugins. Default False.
Plugin options of 'anti-bloat':
--show-anti-bloat-changes
Annotate what changes are by the plugin done.
--noinclude-setuptools-mode=NOINCLUDE_SETUPTOOLS_MODE
What to do if a 'setuptools' or import is encountered.
This package can be big with dependencies, and should
definitely be avoided. Also handles 'setuptools_scm'.
--noinclude-pytest-mode=NOINCLUDE_PYTEST_MODE
What to do if a 'pytest' import is encountered. This
package can be big with dependencies, and should
definitely be avoided. Also handles 'nose' imports.
--noinclude-unittest-mode=NOINCLUDE_UNITTEST_MODE
What to do if a unittest import is encountered. This
package can be big with dependencies, and should
definitely be avoided.
--noinclude-IPython-mode=NOINCLUDE_IPYTHON_MODE
What to do if a IPython import is encountered. This
package can be big with dependencies, and should
definitely be avoided.
--noinclude-dask-mode=NOINCLUDE_DASK_MODE
What to do if a 'dask' import is encountered. This
package can be big with dependencies, and should
definitely be avoided.
--noinclude-numba-mode=NOINCLUDE_NUMBA_MODE
What to do if a 'numba' import is encountered. This
package can be big with dependencies, and is currently
not working for standalone. This package is big with
dependencies, and should definitely be avoided.
--noinclude-default-mode=NOINCLUDE_DEFAULT_MODE
This actually provides the default "warning" value for
above options, and can be used to turn all of these
on.
--noinclude-custom-mode=CUSTOM_CHOICES
What to do if a specific import is encountered. Format
is module name, which can and should be a top level
package and then one choice, "error", "warning",
"nofollow", e.g. PyQt5:error.
```

View File

@ -7,11 +7,11 @@ Thanks a lot to Fallen_Breath and MCDR contributors
GNU Lesser General Public License v3.0 (GNU LGPL v3) GNU Lesser General Public License v3.0 (GNU LGPL v3)
""" """
import re
from typing import List, Callable, Tuple, Optional, Union
""" """
Plugin Version Plugin Version
""" """
import re
from typing import List, Callable, Tuple, Optional, Union
# beta.3 -> (beta, 3), random -> (random, None) # beta.3 -> (beta, 3), random -> (random, None)

View File

@ -19,12 +19,17 @@ by this package.
import os import os
import sys import sys
import weakref import weakref
from typing import Dict, Union, BinaryIO, Optional, List, Iterable
import pyglet import pyglet
from pyglet.font.user import UserDefinedFont
from pyglet import gl from pyglet import gl
if not getattr(sys, 'is_pyglet_doc_run', False): def _get_system_font_class():
"""Get the appropriate class for the system being used.
Pyglet relies on OS dependent font systems for loading fonts and glyph creation.
"""
if pyglet.compat_platform == 'darwin': if pyglet.compat_platform == 'darwin':
from pyglet.font.quartz import QuartzFont from pyglet.font.quartz import QuartzFont
_font_class = QuartzFont _font_class = QuartzFont
@ -37,18 +42,86 @@ if not getattr(sys, 'is_pyglet_doc_run', False):
else: else:
from pyglet.font.win32 import GDIPlusFont from pyglet.font.win32 import GDIPlusFont
_font_class = GDIPlusFont _font_class = GDIPlusFont
else: else:
from pyglet.font.freetype import FreeTypeFont from pyglet.font.freetype import FreeTypeFont
_font_class = FreeTypeFont _font_class = FreeTypeFont
return _font_class
def have_font(name):
def create_font(name: str, mappings: Dict[str, pyglet.image.ImageData], default_char: str,
ascent: Optional[float] = None,
descent: Optional[float] = None, size: Optional[float] = None, bold: bool = False,
italic: bool = False, stretch: bool = False, dpi: Optional[float] = None,
font_class=UserDefinedFont):
"""
Create a custom font with the mappings provided.
If a character in a string is not mapped in the font, it will use the default_char as fallback.
Default size is 12.
Ascent and descent will use the image dimensions as default, but can be provided.
The rest of the font parameters are used for font lookups.
"""
# Arbitrary default size
if size is None:
size = 12
if dpi is None:
dpi = 96
# Locate or create font cache
shared_object_space = gl.current_context.object_space
if not hasattr(shared_object_space, 'pyglet_font_font_cache'):
shared_object_space.pyglet_font_font_cache = weakref.WeakValueDictionary()
shared_object_space.pyglet_font_font_hold = []
shared_object_space.pyglet_font_font_name_match = {} # Match a tuple to specific name to reduce lookups.
font_cache = shared_object_space.pyglet_font_font_cache
font_hold = shared_object_space.pyglet_font_font_hold
# Look for font name in font cache
descriptor = (name, size, bold, italic, stretch, dpi)
if descriptor in font_cache:
raise Exception("A font with these parameters has already been created.", descriptor)
if _system_font_class.have_font(name):
raise Exception(f"Font name: '{name}' already exists within the system fonts.")
# Not in cache, create from scratch
font = font_class(mappings, default_char, name, ascent, descent, size, bold, italic, stretch, dpi)
# Save parameters for new-style layout classes to recover
# TODO: add properties to the Font classes, so these can be queried:
font.size = size
font.bold = bold
font.italic = italic
font.stretch = stretch
font.dpi = dpi
if name not in _user_fonts:
_user_fonts.append(name)
# Cache font in weak-ref dictionary to avoid reloading while still in use
font_cache[descriptor] = font
# Hold onto refs of last three loaded fonts to prevent them being
# collected if momentarily dropped.
del font_hold[3:]
font_hold.insert(0, font)
return font
def have_font(name: str) -> bool:
"""Check if specified system font name is available.""" """Check if specified system font name is available."""
return _font_class.have_font(name) return name in _user_fonts or _system_font_class.have_font(name)
def load(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None): def load(name: Optional[Union[str, Iterable[str]]] = None, size: Optional[float] = None, bold: bool = False,
italic: bool = False,
stretch: bool = False, dpi: Optional[float] = None):
"""Load a font for rendering. """Load a font for rendering.
:Parameters: :Parameters:
@ -101,7 +174,7 @@ def load(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None
# Find first matching name, cache it. # Find first matching name, cache it.
found_name = None found_name = None
for n in name: for n in name:
if _font_class.have_font(n): if n in _user_fonts or _system_font_class.have_font(n):
found_name = n found_name = n
break break
@ -114,7 +187,7 @@ def load(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None
return font_cache[descriptor] return font_cache[descriptor]
# Not in cache, create from scratch # Not in cache, create from scratch
font = _font_class(name, size, bold=bold, italic=italic, stretch=stretch, dpi=dpi) font = _system_font_class(name, size, bold=bold, italic=italic, stretch=stretch, dpi=dpi)
# Save parameters for new-style layout classes to recover # Save parameters for new-style layout classes to recover
# TODO: add properties to the Font classes, so these can be queried: # TODO: add properties to the Font classes, so these can be queried:
@ -135,7 +208,12 @@ def load(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None
return font return font
def add_file(font): if not getattr(sys, 'is_pyglet_doc_run', False):
_system_font_class = _get_system_font_class()
_user_fonts = []
def add_file(font: Union[str, BinaryIO]):
"""Add a font to pyglet's search path. """Add a font to pyglet's search path.
In order to load a font that is not installed on the system, you must In order to load a font that is not installed on the system, you must
@ -156,7 +234,7 @@ def add_file(font):
font = open(font, 'rb') font = open(font, 'rb')
if hasattr(font, 'read'): if hasattr(font, 'read'):
font = font.read() font = font.read()
_font_class.add_font_data(font) _system_font_class.add_font_data(font)
def add_directory(directory): def add_directory(directory):

86
libs/pyglet/font/user.py Normal file
View File

@ -0,0 +1,86 @@
from typing import Dict, Optional
import pyglet
from pyglet.font import base
class UserGlyphRenderer(base.GlyphRenderer):
def __init__(self, font: 'UserDefinedFont'):
self._font = font
self._font.glyphs[self._font.default_char] = self.render(self._font.default_char)
super().__init__(font)
def render(self, text: str):
image_data = self._font.mappings[text]
glyph = self._font.create_glyph(image_data)
glyph.set_bearings(-self._font.descent, 0, image_data.width)
return glyph
class UserDefinedFont(base.Font):
"""A basic UserDefinedFont, it takes a mappings of ImageData """
glyph_renderer_class = UserGlyphRenderer
def __init__(self, mappings: Dict[str, pyglet.image.ImageData], default_char: str, name: str, ascent: float,
descent: float, size: float, bold: bool = False, italic: bool = False, stretch: bool = False,
dpi: int = None,
locale: Optional[str] = None):
super().__init__()
self._name = name
self.mappings: Dict[str, pyglet.image.ImageData] = mappings
if default_char not in self.mappings:
raise Exception(f"Default character: '{default_char}' must exist within your mappings.")
if ascent is None or descent is None:
image = list(mappings.values())[0]
if ascent is None:
ascent = image.height
if descent is None:
descent = 0
self.ascent = ascent
self.descent = descent
self.default_char = default_char
self.bold = bold
self.italic = italic
self.stretch = stretch
self.dpi = dpi
self.size = size
self.locale = locale
@property
def name(self):
return self._name
def get_glyphs(self, text):
"""Create and return a list of Glyphs for `text`.
If any characters do not have a known glyph representation in this
font, a substitution will be made.
:Parameters:
`text` : str or unicode
Text to render.
:rtype: list of `Glyph`
"""
glyph_renderer = None
glyphs = [] # glyphs that are committed.
for c in base.get_grapheme_clusters(str(text)):
# Get the glyph for 'c'. Hide tabs (Windows and Linux render
# boxes)
if c == '\t':
c = ' '
if c not in self.glyphs:
if not glyph_renderer:
glyph_renderer = self.glyph_renderer_class(self)
if c not in self.mappings:
c = self.default_char
else:
self.glyphs[c] = glyph_renderer.render(c)
glyphs.append(self.glyphs[c])
return glyphs

View File

@ -1,64 +0,0 @@
# pyglet_rs
This is a folder about pyglet_rs.
## What is pyglet_rs?
pyglet_rs is a python library that patches pyglet to use rust to make it faster!
## Notice
**This Folder may be move to an individual repo. here is just a temp location**
## requirements
- `python 3.8+`
- `pyglet 2.0+`
- `rustc 1.68.1+`
- no more
## status
- still writing
## usage
```python
import pyglet_rs
pyglet_rs.patch_sprite()
import pyglet
...
```
## how to build
```powershell
cd src
./build.ps1
```
## roadmap
- [ ] `pyglet.sprite.Sprite` patch
- [ ] `pyglet.math.Vec2` patch (doing)
- [ ] main Calculate protocol
- [ ] other protocols
- [ ] `pyglet.math.Vec3` patch (doing)
- [ ] main Calculate protocol
- [ ] other protocols
- [ ] `pyglet.math.Vec4` patch (doing)
- [ ] main Calculate protocol
- [ ] other protocols
- [ ] `pyglet.math.Mat3(tuple)` patch (doing)
- [ ] main Calculate protocol
- [ ] other protocols
- [ ] `pyglet.math.Mat4(tuple)` patch (doing)
- [ ] main Calculate protocol
- [ ] other protocols
## Thanks
Great thanks to Github Copilot!
It helps me a lot in Vector and Matrix calculation and protocol implementation.
(there are A LOT of code generated by copilot)
(even this sentence is generated by copilot)

View File

@ -1,112 +0,0 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
"""
from .lib import (get_version_str)
from .lib import (Sprite_rs,
Vector2_rs, Vector3_rs, Vector4_rs,
Matrix3_rs, Matrix4_rs)
"""
from .lib import *
from typing import TYPE_CHECKING, Union
# noinspection PyUnresolvedReferences
__version__ = get_version_str()
__all__ = ['patch_sprite', 'patch_vector', 'patch_matrix', 'patch_all',
'Sprite_rs',
'Vector2_rs', 'Vector3_rs', 'Vector4_rs',
'Matrix3_rs', 'Matrix4_rs']
if TYPE_CHECKING:
from pyglet.event import EventDispatcher
Number = Union[int, float]
def get_version_str() -> str: ...
class Sprite_rs(EventDispatcher): ...
class Vector2_rs:
def __init__(self, x: Number, y: Number): ...
def __add__(self, other: "Vector2_rs") -> "Vector2_rs": ...
def __sub__(self, other: "Vector2_rs") -> "Vector2_rs": ...
def __mul__(self, other: "Vector2_rs") -> "Vector2_rs": ...
def __truediv__(self, other: "Vector2_rs") -> "Vector2_rs": ...
def __floordiv__(self, other: "Vector2_rs") -> "Vector2_rs": ...
def __repr__(self) -> str: ...
@property
def x(self) -> float: ...
@property
def y(self) -> float: ...
class Vector3_rs:
def __init__(self, x: Number, y: Number, z: Number): ...
def __add__(self, other: "Vector3_rs") -> "Vector3_rs": ...
def __sub__(self, other: "Vector3_rs") -> "Vector3_rs": ...
def __mul__(self, other: "Vector3_rs") -> "Vector3_rs": ...
def __truediv__(self, other: "Vector3_rs") -> "Vector3_rs": ...
def __floordiv__(self, other: "Vector3_rs") -> "Vector3_rs": ...
def __repr__(self) -> str: ...
@property
def x(self) -> float: ...
@property
def y(self) -> float: ...
@property
def z(self) -> float: ...
class Vector4_rs:
def __init__(self, x: Number, y: Number, z: Number, w: Number): ...
def __add__(self, other: "Vector4_rs") -> "Vector4_rs": ...
def __sub__(self, other: "Vector4_rs") -> "Vector4_rs": ...
def __mul__(self, other: "Vector4_rs") -> "Vector4_rs": ...
def __truediv__(self, other: "Vector4_rs") -> "Vector4_rs": ...
def __floordiv__(self, other: "Vector4_rs") -> "Vector4_rs": ...
def __repr__(self) -> str: ...
@property
def x(self) -> float: ...
@property
def y(self) -> float: ...
@property
def z(self) -> float: ...
@property
def w(self) -> float: ...
class Matrix3_rs: ...
class Matrix4_rs: ...
def patch_sprite():
from pyglet import sprite
sprite.Sprite = Sprite_rs
def patch_vector():
from pyglet import math
math.Vector2 = Vector2_rs
math.Vector3 = Vector3_rs
math.Vector4 = Vector4_rs
def patch_matrix():
from pyglet import math
math.Matrix3 = Matrix3_rs
math.Matrix4 = Matrix4_rs
def patch_all():
patch_sprite()
patch_vector()
patch_matrix()

View File

@ -1,325 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ctor"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "ghost"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e77ac7b51b8e6313251737fcef4b1c01a2ea102bde68415b62c0ee9268fec357"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.5",
]
[[package]]
name = "indoc"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
[[package]]
name = "inventory"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "498ae1c9c329c7972b917506239b557a60386839192f1cf0ca034f345b65db99"
dependencies = [
"ctor",
"ghost",
]
[[package]]
name = "libc"
version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "memoffset"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "proc-macro2"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyglet_rs"
version = "0.1.0"
dependencies = [
"pyo3",
]
[[package]]
name = "pyo3"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147"
dependencies = [
"cfg-if",
"indoc",
"inventory",
"libc",
"memoffset",
"parking_lot",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 1.0.109",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "quote"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89c2d1c76a26822187a1fbb5964e3fff108bc208f02e820ab9dac1234f6b388a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5"
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unindent"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"

View File

@ -1,17 +0,0 @@
[package]
name = "pyglet_rs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = 'pyglet_rs'
crate-type = ["cdylib"]
[profile.release]
codegen-units = 1
[dependencies.pyo3]
version = "0.18.1"
features = ["extension-module", "multiple-pymethods"]

View File

@ -1 +0,0 @@
cargo fmt;python3.8 .\setup.py build; python .\post_build.py

View File

@ -1,41 +0,0 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import os
import shutil
import warnings
import traceback
package_path = 'pyglet_rs'
lib_path = '../lib'
build_path = 'build'
if not os.path.exists(lib_path):
os.mkdir(lib_path)
builds = os.listdir(build_path)
print(os.path.abspath('.'))
try:
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}')
continue
for file in os.listdir(os.path.join(build_path, build_dir, package_path)):
# file_name = os.path.join(lib_path, file.replace(package_path, f'{package_path}.{DR_runtime.DR_Rust_version}'))
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)
except (shutil.SameFileError, PermissionError):
# print(os.path.exists(os.path))
print(os.listdir(lib_path))
traceback.print_exc()
continue
print(os.path.abspath(file_name))

View File

@ -1,39 +0,0 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import os
import sys
import rtoml
import shutil
from setuptools import setup
from setuptools_rust import Binding, RustExtension
sys.path.append('../../../')
sys.path.append(os.curdir)
package_path = 'pyglet_rs'
# 版本号从 cargo.toml 中读取
with open(f'Cargo.toml', 'r') as f:
cargo_toml = rtoml.load(f)
version = cargo_toml['package']['version']
setup(
name='pyglet_rs',
version=version,
author='shenjackyuanjie',
author_email='3695888@qq.com',
rust_extensions=[RustExtension(target="pyglet_rs.pyglet_rs",
binding=Binding.PyO3)],
zip_safe=False,
)
lib_path = '../lib'
build_path = 'build'
if 'clean' in sys.argv:
shutil.rmtree(build_path, ignore_errors=True)
shutil.rmtree(f'{package_path}.egg-info', ignore_errors=True)
sys.exit(0)

View File

@ -1,10 +0,0 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from typing import TYPE_CHECKING
if not TYPE_CHECKING:
from .pyglet_rs import *

View File

@ -1,30 +0,0 @@
/*
* -------------------------------
* Difficult Rocket
* Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
* All rights reserved
* -------------------------------
*/
mod math;
mod pymath;
mod sprite;
use pyo3::prelude::*;
#[pyfunction]
fn get_version_str() -> String {
return "0.1.0".to_string();
}
#[pymodule]
#[pyo3(name = "pyglet_rs")]
fn module_init(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(get_version_str, m)?)?;
m.add_class::<sprite::Sprite>()?;
// vector
m.add_class::<pymath::python_class::PyVector2>()?;
m.add_class::<pymath::python_class::PyVector3>()?;
m.add_class::<pymath::python_class::PyVector4>()?;
Ok(())
}

View File

@ -1,395 +0,0 @@
/*
* -------------------------------
* Difficult Rocket
* Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
* All rights reserved
* -------------------------------
*/
pub mod vector {
use std::ops::{Add, Div, Mul, Sub};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Vector2 {
pub x: f64,
pub y: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Vector3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Vector4 {
pub x: f64,
pub y: f64,
pub z: f64,
pub w: f64,
}
pub trait VectorTrait {
fn len(&self) -> i8; // use short int to save memory (even if its not going to save a lot)
fn floordiv(&self, other: &Self) -> Self;
fn abs(&self) -> f64;
fn neg(&self) -> Self;
fn dot(&self, other: &Self) -> f64;
fn round(&self, ndigits: Option<i64>) -> Self;
fn clamp(&self, min: f64, max: f64) -> Self;
fn distance(&self, other: &Self) -> f64;
fn normalize(&self) -> Self;
// from
fn from_same(len: f64) -> Self;
}
impl Add for Vector2 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl Sub for Vector2 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::new(self.x - rhs.x, self.y - rhs.y)
}
}
impl Mul for Vector2 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::new(self.x * rhs.x, self.y * rhs.y)
}
}
impl Div for Vector2 {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self::new(self.x / rhs.x, self.y / rhs.y)
}
}
impl Add for Vector3 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
}
}
impl Sub for Vector3 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
}
}
impl Mul for Vector3 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
}
}
impl Div for Vector3 {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self::new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
}
}
impl Add for Vector4 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::new(
self.x + rhs.x,
self.y + rhs.y,
self.z + rhs.z,
self.w + rhs.w,
)
}
}
impl Sub for Vector4 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::new(
self.x - rhs.x,
self.y - rhs.y,
self.z - rhs.z,
self.w - rhs.w,
)
}
}
impl Mul for Vector4 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::new(
self.x * rhs.x,
self.y * rhs.y,
self.z * rhs.z,
self.w * rhs.w,
)
}
}
impl Div for Vector4 {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self::new(
self.x / rhs.x,
self.y / rhs.y,
self.z / rhs.z,
self.w / rhs.w,
)
}
}
impl VectorTrait for Vector2 {
fn len(&self) -> i8 {
return 2;
}
fn floordiv(&self, other: &Self) -> Self {
// 手动模拟python的//运算符
Self::new((self.x / other.x).floor(), (self.y / other.y).floor())
}
fn abs(&self) -> f64 {
return (self.x.powi(2) + self.y.powi(2)).sqrt();
}
fn neg(&self) -> Self {
Self::new(-self.x, -self.y)
}
fn dot(&self, other: &Self) -> f64 {
self.x * other.x + self.y * other.y
}
fn round(&self, ndigits: Option<i64>) -> Self {
match ndigits {
Some(ndigits) => {
let ndigits = ndigits as i32;
Self::new(
self.x.round() * 10.0_f64.powi(ndigits),
self.y.round() * 10.0_f64.powi(ndigits),
)
}
None => Self::new(self.x.round(), self.y.round()),
}
}
fn clamp(&self, min: f64, max: f64) -> Self {
Self::new(self.x.clamp(min, max), self.y.clamp(min, max))
}
fn distance(&self, other: &Self) -> f64 {
(*self - *other).abs()
}
fn normalize(&self) -> Self {
let d = self.abs();
return if d != 0.0 {
Self::new(self.x / d, self.y / d)
} else {
self.clone()
};
}
fn from_same(len: f64) -> Self {
Self::new(len, len)
}
}
impl VectorTrait for Vector3 {
fn len(&self) -> i8 {
return 3;
}
fn floordiv(&self, other: &Self) -> Self {
// 手动模拟python的//运算符
Self::new(
(self.x / other.x).floor(),
(self.y / other.y).floor(),
(self.z / other.z).floor(),
)
}
fn abs(&self) -> f64 {
return (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt();
}
fn neg(&self) -> Self {
Self::new(-self.x, -self.y, -self.z)
}
fn dot(&self, other: &Self) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
fn round(&self, ndigits: Option<i64>) -> Self {
match ndigits {
Some(ndigits) => {
let ndigits = ndigits as i32;
Self::new(
self.x.round() * 10.0_f64.powi(ndigits),
self.y.round() * 10.0_f64.powi(ndigits),
self.z.round() * 10.0_f64.powi(ndigits),
)
}
None => Self::new(self.x.round(), self.y.round(), self.z.round()),
}
}
fn clamp(&self, min: f64, max: f64) -> Self {
Self::new(
self.x.clamp(min, max),
self.y.clamp(min, max),
self.z.clamp(min, max),
)
}
fn distance(&self, other: &Self) -> f64 {
(*self - *other).abs()
}
fn normalize(&self) -> Self {
let d = self.abs();
return if d != 0.0 {
Self::new(self.x / d, self.y / d, self.z / d)
} else {
self.clone()
};
}
fn from_same(len: f64) -> Self {
Self::new(len, len, len)
}
}
impl VectorTrait for Vector4 {
fn len(&self) -> i8 {
return 4;
}
fn floordiv(&self, other: &Self) -> Self {
// 手动模拟python的//运算符
Self::new(
(self.x / other.x).floor(),
(self.y / other.y).floor(),
(self.z / other.z).floor(),
(self.w / other.w).floor(),
)
}
fn abs(&self) -> f64 {
return (self.x.powi(2) + self.y.powi(2) + self.z.powi(2) + self.w.powi(2)).sqrt();
}
fn neg(&self) -> Self {
Self::new(-self.x, -self.y, -self.z, -self.w)
}
fn dot(&self, other: &Self) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
}
fn round(&self, ndigits: Option<i64>) -> Self {
match ndigits {
Some(ndigits) => {
let ndigits = ndigits as i32;
Self::new(
self.x.round() * 10.0_f64.powi(ndigits),
self.y.round() * 10.0_f64.powi(ndigits),
self.z.round() * 10.0_f64.powi(ndigits),
self.w.round() * 10.0_f64.powi(ndigits),
)
}
None => Self::new(
self.x.round(),
self.y.round(),
self.z.round(),
self.w.round(),
),
}
}
fn clamp(&self, min: f64, max: f64) -> Self {
Self::new(
self.x.clamp(min, max),
self.y.clamp(min, max),
self.z.clamp(min, max),
self.w.clamp(min, max),
)
}
fn distance(&self, other: &Self) -> f64 {
(*self - *other).abs()
}
fn normalize(&self) -> Self {
let d = self.abs();
return if d != 0.0 {
Self::new(self.x / d, self.y / d, self.z / d, self.w / d)
} else {
self.clone()
};
}
fn from_same(len: f64) -> Self {
Self::new(len, len, len, len)
}
}
impl Vector2 {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
}
impl Vector3 {
pub fn new(x: f64, y: f64, z: f64) -> Self {
Self { x, y, z }
}
}
impl Vector4 {
pub fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
Self { x, y, z, w }
}
}
}
pub mod matrix {
use super::vector::{Vector3, Vector4};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Matrix3 {
pub line1: Vector3,
pub line2: Vector3,
pub line3: Vector3,
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Matrix4 {
pub line1: Vector4,
pub line2: Vector4,
pub line3: Vector4,
pub line4: Vector4,
}
}

View File

@ -1,354 +0,0 @@
/*
* -------------------------------
* Difficult Rocket
* Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
* All rights reserved
* -------------------------------
*/
pub mod python_class {
use pyo3::class::basic::CompareOp;
use pyo3::prelude::*;
use pyo3::types::PySlice;
use crate::math::matrix::{Matrix3, Matrix4};
use crate::math::vector::{Vector2, Vector3, Vector4, VectorTrait};
#[derive(Clone)]
#[pyclass(name = "Vector2_rs")]
pub struct PyVector2 {
pub data: Vector2,
}
#[derive(Clone)]
#[pyclass(name = "Vector3_rs")]
pub struct PyVector3 {
pub data: Vector3,
}
#[derive(Clone)]
#[pyclass(name = "Vector4_rs")]
pub struct PyVector4 {
pub data: Vector4,
}
#[derive(Clone)]
#[pyclass(name = "Matrix3_rs")]
pub struct PyMatrix3 {
pub data: Matrix3,
}
#[derive(Clone)]
#[pyclass(name = "Matrix4_rs")]
pub struct PyMatrix4 {
pub data: Matrix4,
}
#[allow(unused)]
pub trait PyCalc {
fn __add__(&self, other: &Self) -> Self;
fn __sub__(&self, other: &Self) -> Self;
fn __mul__(&self, other: &Self) -> Self;
fn __truediv__(&self, other: &Self) -> Self;
fn __floordiv__(&self, other: &Self) -> Self;
fn __abs__(&self) -> f64;
fn __neg__(&self) -> Self;
fn __round__(&self, ndigits: Option<i64>) -> Self;
fn __radd__(&self, other: &PyAny) -> Self;
// fn rotate
}
/// 这是一个用来自动给 impl xxx for xxx 的块去掉 trait 部分的宏
/// 用于在为 pyclass 实现
#[pymethods]
impl PyVector2 {
#[new]
fn py_new(x: f64, y: f64) -> Self {
return Self {
data: Vector2::new(x, y),
};
}
fn __add__(&self, other: &Self) -> Self {
return Self {
data: self.data + other.data,
};
}
fn __radd__(&self, other: &PyAny) -> Self {
return if other.is_instance_of::<PyVector2>().unwrap() {
Self {
data: self.data + other.extract::<PyVector2>().unwrap().data,
}
} else {
// if other == 0
if other.is_none() {
self.clone()
} else {
Self {
data: self.data + Vector2::from_same(other.extract::<f64>().unwrap()),
}
}
};
}
fn __sub__(&self, other: &Self) -> Self {
return Self {
data: self.data - other.data,
};
}
fn __mul__(&self, other: &Self) -> Self {
return Self {
data: self.data * other.data,
};
}
fn __truediv__(&self, other: &Self) -> Self {
return Self {
data: self.data / other.data,
};
}
fn __floordiv__(&self, other: &Self) -> Self {
return Self {
data: self.data.floordiv(&other.data),
};
}
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
match op {
CompareOp::Lt => Ok(self.data < other.data),
CompareOp::Le => Ok(self.data <= other.data),
CompareOp::Eq => Ok(self.data == other.data),
CompareOp::Ne => Ok(self.data != other.data),
CompareOp::Gt => Ok(self.data > other.data),
CompareOp::Ge => Ok(self.data >= other.data),
}
}
fn __repr__(&self) -> String {
return format!("Vector2_rs({}, {})", self.data.x, self.data.y);
}
// fn __getitem__(&self, item: &PyAny) -> PyResult<&PyAny> {
// if item.is_instance_of::<PySlice>().unwrap() {
// let item = item.extract::<PySlice>().unwrap();
// let indices = item.indices().unwrap();
// }
// }
// getter and setter
#[getter]
fn get_x(&self) -> f64 {
return self.data.x;
}
#[getter]
fn get_y(&self) -> f64 {
return self.data.y;
}
#[setter]
fn set_x(&mut self, x: f64) {
self.data.x = x;
}
#[setter]
fn set_y(&mut self, y: f64) {
self.data.y = y;
}
}
#[pymethods]
impl PyVector3 {
#[new]
fn py_new(x: f64, y: f64, z: f64) -> Self {
return Self {
data: Vector3::new(x, y, z),
};
}
fn __add__(&self, other: &Self) -> Self {
return Self {
data: self.data + other.data,
};
}
fn __sub__(&self, other: &Self) -> Self {
return Self {
data: self.data - other.data,
};
}
fn __mul__(&self, other: &Self) -> Self {
return Self {
data: self.data * other.data,
};
}
fn __truediv__(&self, other: &Self) -> Self {
return Self {
data: self.data / other.data,
};
}
fn __floordiv__(&self, other: &Self) -> Self {
return Self {
data: self.data.floordiv(&other.data),
};
}
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
match op {
CompareOp::Lt => Ok(self.data < other.data),
CompareOp::Le => Ok(self.data <= other.data),
CompareOp::Eq => Ok(self.data == other.data),
CompareOp::Ne => Ok(self.data != other.data),
CompareOp::Gt => Ok(self.data > other.data),
CompareOp::Ge => Ok(self.data >= other.data),
}
}
fn __repr__(&self) -> String {
return format!(
"Vector3_rs({}, {}, {})",
self.data.x, self.data.y, self.data.z
);
}
// getter and setter
#[getter]
fn get_x(&self) -> f64 {
return self.data.x;
}
#[getter]
fn get_y(&self) -> f64 {
return self.data.y;
}
#[getter]
fn get_z(&self) -> f64 {
return self.data.z;
}
#[setter]
fn set_x(&mut self, x: f64) {
self.data.x = x;
}
#[setter]
fn set_y(&mut self, y: f64) {
self.data.y = y;
}
#[setter]
fn set_z(&mut self, z: f64) {
self.data.z = z;
}
}
#[pymethods]
impl PyVector4 {
#[new]
fn py_new(x: f64, y: f64, z: f64, w: f64) -> Self {
return Self {
data: Vector4::new(x, y, z, w),
};
}
fn __add__(&self, other: &Self) -> Self {
return Self {
data: self.data + other.data,
};
}
fn __sub__(&self, other: &Self) -> Self {
return Self {
data: self.data - other.data,
};
}
fn __mul__(&self, other: &Self) -> Self {
return Self {
data: self.data * other.data,
};
}
fn __truediv__(&self, other: &Self) -> Self {
return Self {
data: self.data / other.data,
};
}
fn __floordiv__(&self, other: &Self) -> Self {
return Self {
data: self.data.floordiv(&other.data),
};
}
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
match op {
CompareOp::Lt => Ok(self.data < other.data),
CompareOp::Le => Ok(self.data <= other.data),
CompareOp::Eq => Ok(self.data == other.data),
CompareOp::Ne => Ok(self.data != other.data),
CompareOp::Gt => Ok(self.data > other.data),
CompareOp::Ge => Ok(self.data >= other.data),
}
}
fn __repr__(&self) -> String {
return format!(
"Vector4_rs({}, {}, {}, {})",
self.data.x, self.data.y, self.data.z, self.data.w
);
}
// getter and setter
#[getter]
fn get_x(&self) -> f64 {
return self.data.x;
}
#[getter]
fn get_y(&self) -> f64 {
return self.data.y;
}
#[getter]
fn get_z(&self) -> f64 {
return self.data.z;
}
#[getter]
fn get_w(&self) -> f64 {
return self.data.w;
}
#[setter]
fn set_x(&mut self, x: f64) {
self.data.x = x;
}
#[setter]
fn set_y(&mut self, y: f64) {
self.data.y = y;
}
#[setter]
fn set_z(&mut self, z: f64) {
self.data.z = z;
}
#[setter]
fn set_w(&mut self, w: f64) {
self.data.w = w;
}
}
}

View File

@ -1,226 +0,0 @@
/*
* -------------------------------
* Difficult Rocket
* Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
* All rights reserved
* -------------------------------
*/
use pyo3::intern;
use pyo3::prelude::*;
// use pyo3::types::PyDict;
/// Instance of an on-screen image
/// See the module documentation for usage.
#[pyclass(name = "Sprite_rs", subclass)]
#[pyo3(text_signature = "(img, x=0.0, y=0.0, z=0.0, \
blend_src=770, blend_dest=771, \
batch=None, group=None, \
subpixel=False, program=None)")]
pub struct Sprite {
// render
pub subpixel: bool,
pub batch: Py<PyAny>,
pub group: Option<Py<PyAny>>,
pub user_group: Option<Py<PyAny>>,
pub group_class: Py<PyAny>,
// view
pub x: f64,
pub y: f64,
pub z: f64,
pub scale: f64,
pub scale_x: f64,
pub scale_y: f64,
pub visible: bool,
pub vertex_list: Option<Vec<()>>,
// frame
pub frame_index: u32,
pub next_dt: f64,
#[pyo3(get)]
pub program: Option<Py<PyAny>>,
pub animation: Option<Py<PyAny>>,
pub texture: Option<Py<PyAny>>,
pub paused: bool,
// other
pub rotation: f64,
pub rgba: (u8, u8, u8, u8),
}
#[pymethods]
impl Sprite {
/// python code:
/// 366:
/// if isinstance(img, image.Animation):
/// self._animation = img
/// self._texture = img.frames[0].image.get_texture()
/// self._next_dt = img.frames[0].duration
/// if self._next_dt:
/// clock.schedule_once(self._animate, self._next_dt)
/// else:
/// self._texture = img.get_texture()
/// 375:
/// if not program:
/// if isinstance(img, image.TextureArrayRegion):
/// self._program = get_default_array_shader()
/// else:
/// self._program = get_default_shader()
/// else:
/// self._program = program
/// 383:
/// self._batch = batch or graphics.get_default_batch()
/// self._user_group = group
/// self._group = self.group_class(self._texture, blend_src, blend_dest, self.program, group)
/// self._subpixel = subpixel
/// 387:
/// self._create_vertex_list()
#[new]
fn new(
py_: Python,
img: &PyAny,
x: f64,
y: f64,
z: f64,
blend_src: u32, // default 770 (GL_SRC_ALPHA)
blend_dest: u32, // default 771 (GL_ONE_MINUS_SRC_ALPHA)
batch_: &PyAny,
group: &PyAny,
subpixel: bool,
program_: &PyAny,
) -> Self {
let texture;
let batch;
let mut next_dt = 0.0;
let mut animation = None;
let mut program = program_;
let sprite_group_class = PyModule::import(py_, "pyglet.sprite")
.unwrap()
.getattr("SpriteGroup")
.unwrap();
// 366
let animation_class = PyModule::import(py_, "pyglet.image.Animation")
.unwrap()
.getattr("Animation")
.unwrap();
if img.is_instance(animation_class).unwrap() {
animation = Some(img.into());
texture = img
.getattr(intern!(img.py(), "frames"))
.unwrap()
.get_item(0)
.unwrap()
.getattr(intern!(img.py(), "image"))
.unwrap()
.call_method0(intern!(img.py(), "get_texture"))
.unwrap();
let _next_dt = img
.getattr(intern!(img.py(), "frames"))
.unwrap()
.get_item(0)
.unwrap()
.getattr(intern!(img.py(), "duration"));
next_dt = match _next_dt {
Ok(v) => v.extract().unwrap(),
Err(_) => 0.0,
}
// 372
} else {
texture = img.call_method0(intern!(img.py(), "get_texture")).unwrap();
}
// 375
if !program.is_true().unwrap() {
let texture_array_region_class =
PyModule::import(py_, "pyglet.image.TextureArrayRegion")
.unwrap()
.getattr("TextureArrayRegion")
.unwrap();
if img.is_instance(texture_array_region_class).unwrap() {
// self._program = get_default_array_shader()
let get_default_array_shader = PyModule::import(py_, "pyglet.sprite")
.unwrap()
.getattr("get_default_array_shader")
.unwrap();
program = get_default_array_shader.call0().unwrap();
} else {
// self._program = get_default_shader()
let get_default_shader = PyModule::import(py_, "pyglet.sprite")
.unwrap()
.getattr("get_default_shader")
.unwrap();
program = get_default_shader.call0().unwrap();
}
}
// 383
if !batch_.is_none() {
batch = PyModule::import(py_, "pyglet.graphics")
.unwrap()
.getattr("get_default_batch")
.unwrap()
.call0()
.unwrap();
} else {
batch = batch_;
}
// 385
let group = sprite_group_class
.call1((texture, blend_src, blend_dest, program, group))
.unwrap();
Sprite {
subpixel,
batch: batch.into(),
group: Some(group.into()),
user_group: Some(group.into()),
group_class: group.into(),
x,
y,
z,
scale: 1.0,
scale_x: 1.0,
scale_y: 1.0,
visible: true,
vertex_list: None,
frame_index: 0,
next_dt,
program: Some(program.into()),
animation: animation,
texture: Some(texture.into()),
paused: false,
rotation: 0.0,
rgba: (255, 255, 255, 255),
}
}
// python code:
// 390:
// def _create_vertex_list(self):
// texture = self._texture
// self._vertex_list = self.program.vertex_list(
// 1, GL_POINTS, self._batch, self._group,
// position=('f', (self._x, self._y, self._z)),
// size=('f', (texture.width, texture.height, 1, 1)),
// color=('Bn', self._rgba),
// texture_uv=('f', texture.uv),
// rotation=('f', (self._rotation,)))
// pub fn _create_vertex_list(&mut self) -> PyResult<()> {
// let texture = self.texture.as_ref()?;
// Python::with_gil(|py| -> PyResult<()> {
// let args = PyDict::new(py);
// args.set_item("position", (self.x, self.y, self.z))?;
// args.set_item(
// "size",
// (
// texture.getattr(py, "width")?,
// texture.getattr(py, "height")?,
// 1,
// 1,
// ),
// )?;
// args.set_item("color", ("Bn", self.rgba))?;
// args.set_item("texture_uv", texture.getattr(py, "uv")?)?;
// args.set_item("rotation", (self.rotation,))?;
// Ok(())
// })?;
// Ok(())
// }
}

View File

@ -1,71 +0,0 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import random
import unittest
from typing import Tuple
from libs.pyglet_rs import Vector2_rs, Vector3_rs, Vector4_rs
# 用于自动在测试运行前后输出测试信息的装饰器
def print_test_info(func):
def wrapper(*args, **kwargs):
print(f"{'=' * 20} {func.__name__} {'=' * 20}")
func(*args, **kwargs)
print(f"{'=' * 20} {func.__name__} {'=' * 20}")
return wrapper
def gen_random_vector() -> Tuple[Vector2_rs, Vector3_rs, Vector4_rs]:
vec2 = Vector2_rs(random.randint(1, 100), random.randint(1, 100))
vec3 = Vector3_rs(random.randint(1, 100), random.randint(1, 100), random.randint(1, 100))
vec4 = Vector4_rs(random.randint(1, 100), random.randint(1, 100), random.randint(1, 100), random.randint(1, 100))
return vec2, vec3, vec4
class TestVector(unittest.TestCase):
@print_test_info
def test1_create_print_vector(self):
vec2, vec3, vec4 = gen_random_vector()
print(f"{vec2=}")
print(f"{vec3=}")
print(f"{vec4=}")
@print_test_info
def test2_calculate_vector(self):
vec2, vec3, vec4 = gen_random_vector()
vec2_1, vec3_1, vec4_1 = gen_random_vector()
print('test add')
self.assertEqual(vec2 + vec2_1, Vector2_rs(vec2.x + vec2_1.x, vec2.y + vec2_1.y))
self.assertEqual(vec3 + vec3_1, Vector3_rs(vec3.x + vec3_1.x, vec3.y + vec3_1.y, vec3.z + vec3_1.z))
self.assertEqual(vec4 + vec4_1, Vector4_rs(vec4.x + vec4_1.x, vec4.y + vec4_1.y, vec4.z + vec4_1.z, vec4.w + vec4_1.w))
print('test sub')
self.assertEqual(vec2 - vec2_1, Vector2_rs(vec2.x - vec2_1.x, vec2.y - vec2_1.y))
self.assertEqual(vec3 - vec3_1, Vector3_rs(vec3.x - vec3_1.x, vec3.y - vec3_1.y, vec3.z - vec3_1.z))
self.assertEqual(vec4 - vec4_1, Vector4_rs(vec4.x - vec4_1.x, vec4.y - vec4_1.y, vec4.z - vec4_1.z, vec4.w - vec4_1.w))
print('test mul')
self.assertEqual(vec2 * vec2_1, Vector2_rs(vec2.x * vec2_1.x, vec2.y * vec2_1.y))
self.assertEqual(vec3 * vec3_1, Vector3_rs(vec3.x * vec3_1.x, vec3.y * vec3_1.y, vec3.z * vec3_1.z))
self.assertEqual(vec4 * vec4_1, Vector4_rs(vec4.x * vec4_1.x, vec4.y * vec4_1.y, vec4.z * vec4_1.z, vec4.w * vec4_1.w))
print('test true_div')
self.assertEqual(vec2 / vec2_1, Vector2_rs(vec2.x / vec2_1.x, vec2.y / vec2_1.y))
self.assertEqual(vec3 / vec3_1, Vector3_rs(vec3.x / vec3_1.x, vec3.y / vec3_1.y, vec3.z / vec3_1.z))
self.assertEqual(vec4 / vec4_1, Vector4_rs(vec4.x / vec4_1.x, vec4.y / vec4_1.y, vec4.z / vec4_1.z, vec4.w / vec4_1.w))
print('test floor_div')
self.assertEqual(vec2 // vec2_1, Vector2_rs(vec2.x // vec2_1.x, vec2.y // vec2_1.y))
self.assertEqual(vec3 // vec3_1, Vector3_rs(vec3.x // vec3_1.x, vec3.y // vec3_1.y, vec3.z // vec3_1.z))
self.assertEqual(vec4 // vec4_1, Vector4_rs(vec4.x // vec4_1.x, vec4.y // vec4_1.y, vec4.z // vec4_1.z, vec4.w // vec4_1.w))

View File

@ -8,11 +8,17 @@
import platform import platform
import traceback import traceback
from pathlib import Path from pathlib import Path
from typing import List, Tuple from typing import List, Tuple, Optional, Any
from Difficult_Rocket.api.types import Options, Version from Difficult_Rocket.api.types import Options, Version
def _add_cmd(cmd: List[str], string: Optional[Any]) -> List[str]:
if string is not None and string:
cmd.append(string)
return cmd
class CompilerHelper(Options): class CompilerHelper(Options):
name = 'Nuitka Compiler Helper' name = 'Nuitka Compiler Helper'
@ -28,6 +34,7 @@ class CompilerHelper(Options):
use_mingw: bool = False # --mingw64 use_mingw: bool = False # --mingw64
standalone: bool = True # --standalone standalone: bool = True # --standalone
use_ccache: bool = True # not --disable-ccache use_ccache: bool = True # not --disable-ccache
enable_console: bool = True # --enable-console / --disable-console
show_progress: bool = True # --show-progress show_progress: bool = True # --show-progress
show_memory: bool = False # --show-memory show_memory: bool = False # --show-memory
@ -38,8 +45,11 @@ class CompilerHelper(Options):
company_name: str = 'tool-shenjack-workshop' company_name: str = 'tool-shenjack-workshop'
product_name: str = 'Difficult-Rocket' product_name: str = 'Difficult-Rocket'
product_version: Version
file_version: Version file_version: Version
product_version: Version
file_description: str = 'Difficult Rocket' # --file-description
copy_right: str = 'Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com' # --copyright
icon_path: Path = Path('textures/icon.png') icon_path: Path = Path('textures/icon.png')
@ -51,6 +61,9 @@ class CompilerHelper(Options):
('./configs', './configs')] ('./configs', './configs')]
include_packages: List[str] = ['Difficult_Rocket.api'] include_packages: List[str] = ['Difficult_Rocket.api']
enable_plugin: List[str] = [] # --enable-plugin=xxx,xxx
disable_plugin: List[str] = [] # --disable-plugin=xxx,xxx
def init(self, **kwargs) -> None: def init(self, **kwargs) -> None:
# 非 windows 平台不使用 msvc # 非 windows 平台不使用 msvc
if platform.system() != 'Windows': if platform.system() != 'Windows':
@ -62,9 +75,9 @@ class CompilerHelper(Options):
def load_file(self) -> bool: def load_file(self) -> bool:
try: try:
from Difficult_Rocket import DR_runtime from Difficult_Rocket import DR_status
self.product_version = DR_runtime.DR_version self.product_version = DR_status.DR_version
self.file_version = DR_runtime.Build_version self.file_version = DR_status.Build_version
return True return True
except ImportError: except ImportError:
traceback.print_exc() traceback.print_exc()
@ -73,57 +86,52 @@ class CompilerHelper(Options):
def __str__(self): def __str__(self):
return self.as_markdown() return self.as_markdown()
def as_markdown(self) -> str: def as_markdown(self, longest: Optional[int] = None) -> str:
front = super().as_markdown() front = super().as_markdown(longest)
gen_cmd = self.gen_subprocess_cmd() gen_cmd = self.gen_subprocess_cmd()
return f"{front}\n\n```bash\n{' '.join(gen_cmd)}\n```" return f"{front}\n\n```bash\n{' '.join(gen_cmd)}\n```"
def gen_subprocess_cmd(self) -> List[str]: def gen_subprocess_cmd(self) -> List[str]:
cmd_list = [self.python_cmd, '-m', 'nuitka'] cmd_list = [self.python_cmd, '-m', 'nuitka']
# macos 和 非 macos icon 参数不同 # macos 和 非 macos icon 参数不同
icon_cmd = ""
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
icon_cmd = f"--macos-app-icon={self.icon_path.absolute()}" cmd_list.append(f"--macos-app-version={self.product_version}")
_add_cmd(cmd_list, f'--macos-app-icon={self.icon_path.absolute()}' if self.icon_path else None)
elif platform.system() == 'Windows': elif platform.system() == 'Windows':
icon_cmd = f"--windows-icon-from-ico={self.icon_path.absolute()}" _add_cmd(cmd_list, f'--windows-icon-from-ico={self.icon_path.absolute()}' if self.icon_path else None)
elif platform.system() == 'Linux':
_add_cmd(cmd_list, f'--linux-icon={self.icon_path.absolute()}' if self.icon_path else None)
if self.use_lto: _add_cmd(cmd_list, '--lto=yes' if self.use_lto else '--lto=no')
cmd_list.append('--lto=yes') _add_cmd(cmd_list, '--clang' if self.use_clang else None)
else: _add_cmd(cmd_list, '--msvc=latest' if self.use_msvc else None)
cmd_list.append('--lto=no') _add_cmd(cmd_list, '--mingw64' if self.use_mingw else None)
_add_cmd(cmd_list, '--standalone' if self.standalone else None)
if self.use_clang: _add_cmd(cmd_list, '--disable-ccache' if not self.use_ccache else None)
cmd_list.append('--clang') _add_cmd(cmd_list, '--show-progress' if self.show_progress else None)
if self.use_msvc: _add_cmd(cmd_list, '--show-memory' if self.show_memory else None)
cmd_list.append('--msvc=latest') _add_cmd(cmd_list, '--assume-yes-for-download' if self.download_confirm else None)
if self.standalone: _add_cmd(cmd_list, '--enable-console' if self.enable_console else '--disable-console')
cmd_list.append('--standalone')
if not self.use_ccache:
cmd_list.append('--disable-ccache')
if self.show_progress:
cmd_list.append('--show-progress')
if self.show_memory:
cmd_list.append('--show-memory')
if self.download_confirm:
cmd_list.append('--assume-yes-for-download')
if self.save_xml:
cmd_list.append(f'--xml={self.xml_path.absolute()}')
cmd_list.append(f"--output-dir={self.output_path.absolute()}") _add_cmd(cmd_list, f'--xml={self.xml_path.absolute()}' if self.save_xml else None)
_add_cmd(cmd_list, f'--output-dir={self.output_path.absolute()}' if self.output_path else None)
_add_cmd(cmd_list, f'--company-name={self.company_name}' if self.company_name else None)
_add_cmd(cmd_list, f'--product-name={self.product_name}' if self.product_name else None)
_add_cmd(cmd_list, f'--file-version={self.file_version}' if self.file_version else None)
_add_cmd(cmd_list, f'--product-version={self.product_version}' if self.product_version else None)
_add_cmd(cmd_list, f'--file-description={self.file_description}' if self.file_description else None)
_add_cmd(cmd_list, f'--copyright={self.copy_right}' if self.copy_right else None)
cmd_list.append(f"--company-name={self.company_name}") _add_cmd(cmd_list, f'--follow-import-to={",".join(self.follow_import)}' if self.follow_import else None)
cmd_list.append(f"--product-name={self.product_name}") _add_cmd(cmd_list, f'--nofollow-import-to={",".join(self.no_follow_import)}' if self.no_follow_import else None)
cmd_list.append(f"--product-version={self.product_version}") _add_cmd(cmd_list, f'--enable-plugin={",".join(self.enable_plugin)}' if self.enable_plugin else None)
cmd_list.append(f"--file-version={self.file_version}") _add_cmd(cmd_list, f'--disable-plugin={",".join(self.disable_plugin)}' if self.disable_plugin else None)
if icon_cmd:
cmd_list.append(icon_cmd)
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"--follow-import-to={','.join(self.follow_import)}")
cmd_list.append(f"--nofollow-import-to={','.join(self.no_follow_import)}")
cmd_list.append(f"{self.src_file}") cmd_list.append(f"{self.src_file}")
return cmd_list return cmd_list

View File

@ -1,3 +0,0 @@
python3.8 setup.py build
python3.9 setup.py build
python3.9 post_build.py

View File

@ -4,18 +4,23 @@
# All rights reserved # All rights reserved
# ------------------------------- # -------------------------------
import logging
import warnings import warnings
import traceback import traceback
from typing import Optional from typing import Optional
from Difficult_Rocket import DR_status
from Difficult_Rocket.main import Game from Difficult_Rocket.main import Game
from Difficult_Rocket.main import Console
from Difficult_Rocket.api.mod import ModInfo from Difficult_Rocket.api.mod import ModInfo
from Difficult_Rocket.api.types import Options, Version
from Difficult_Rocket.client import ClientWindow from Difficult_Rocket.client import ClientWindow
from Difficult_Rocket.api.types import Options, Version
DR_rust_version = Version("0.2.10.1") # DR_mod 的 Rust 编写部分的兼容版本 DR_rust_version = Version("0.2.10.1") # DR_mod 的 Rust 编写部分的兼容版本
logger = logging.getLogger('client.dr_game')
class _DR_mod_runtime(Options): class _DR_mod_runtime(Options):
name = 'DR mod runtime' name = 'DR mod runtime'
@ -32,7 +37,8 @@ class _DR_mod_runtime(Options):
self.DR_rust_available = True self.DR_rust_available = True
if self.DR_rust_get_version != self.DR_rust_version: 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' 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'Builtin version {relationship} than true version')
self.use_DR_rust = self.use_DR_rust and self.DR_rust_available self.use_DR_rust = self.use_DR_rust and self.DR_rust_available
except Exception: except Exception:
@ -46,10 +52,9 @@ DR_mod_runtime = _DR_mod_runtime()
class DR_mod(ModInfo): class DR_mod(ModInfo):
mod_id = "difficult_rocket_mod" mod_id = "difficult_rocket_mod"
name = "Difficult Rocket mod" name = "Difficult Rocket mod"
version = Version("0.1.0.0") version = Version("0.2.0.0")
writer = "shenjackyuanjie" writer = "shenjackyuanjie"
link = "shenjack.top" link = "shenjack.top"
@ -58,7 +63,8 @@ class DR_mod(ModInfo):
config = DR_mod_runtime config = DR_mod_runtime
# DR_version = # DR SDK 兼容版本 DR_version = (DR_status.DR_version, DR_status.DR_version) # DR SDK 兼容版本
# 反正是内置 mod 跟着最新版本的 DR 走就行了 # 反正是内置 mod 跟着最新版本的 DR 走就行了
# DR_Api_version = # DR Api版本 # DR_Api_version = # DR Api版本
# 同理 不管 API 版本 这东西要是不兼容了才是大问题 # 同理 不管 API 版本 这东西要是不兼容了才是大问题
@ -74,15 +80,23 @@ class DR_mod(ModInfo):
game.client.window.add_sub_screen("SR1_ship", old_self.screen) game.client.window.add_sub_screen("SR1_ship", old_self.screen)
else: else:
self.config.flush_option() self.config.flush_option()
print("DR_mod: on_load") logger.info("on_load")
print(self.as_markdown()) logger.info(self.as_markdown())
return True return True
def on_client_start(self, game: Game, client: ClientWindow): def on_client_start(self, game: Game, client: ClientWindow):
from .sr1_ship import SR1ShipRender from .sr1_ship import SR1ShipRender
self.screen = SR1ShipRender self.screen = SR1ShipRender
print('DR_mod: on_client_start')
client.add_sub_screen("SR1_ship", SR1ShipRender) client.add_sub_screen("SR1_ship", SR1ShipRender)
logger.info('on_client_start added sub screen')
def on_unload(self, game: Game):
if DR_mod_runtime.DR_rust_available:
game.console.stop()
game.console_class = Console
logger.info('replace Console class')
game.init_console()
logger.info('reinit console')
mod_class = DR_mod mod_class = DR_mod

View File

@ -4,12 +4,12 @@
# All rights reserved # All rights reserved
# ------------------------------- # -------------------------------
import math # import math
import time import time
import random import random
import logging import logging
import traceback import traceback
from xml.etree import ElementTree # from xml.etree import ElementTree
from xml.etree.ElementTree import Element from xml.etree.ElementTree import Element
from typing import List, TYPE_CHECKING, Union, Dict, Optional, Generator from typing import List, TYPE_CHECKING, Union, Dict, Optional, Generator
@ -21,13 +21,13 @@ from pyglet.math import Vec4
from pyglet.text import Label from pyglet.text import Label
from pyglet.shapes import Line, Rectangle from pyglet.shapes import Line, Rectangle
from pyglet.sprite import Sprite from pyglet.sprite import Sprite
from pyglet.image import Texture # from pyglet.image import Texture
from pyglet.graphics import Batch, Group from pyglet.graphics import Batch, Group
from . import DR_mod_runtime from . import DR_mod_runtime
# Difficult Rocket # Difficult Rocket
from Difficult_Rocket import DR_option from Difficult_Rocket import DR_status
from Difficult_Rocket.utils.translate import tr from Difficult_Rocket.utils.translate import tr
from Difficult_Rocket.api.types import Fonts, Options from Difficult_Rocket.api.types import Fonts, Options
from Difficult_Rocket.command.line import CommandText from Difficult_Rocket.command.line import CommandText
@ -40,7 +40,7 @@ if TYPE_CHECKING:
if DR_mod_runtime.use_DR_rust: if DR_mod_runtime.use_DR_rust:
from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, SR1Ship_rs from .Difficult_Rocket_rs import CenterCamera_rs, SR1PartList_rs, SR1Ship_rs
logger = logging.getLogger('client') logger = logging.getLogger('client.dr_game_sr1_ship')
def get_sr1_part(part_xml: Element) -> Optional[SR1PartData]: def get_sr1_part(part_xml: Element) -> Optional[SR1PartData]:
@ -124,7 +124,7 @@ class SR1ShipRender(BaseScreen):
self.part_box_batch = Batch() self.part_box_batch = Batch()
self.part_batch = Batch() self.part_batch = Batch()
self.part_group = Group() self.part_group = Group()
self.debug_label = Label(x=20, y=main_window.height - 20, font_size=DR_option.std_font_size, self.debug_label = Label(x=20, y=main_window.height - 20, font_size=DR_status.std_font_size,
text='SR1 render!', font_name=Fonts.微软等宽无线, text='SR1 render!', font_name=Fonts.微软等宽无线,
width=main_window.width - 20, height=20, width=main_window.width - 20, height=20,
anchor_x='left', anchor_y='top') anchor_x='left', anchor_y='top')
@ -171,7 +171,7 @@ class SR1ShipRender(BaseScreen):
self.drawing = True self.drawing = True
for part_id, part in part_datas.items(): for part_id, part in part_datas.items():
# 下面就是调用 pyglet 去渲染的部分 # 下面就是调用 pyglet 去渲染的部分
# render_scale = DR_option.gui_scale # 这个是 DR 的缩放比例 可以调节的( # render_scale = DR_status.gui_scale # 这个是 DR 的缩放比例 可以调节的(
# 主要是 Windows 下有一个缩放系数嘛,我待会试试这玩意能不能获取(估计得 ctypes # 主要是 Windows 下有一个缩放系数嘛,我待会试试这玩意能不能获取(估计得 ctypes
# 在不缩放的情况下XML的1个单位长度对应60个像素 # 在不缩放的情况下XML的1个单位长度对应60个像素
render_x = part.x * 60 render_x = part.x * 60

View File

@ -79,9 +79,11 @@ if __name__ == '__main__':
if f'pyglet.{lib}.{name}' in compiler.no_follow_import: if f'pyglet.{lib}.{name}' in compiler.no_follow_import:
compiler.no_follow_import.remove(f'pyglet.{lib}.{name}') compiler.no_follow_import.remove(f'pyglet.{lib}.{name}')
print(compiler.output_path) print(compiler.as_markdown(longest=70))
print(compiler) if is_github:
from pprint import pprint
pprint(compiler.option())
print(compiler.gen_subprocess_cmd()) print(compiler.gen_subprocess_cmd())
@ -133,7 +135,7 @@ if __name__ == '__main__':
'dist_size_mb': dist_dir_size / 1024 / 1024, 'dist_size_mb': dist_dir_size / 1024 / 1024,
'compiler_data': compiler.str_option(), 'compiler_data': compiler.str_option(),
'dist_file_size': dist_file_size} 'dist_file_size': dist_file_size}
with open(compiler.output_path / f'../compile_data-{time.time()}.toml', 'w') as compile_data_file: with open(compiler.output_path / f'../compile_data-{time.time()}.toml', 'w', encoding='utf-8') as compile_data_file:
tomlkit.dump(compile_data, compile_data_file) tomlkit.dump(compile_data, compile_data_file)
sys.exit(0) sys.exit(0)

View File

@ -6,7 +6,7 @@ build-backend = "pdm.pep517.api"
[project] [project]
name = "difficult-rocket" name = "difficult-rocket"
version = "0.8.2.0" version = "0.8.3.0"
description = "A rocket game" description = "A rocket game"
authors = [ authors = [
{name = "shenjackyuanjie", email = "3695888@qq.com"} {name = "shenjackyuanjie", email = "3695888@qq.com"}

View File

@ -3,7 +3,8 @@
# DR build (by nuitka) # DR build (by nuitka)
# for images # for images
pillow >= 9.5.0 # not for pypy >= 3.10
pillow >= 9.5.0; (platform_python_implementation == "PyPy" and python_version < "3.10") or platform_python_implementation == "CPython"
# for sys info # for sys info
psutil >= 5.9.5 psutil >= 5.9.5
@ -17,9 +18,9 @@ defusedxml >= 0.7.1
objprint >= 0.2.2 objprint >= 0.2.2
# for compile # for compile
nuitka >= 1.6.1 nuitka >= 1.6.3
ordered-set >= 4.1.0 ordered-set >= 4.1.0
imageio >= 2.31.0 imageio >= 2.31.0; (platform_python_implementation == "PyPy" and python_version < "3.10") or platform_python_implementation == "CPython"
wheel >= 0.40.0 wheel >= 0.40.0
setuptools >= 67.8.0 setuptools >= 67.8.0
setuptools-rust >= 1.6.0 setuptools-rust >= 1.6.0

View File

@ -4,7 +4,8 @@
# DR contributing # DR contributing
# for images # for images
pillow >= 9.5.0 # not for pypy >= 3.10
pillow >= 9.5.0; (platform_python_implementation == "PyPy" and python_version < "3.10") or platform_python_implementation == "CPython"
# for sys info # for sys info
psutil >= 5.9.5 psutil >= 5.9.5
@ -16,13 +17,13 @@ defusedxml >= 0.7.1
# for debug # for debug
objprint >= 0.2.2 objprint >= 0.2.2
viztracer >= 0.15.6 viztracer >= 0.15.6; platform_python_implementation != "PyPy"
vizplugins >= 0.1.3 vizplugins >= 0.1.3; platform_python_implementation != "PyPy"
# for compile # for compile
nuitka >= 1.6.1 nuitka >= 1.6.3
ordered-set >= 4.1.0 ordered-set >= 4.1.0
imageio >= 2.31.0 imageio >= 2.31.0; (platform_python_implementation == "PyPy" and python_version < "3.10") or platform_python_implementation == "CPython"
wheel >= 0.40.0 wheel >= 0.40.0
setuptools >= 67.8.0 setuptools >= 67.8.0
setuptools-rust >= 1.6.0 setuptools-rust >= 1.6.0

View File

@ -2,7 +2,8 @@
# DR basic running from source # DR basic running from source
# for images # for images
pillow >= 9.5.0 # not for pypy >= 3.10
pillow >= 9.5.0; platform_python_implementation == "PyPy" and python_version < "3.10"
# for sys info # for sys info
psutil >= 5.9.5 psutil >= 5.9.5