好活!

readme update

看起来更像 Dear ImGui 一些(looks more like Dear ImGui

and some intersting feature to the button

remove debug

确认一下action

404 修改

writing theme

looks good

better?

a ?

alpha=255 not 256

looks better

try new pyglet first

看起来好一些

sync pyglet

水一手

这波必须得水一手了,要不然commit太少了(确信

丢点正经东西上去

顺手继承一下Options

补充docs

坏了,忘记水commit了(

至少我能早睡了(

这里还能水一点来着(

试试再说

reee

保证能跑(

同步lib not dr 的修改

忘记带上 None了

还是加上一个额外的判断参数吧

刷点commit也不错

先更新一下依赖版本

水commit啦

理论可行,实践开始!

构建参数喜加一

reeeee

更新一下 pyproject 的依赖

fix typing

looks better

水一个(

测试?

sync pyglet to master

A | Try use rust-cache

looks good?

what?

C | sync pyglet

A | 添加了一个 Button Draw Theme

A | Magic Number (确信)

A | 尽量不继承Options

sync pyglet

A | Add theme

A | Add more Theme information

Enhance | Theme

sync pyglet

Add | add unifont

Enhance | use os.walk in font loading

Enhance | Use i18n in font loading

Enhance | doc

sync pyglet

Add | add 3.12 build option to build_rs

Fix | Button position have a z

sync pyglet

A | Logger.py 启动!

sync pyglet

Changed | Bump pyo3 to 0.20.0

add logger.py update

logger!

Add | more logger!

Add | lib-not-dr

some lib-not-dr
This commit is contained in:
shenjack 2023-08-27 01:52:45 +08:00
parent 0a4de29d5a
commit f9eeafe322
Signed by: shenjack
GPG Key ID: 7B1134A979775551
69 changed files with 2106 additions and 627 deletions

View File

@ -34,6 +34,13 @@ jobs:
- name: Check out
uses: actions/checkout@v3
# 缓存 Rust 构建
- name: Cache rust
uses: Swatinem/rust-cache@v2
with:
workspace: mods/dr_game/Difficult_Rocket_rs
key: dr_rs-v1
# 获取短 sha
- name: Get short commit sha
id: get_short_sha

View File

@ -108,6 +108,7 @@ def main():
return 0
dsm.clear_dsm()
dsm.upload_docs('docs/md5.txt')
dsm.fl.logout()

View File

@ -10,7 +10,10 @@ import rtoml
sys.path.append(os.path.abspath(os.curdir))
from Difficult_Rocket import DR_status
try:
from Difficult_Rocket import DR_status
except ImportError:
raise
args = ['-env', '-github-dev']

2
DR.py
View File

@ -43,7 +43,7 @@ def start(start_time_ns: int) -> None:
main_game.start()
if DR_status.crash_report_test:
raise TestError('debug crash test')
except:
except: # noqa: E722
trace = traceback.format_exc()
crash.create_crash_report(trace)
print(trace)

View File

@ -11,7 +11,7 @@ from pathlib import Path
from Difficult_Rocket.api.types import Options, Version
sdk_version = Version("0.8.7.0") # SDK 版本
build_version = Version("2.1.3.0") # 编译文件版本(与游戏本体无关)
build_version = Version("2.2.0.0") # 编译文件版本(与游戏本体无关)
Api_version = Version("0.1.1.0") # API 版本
__version__ = sdk_version

View File

@ -11,6 +11,7 @@ from os import PathLike
from pyglet.event import EventDispatcher
# Difficult Rocket function
from Difficult_Rocket.api.types import Options
from Difficult_Rocket.command.api import CommandText
if TYPE_CHECKING:
@ -19,11 +20,13 @@ else:
ClientWindow = TypeVar("ClientWindow")
class BaseScreen(EventDispatcher):
class BaseScreen(EventDispatcher, Options):
"""
DR 页面API
"""
name: str = 'BaseScreen'
def __init__(self, main_window: ClientWindow):
super().__init__()
self.focus = False

View File

@ -119,26 +119,28 @@ def pyglet_load_fonts_folder(folder) -> None:
if not font_path.exists():
font_path.mkdir(parents=True)
return None
file_folder_list = os.listdir(folder)
for obj in file_folder_list:
if os.path.isfile(os.path.join(folder, obj)):
if obj[-4:] == '.ttf' or obj[-4:] == '.otf':
logger.debug(f'loading font {os.path.join(folder, obj)}')
logger.info(tr().client.load.font.start().format(font_path))
start_time = time.time_ns()
for dir_path, dir_names, file_names in os.walk(font_path):
dir_path = Path(dir_path)
for file_name in file_names:
file_name = Path(file_name)
if file_name.suffix in ('.ttf', '.otf'):
logger.debug(tr().client.load.font.file().format(str(dir_path / file_name)))
try:
pyglet.font.add_file(os.path.join(folder, obj))
pyglet.font.add_file(str(dir_path / file_name))
except Exception:
logger.error(traceback.format_exc())
logger.error(f'loading font {os.path.join(folder, obj)} failed')
else:
logger.info(f'loading font folder {os.path.join(folder, obj)}')
pyglet_load_fonts_folder(os.path.join(folder, obj))
logger.error(tr().client.load.font.error().format(str(dir_path / file_name), traceback.format_exc()))
end_time = time.time_ns()
use_time = end_time - start_time
logger.info(tr().client.load.font.use_time().format(use_time / 1000000000))
def _call_back(call_back: Callable) -> Callable:
"""
>>> def call_back():
>>> def call_back_example():
>>> pass
>>> @_call_back(call_back)
>>> @_call_back(call_back_example)
>>> def on_draw(self):
>>> pass
用于在调用窗口函数后调用指定函数 的装饰器
@ -149,7 +151,7 @@ def _call_back(call_back: Callable) -> Callable:
@functools.wraps(func)
def warp(self: "ClientWindow", *args, **kwargs):
result = func(self, *args, **kwargs)
call_back(self)
# call_back(self)
return result
return warp
return wrapper
@ -256,7 +258,7 @@ class ClientWindow(Window):
end_time = time.time_ns()
self.use_time = end_time - start_time
DR_runtime.client_setup_cause_ns = self.use_time
self.logger.info(tr().window.setup.use_time().format(Decimal(self.use_time) / 1000000000))
self.logger.info(tr().window.setup.use_time().format(self.use_time / 1000000000))
self.logger.debug(tr().window.setup.use_time_ns().format(self.use_time))
self.count = 0
@ -321,7 +323,7 @@ class ClientWindow(Window):
def on_draw(self):
while (command := self.game.console.get_command()) is not None:
self.on_command(line.CommandText(command))
pyglet.gl.glClearColor(0.1, 0, 0, 0.0)
pyglet.gl.glClearColor(21/255, 22/255, 23/255, 0.0)
self.clear()
# self.draw_update(dt) # TODO: wait for pyglet 2.1
self.draw_update(float(self.SPF))
@ -376,10 +378,10 @@ class ClientWindow(Window):
self.logger.debug(self.fps_log.fps_list)
elif command.find('max'):
self.logger.info(self.fps_log.max_fps)
self.command.push_line(self.fps_log.max_fps, block_line=True)
# self.command.push_line(self.fps_log.max_fps, block_line=True)
elif command.find('min'):
self.logger.info(self.fps_log.min_fps)
self.command.push_line(self.fps_log.min_fps, block_line=True)
# self.command.push_line(self.fps_log.min_fps, block_line=True)
elif command.find('default'):
self.set_size(int(self.main_config['window_default']['width']),
int(self.main_config['window_default']['height']))

View File

@ -4,14 +4,7 @@
# All rights reserved
# -------------------------------
"""
writen by shenjackyuanjie
mail: 3695888@qq.com
github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
from typing import Optional, Union, Tuple
from typing import Optional, Tuple
# from libs import pyglet
import pyglet
@ -23,7 +16,7 @@ from pyglet.shapes import Rectangle
# from pyglet.image import AbstractImage
from pyglet.graphics import Batch, Group
from Difficult_Rocket.api.types import Fonts
from Difficult_Rocket.api.types import Options, FontData
# from Difficult_Rocket import DR_status
@ -31,19 +24,67 @@ from Difficult_Rocket.api.types import Fonts
RGBA = Tuple[int, int, int, int]
class BaseTheme:
class ButtonDrawTheme:
"""
用于定义主题的类
直接绘制按钮的风格
"""
name = 'ButtonDrawTheme'
def __init__(self,
main_color: RGBA = (39, 73, 114, 256),
secondary_color: RGBA = (66, 150, 250, 256),
main_font: str = Fonts.鸿蒙简体,
):
self.main_color = main_color
self.secondary_color = secondary_color
self.main_font = main_font
batch: Batch,
group: Group):
self.batch = batch
self.group = group
a = (72, 73, 74)
b = (109, 109, 110)
c = (88, 91, 92)
d = (124, 124, 125)
e = (49, 50, 51)
touch_a = (49, 50, 51)
touch_b = (90, 91, 92)
touch_c = (71, 72, 72)
touch_d = (106, 107, 108)
def on_touch(self, x, y) -> None:
"""
当鼠标在按钮上的时候
:param x: 鼠标绝对位置
:param y: 鼠标绝对位置
:return:
"""
def on_move_away(self) -> None:
"""
当鼠标移出按钮的时候
:return:
"""
def on_hit(self, x: int, y: int) -> None:
"""
当鼠标点击按钮的时候
:param x: 鼠标绝对位置
:param y: 鼠标绝对位置
:return:
"""
def on_release(self) -> None:
"""
当鼠标松开按钮的时候
:return:
"""
class ButtonThemeOptions(Options):
""" 基于 Options 写的 ButtonTheme """
name = 'ButtonTheme'
untouched_color: RGBA = (39, 73, 114, 255)
touched_color: RGBA = (66, 150, 250, 255)
hit_color: RGBA = (15, 135, 250, 255)
font_theme: FontData = FontData()
def __str__(self):
return self.as_markdown()
class PressTextButton(widgets.WidgetBase):
@ -57,38 +98,39 @@ class PressTextButton(widgets.WidgetBase):
width: int,
height: int,
text: str,
font_name: str = Fonts.鸿蒙简体,
font_size: int = 15,
batch: Optional[Batch] = None,
group: Optional[Group] = None,
theme: Optional[ButtonThemeOptions] = None,
):
super().__init__(x, y, width, height)
self.back_ground_batch = batch or Batch()
self.front_batch = batch or Batch()
if group:
self.front_group = Group(order=10, parent=group)
self.back_ground_group = Group(order=5, parent=group)
else:
self.front_group = Group(order=5)
self.back_ground_group = Group(order=10)
self.main_batch = batch or Batch()
self.user_batch = batch is not None
self.front_group = Group(order=10, parent=group)
self.back_ground_group = Group(order=5, parent=group)
self.pressed = False
self.untouched_color = (39, 73, 114, 255)
self.touched_color = (66, 150, 250, 255)
self.hit_color = (15, 135, 250, 255)
self.theme = theme or ButtonThemeOptions()
self.untouched_color = self.theme.untouched_color
self.touched_color = self.theme.touched_color
self.hit_color = self.theme.hit_color
# from ImGui
self.text = text
self.text_label = Label(font_name=font_name, font_size=font_size,
batch=self.front_batch, group=self.front_group,
self.text_label = Label(font_name=self.theme.font_theme.font_name, font_size=self.theme.font_theme.font_size,
batch=self.main_batch, group=self.front_group,
x=self._x, y=self._y, width=self._width,
height=self._height,)
self.font = pyglet.font.load(font_name, font_size)
self.font = pyglet.font.load(self.theme.font_theme.font_name,
self.theme.font_theme.font_size,
bold=self.theme.font_theme.bold,
italic=self.theme.font_theme.italic,
stretch=self.theme.font_theme.stretch)
self.font_height = self.font.ascent - self.font.descent
self.back_rec = Rectangle(x=self._x, y=self._y,
width=self._width, height=self._height,
color=self.untouched_color, # ImGui color
batch=self.back_ground_batch, group=self.back_ground_group)
batch=self.main_batch, group=self.back_ground_group)
self.value = text # 重新分配一下高度和宽度的位置
@ -103,12 +145,14 @@ class PressTextButton(widgets.WidgetBase):
text_width = self.text_label.content_width
self.text_label.x = self._x + (self.width - text_width) // 2
self.text_label.y = self._y + (self.height - self.font_height) // 2 + (self.font_height * 0.2) # 修正一下位置
print(self.text_label.x, self.text_label.y)
print(self.height, self.font_height)
def __contains__(self, item):
return item in self.back_rec
def on_draw(self):
if not self.user_batch:
self.main_batch.draw()
def on_mouse_motion(self, x, y, dx, dy):
if (x, y) in self.back_rec:
self.back_rec.color = self.touched_color
@ -130,14 +174,10 @@ class PressTextButton(widgets.WidgetBase):
self.pressed = False
def _update_position(self):
self.text_label.position = self._x, self._y
self.text_label.position = self._x, self._y, 0
self.back_rec.position = self._x, self._y
self.back_rec.width = self._width
self.back_rec.height = self._height
...
def on_press(self, x, y):
self.value += "1"
PressTextButton.register_event_type('on_press')

View File

@ -0,0 +1,50 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from typing import Optional, Tuple, TYPE_CHECKING
from pyglet.graphics import Batch, Group
class BaseTheme(dict):
"""
Base class of themes
"""
theme_name = 'BaseTheme'
def __init__(self, **kwargs):
super().__init__(**kwargs)
for k, v in kwargs.items():
if hasattr(self, k):
setattr(self, k, v)
if TYPE_CHECKING:
def init(self,
batch: Batch,
group: Group,
**kwargs) -> None:
"""
Init theme
:param batch: batch
:param group: group
:param kwargs: options
:return: None
"""
class FontTheme(BaseTheme):
"""
Base class of font themes
"""
theme_name = 'FontTheme'
font_name: Optional[str] = 'Times New Roman'
font_size: Optional[int] = 12
bold: Optional[bool] = False
italic: Optional[bool] = False
stretch: Optional[bool] = False
color: Optional[Tuple[int, int, int, int]] = (255, 255, 255, 255)
align: Optional[str] = 'center'

View File

@ -0,0 +1,49 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from typing import Optional, Tuple
from pyglet.shapes import Rectangle
from pyglet.graphics import Batch, Group
from Difficult_Rocket.gui.widget.theme import BaseTheme, FontTheme
_RGBA = Tuple[int, int, int, int]
class ButtonBaseTheme(BaseTheme):
"""
Base theme of button
inherit from BaseTheme and dict
按钮的基础主题
继承了 BaseTheme dict
"""
theme_name = 'Button Base Theme'
def init(self, batch: Batch, group: Group, **kwargs) -> None:
"""
Init theme
:param batch: batch
:param group: group
:param kwargs: options
:return: None
"""
self.batch = batch
self.group = group
self.font_theme = FontTheme(**kwargs)
class BlockTheme(ButtonBaseTheme):
"""
button theme: Block like button
"""
theme_name = 'Block Theme(button)'
main_color: _RGBA = (39, 73, 114, 255)
touch_color: _RGBA = (66, 150, 250, 255)
hit_color: _RGBA = (15, 135, 250, 255)
font_theme: FontTheme = FontTheme()

View File

@ -11,23 +11,23 @@ github: @shenjackyuanjie
gitee: @shenjackyuanjie
"""
import time
# import time
import logging
import traceback
# import traceback
import logging.config
import multiprocessing
from io import StringIO
from pathlib import Path
# from io import StringIO
# from pathlib import Path
from typing import List, Optional, Dict
from Difficult_Rocket.utils import tools
# from Difficult_Rocket.utils import tools
from Difficult_Rocket.api.types import Options
from Difficult_Rocket.utils.translate import tr
from Difficult_Rocket.runtime import DR_runtime
# from Difficult_Rocket.utils.translate import tr
# from Difficult_Rocket.runtime import DR_runtime
from Difficult_Rocket.mod.loader import ModManager
from Difficult_Rocket.utils.thread import new_thread
from Difficult_Rocket.crash import write_info_to_cache
# from Difficult_Rocket.crash import write_info_to_cache
from Difficult_Rocket import client, server, DR_status

View File

@ -61,9 +61,11 @@ class ModInfo(Options):
def __init__(self, **kwargs):
if not self.DR_version[0] <= DR_status.DR_version <= self.DR_version[1]:
warnings.warn(f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.DR_version}\nDR {self.DR_version} is required")
warnings.warn(f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.DR_version}\n"
f"DR {self.DR_version} is required")
if not self.DR_Api_version[0] <= DR_status.API_version <= self.DR_Api_version[1]:
warnings.warn(f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.API_version}\nDR {self.DR_Api_version} is required")
warnings.warn(f"mod {self.mod_id} version {self.version} is not support by DR {DR_status.API_version}\n"
f"DR {self.DR_Api_version} is required")
super().__init__(**kwargs)
def on_load(self, game: Game, old_self: Optional["ModInfo"] = None) -> bool:

View File

@ -14,7 +14,7 @@ from typing import List, Dict, Optional, TypeVar
from Difficult_Rocket.mod.api import ModInfo
from Difficult_Rocket.utils.translate import tr
from Difficult_Rocket.api.types import Options, Version
from Difficult_Rocket.api.types import Options
Game = TypeVar('Game')

View File

@ -7,7 +7,7 @@
from typing import Tuple, Optional
from pyglet.gl import gl_compat, gl
from pyglet.gl import gl
from pyglet.math import Mat4, Vec3
from pyglet.graphics import Group

View File

@ -58,7 +58,6 @@ key_type = Union[str, int, Hashable]
class Translates:
name = 'Translate'
def __init__(self, value: Union[Dict[str, Any], list, tuple, str],
config: Optional[TranslateConfig] = None,

View File

@ -24,7 +24,7 @@
[关于版本号的说明](./docs/src/version.md)
[![release version](https://img.shields.io/badge/Release-0.8.6.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![pre version](https://img.shields.io/badge/Pre_Release-0.8.6.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![pre version](https://img.shields.io/badge/Pre_Release-0.8.7.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![devlo version](https://img.shields.io/badge/Devloping-0.8.7-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)
@ -51,20 +51,20 @@
- `开发平台 1 - Windows 10 x64 22H2`
- Python `3.8.10` / `3.10.11`
- pillow `9.5.0`
- pillow `10.0.0`
- psutil `5.9.5`
- rtoml `0.9.0`
- tomlkit `0.11.8`
- tomlkit `0.12.1`
- defusedxml `0.7.1`
- objprint `0.2.2`
- viztracer `0.15.6`
- vizplugins `0.1.3`
- nuitka `1.6.6`
- nuitka `1.7.10`
- ordered-set `4.1.0`
- imageio `2.31.0`
- wheel `0.40.0`
- setuptools `67.8.0`
- setuptools-rust `1.6.0`
- imageio `2.31.2`
- wheel `0.41.2`
- setuptools `68.1.2`
- setuptools-rust `1.7.0`
- `AMD R5 5600X`
- `AMD RX 550 4G`

View File

@ -1,4 +1,4 @@
<PartTypes xmlns="https://raw.githubusercontent.com/wengh/SRxsd/master/SR/partlist.xsd">
<PartTypes xmlns="http://shenjack.top:81/files/DR/xsd/partlist.xsd">
<PartType id="pod-1" name="Command Pod Mk1" description="This is your ship's brain. Be careful with it." sprite="Pod.png" type="pod" mass="1.0" width="4" height="3" hidden="true">
<Damage disconnect="1500" explode="1500" explosionPower="5" explosionSize="10" />
<Shape>

5
assets/fonts/readme.md Normal file
View File

@ -0,0 +1,5 @@
# Fonts information
## Unifont
- current version: 15.1.02

BIN
assets/fonts/unifont.otf (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -47,6 +47,10 @@ setup.use_time = "Client loading has used: {} second"
setup.use_time_ns = "Client loading has used: {} nano second"
config.save.start = "Saving config……"
config.save.done = "Config saved"
load.font.start = "Font loading~ from folder {}"
load.font.file = "Loading font file: {}"
load.font.error = "Font {} Load failed\ntraceback: {}"
load.font.use_time = "Font loading has used: {} second"
[window]
setup.start = "Window start loading"

View File

@ -47,6 +47,10 @@ setup.use_time = "客户端载入花费: {} 秒"
setup.use_time_ns = "客户端载入花费: {} 纳秒"
config.save.start = "正在保存配置文件"
config.save.done = "配置文件保存完成"
load.font.start = "正在加载文件夹 {} 下的字体文件"
load.font.file = "正在加载字体文件: {}"
load.font.error = "字体加载失败: {}\n错误信息: {}"
load.font.use_time = "字体加载消耗时间: {} 秒"
[window]
setup.start = "游戏窗口加载开始"

View File

@ -4,7 +4,7 @@ Write-Output $args[0]
$do = 0
if ("38" -notin $args -and "39" -notin $args -and "310" -notin $args -and "311" -notin $args) {
if ("38" -notin $args -and "39" -notin $args -and "310" -notin $args -and "311" -notin $args -and "312" -notin $args) {
$do = 1
}
@ -22,6 +22,9 @@ if ($do -or "310" -in $args) {
if ($do -or "311" -in $args) {
python3.11 setup.py build
}
if ($do -or "312" -in $args) {
python3.12 setup.py build
}
python3.8 post_build.py

View File

@ -22,8 +22,8 @@
[About Versions](src/version.md)
[![release version](https://img.shields.io/badge/Release-0.8.6.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![pre version](https://img.shields.io/badge/Pre_Release-0.8.6.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![devlo version](https://img.shields.io/badge/Devloping-0.8.7-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![pre version](https://img.shields.io/badge/Pre_Release-0.8.7.0-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
[![devlo version](https://img.shields.io/badge/Devloping-0.8.8-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)
@ -49,20 +49,20 @@
- `Develop platform 1 - Windows 10 x64 22H2`
- Python `3.8.10` / `3.10.11`
- pillow `9.5.0`
- pillow `10.0.0`
- psutil `5.9.5`
- rtoml `0.9.0`
- tomlkit `0.11.8`
- tomlkit `0.12.1`
- defusedxml `0.7.1`
- objprint `0.2.2`
- viztracer `0.15.6`
- vizplugins `0.1.3`
- nuitka `1.6.6`
- nuitka `1.7.10`
- ordered-set `4.1.0`
- imageio `2.31.0`
- wheel `0.40.0`
- setuptools `67.8.0`
- setuptools-rust `1.6.0`
- imageio `2.31.2`
- wheel `0.41.2`
- setuptools `68.1.2`
- setuptools-rust `1.7.0`
- `AMD R5 5600X`
- `AMD RX 550 4G`

View File

@ -3,3 +3,5 @@
- 很明显,这里没有你想要的东西
- 404啦
aaaaaaa

View File

@ -2,7 +2,23 @@
# DR 构建 更新日志
- 最新构建版本号
- build_version: 2.1.3.0
- build_version: 2.2.0.0
## 20230917 build 2.2.0.0
### 修改
- 删掉了蹩脚的 `_add_cmd`
- 可读性更好的写法
- 反正建议自己去看源码修改
- 现在应该可以直接运行输出的脚本了
- 不需要手动给带空格的参数添加引号了
- 给 `--disable-plugin` 添加了
- `pyqt5`
- `tk-inter`
- 防止因为 `pyperclicp` 把他俩打包进来
- 添加了几行 `# noqa`
- 向 linker 低头
## 20230715 build 2.1.3.0

View File

@ -5,6 +5,47 @@
- DR sdk: 0.8.7.0
- DR api: 0.1.1.0
## Draft DR sdk 0.8.7.2
### Add
- `assets/fonts`
- `unifont.otf`
- `unifont v 15.1.02`
### Translate key
- Add
- `client`
- `load.font`
- `start`
- `file`
- `error`
- `use_time`
### Enhance
- `client.pyglet_load_fonts_folder`
- 现在使用 `os.walk` 遍历文件夹
- 使用 `tr` 进行日志记录
## DR sdk 0.8.7.1
### Add
- `BaseScreen`
- 现在继承了 `Options`
- 添加了 `name` 选项来识别名称
- Now inherits `Options`
- Added `name` option to identify name
- `gui.widget.PressTextButton`
- 作为 gui 的一部分
- 依然在测试阶段
- 有人发现 bug 请务必发 issue, 十分感谢
- As part of gui
- Still in the testing phase
- If you find a bug, please be sure to issue it, thank you very much
## DR sdk 0.8.7.0
### Add

View File

@ -0,0 +1,7 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
__version__ = '0.1.7'

View File

View File

@ -0,0 +1,40 @@
from dataclasses import dataclass, field
from typing import Set, List
class Parsed:
...
@dataclass
class Option:
name: str
shortcuts: List[str]
optional: bool
types: Set[type] = field(default_factory=lambda: {str})
@dataclass
class OptionGroup:
options: List[Option]
optional: bool = True
exclusive: bool = False
@dataclass
class Argument:
name: str
types: Set[type] = field(default_factory=lambda: {str})
@dataclass
class Flag:
name: str
shortcuts: List[str]
@dataclass
class FlagGroup:
flags: List[Flag]
exclusive: bool = False

View File

@ -0,0 +1,14 @@
class CallBackDescriptor:
def __init__(self, name):
self.callback_name = name
def __set__(self, instance, value):
assert getattr(instance, self.callback_name) is None, f"Attribute '{self.callback_name}' has been set."
instance.__dict__[self.callback_name] = value
def __get__(self, instance, owner):
return (
self
if instance is None
else instance.__dict__.get(self.callback_name)
)

View File

@ -0,0 +1,2 @@
class IllegalName(Exception):
"""名称或快捷名不合法"""

View File

@ -0,0 +1,130 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import re
from typing import Callable, List, Optional, Union, Set
from .data import Option, Argument, Flag, Parsed
from .descriptor import CallBackDescriptor
try:
from typing import Self
except ImportError:
from typing import TypeVar
Self = TypeVar("Self") # NOQA
from .exception import IllegalName
CallBack = Union[Callable[[str], None], str] # Equals to `Callable[[str], None] | str`
# 可调用对象或字符串作为回调
# A callable or str as callback
ParseArgFunc = Callable[[str], Optional[type]]
# 解析参数的函数,返回值为 None 时表示解析失败
# function to parse argument, return None when failed
EMPTY_WORDS = re.compile(r"\s", re.I)
def check_name(name: Union[str, List[str]]) -> None:
"""
Check the name or shortcuts of argument(s) or flag(s).
The name must not be empty str, and must not contains \\t or \\n or \\f or \\r.
If that not satisfy the requirements, it will raise exception `IllegalArgumentName`.
检查 参数或标记 名称或快捷方式 是否符合要求
名称必须是非空的字符串且不能包含 \\t \\n \\f \\r
如果不符合要求将会抛出 `IllegalArgumentName` 异常
:param name: arguments
:return: None
"""
if isinstance(name, str) and EMPTY_WORDS.search(name):
raise IllegalName("The name of argument must not contains empty words.")
elif isinstance(name, list) and all((not isinstance(i, str)) and EMPTY_WORDS.search(i) for i in name):
raise IllegalName("The name of shortcut must be 'str', and must not contains empty words.")
else:
raise TypeError("The type of name must be 'str' or 'list[str]'.")
class Literal:
_tip = CallBackDescriptor("_tip")
_func = CallBackDescriptor("_func")
_err_callback = CallBackDescriptor("_err_callback")
def __init__(self, name: str):
self.name: str = name
self.sub: List[Self] = []
self._tip: Optional[CallBack] = None
self._func: Optional[CallBack] = None
self._err_callback: Optional[CallBack] = None
self._opts: List[Option] = []
self._args: List[Argument] = []
self._flags: List[Flag] = []
def __call__(self, *nodes) -> Self:
self.sub += nodes
return self
def __repr__(self):
attrs = (k for k in self.__dict__ if not (k.startswith("__") and k.endswith("__")))
return f"{self.__class__.__name__}({', '.join(f'{k}={v!r}' for k in attrs if (v := self.__dict__[k]))})"
def arg(self, name: str, types: Optional[Set[type]] = None) -> Self:
Argument(name=name, types=types)
return self
def opt(
self,
name: str,
shortcuts: Optional[List[str]] = None,
optional: bool = True,
types: Optional[Set[type]] = None
) -> Self:
check_name(name)
if shortcuts is not None and len(shortcuts) != 0:
check_name(shortcuts)
self._opts.append(
Option(name=name, shortcuts=shortcuts, optional=optional, types=types)
)
return self
def opt_group(self, opts: List[Option], exclusive: bool = False):
...
def flag(self, name: str, shortcuts: Optional[List[str]] = None) -> Self:
check_name(name)
if shortcuts is not None and len(shortcuts) != 0:
check_name(shortcuts)
Flag(name=name, shortcuts=shortcuts)
...
return self
def flag_group(self, flags: List[Flag], exclusive: bool = False) -> Self:
...
return self
def error(self, callback: CallBack) -> Self:
self._err_callback = callback
return self
def run(self, func: CallBack) -> Self:
self._func = func
return self
def tip(self, tip: CallBack) -> Self:
self._tip = tip
return self
def parse(self, cmd: Union[str, List[str]]) -> Parsed:
...
def to_doc(self) -> str:
...
def builder(node: Literal) -> Literal:
...

View File

View File

@ -0,0 +1,472 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import platform
import warnings
from pathlib import Path
from typing import List, Tuple, Optional, Union, Any
from enum import Enum
from lib_not_dr.types import Options, Version, VersionRequirement
def ensure_cmd_readable(cmd: str) -> str:
"""
保证 参数中 不含空格
:param cmd: 要格式化的命令行参数
:return: 格式化后的命令行参数
"""
if ' ' in str(cmd):
return f'"{cmd}"'
return cmd
def format_cmd(arg_name: Optional[str] = None,
arg_value: Optional[Union[str, List[str]]] = None,
write: Optional[Any] = True) -> List[str]:
"""
用来格式化输出命令行参数
:param arg_name: 类似 --show-memory 之类的主项
:param arg_value: 类似 xxx 类的内容
:param write: 是否写入
:return: 直接拼接好的命令行参数 不带 =
"""
if not write:
return []
if arg_name is None:
return []
if arg_value is None:
return [arg_name]
if isinstance(arg_value, list):
arg_value = ','.join([ensure_cmd_readable(value) for value in arg_value])
return [f'{arg_name}{arg_value}']
arg_value = ensure_cmd_readable(arg_value)
return [f'{arg_name}{arg_value}']
class NuitkaSubConfig(Options):
"""
Nuitka 配置的子项
Nuitka configuration sub-items
"""
name = 'Nuitka Sub Configuration'
def gen_cmd(self) -> List[str]:
"""
生成命令行参数
:return:
"""
raise NotImplementedError
class NuitkaPluginConfig(NuitkaSubConfig):
"""
控制 nuitka plugin 相关参数的部分
Control part of nuitka's plugin related parameters
"""
name = 'Nuitka Plugin Configuration'
# --enable-plugin=PLUGIN_NAME
enable_plugin: List[str] = []
# --disable-plugin=PLUGIN_NAME
disable_plugin: List[str] = []
# --plugin-no-detection
plugin_no_detection: bool = False
# --user-plugin=PATH
user_plugin: List[Path] = []
# --show-source-changes
show_source_changes: bool = False
# --include-plugin-directory=MODULE/PACKAGE
include_plugin_dir: List[str] = []
# --include-plugin-files=PATTERN
include_plugin_files: List[str] = []
def gen_cmd(self) -> List[str]:
lst = []
lst += format_cmd('--enable-plugin=', self.enable_plugin, self.enable_plugin)
lst += format_cmd('--disable-plugin=', self.disable_plugin, self.disable_plugin)
lst += format_cmd('--plugin-no-detection' if self.plugin_no_detection else None)
lst += format_cmd('--user-plugin=', [str(plugin.absolute()) for plugin in self.user_plugin], self.user_plugin)
lst += format_cmd('--show-source-changes' if self.show_source_changes else None)
lst += format_cmd('--include-plugin-directory=', self.include_plugin_dir, self.include_plugin_dir)
lst += format_cmd('--include-plugin-files=', self.include_plugin_files, self.include_plugin_files)
return lst
class NuitkaIncludeConfig(NuitkaSubConfig):
"""
控制 nuitka include 数据 相关参数的部分
Control part of nuitka's include related parameters
"""
name = 'Nuitka Include Configuration'
# --include-package=PACKAGE
include_packages: List[str] = []
# --include-module=MODULE
include_modules: List[str] = []
# --prefer-source-code
# --no-prefer-source-code for --module
prefer_source_code: bool = False
# --follow-stdlib
follow_stdlib: bool = False
def gen_cmd(self) -> List[str]:
lst = []
lst += format_cmd('--include-package=', self.include_packages, self.include_packages)
lst += format_cmd('--include-module=', self.include_modules, self.include_modules)
lst += format_cmd('--prefer-source-code' if self.prefer_source_code else None)
lst += format_cmd('--no-prefer-source-code' if not self.prefer_source_code else None)
lst += format_cmd('--follow-stdlib' if self.follow_stdlib else None)
return lst
class NuitkaDataConfig(NuitkaSubConfig):
"""
控制 nuitka 数据 相关参数的部分
Control part of nuitka's data related parameters
"""
name = 'Nuitka Data Configuration'
# --include-package-data=PACKAGE=PACKAGE_PATH
include_package_data: List[Tuple[Path, Path]] = []
# --include-data-files=PATH=PATH
include_data_files: List[Tuple[Path, Path]] = []
# --include-data-dir=DIRECTORY=PATH
include_data_dir: List[Tuple[Path, Path]] = []
# --noinclude-data-files=PATH
no_include_data_files: List[Path] = []
# --list-package-data=LIST_PACKAGE_DATA
list_package_data: List[str] = []
# --list-package-dlls=LIST_PACKAGE_DLLS
list_package_dlls: List[str] = []
# --include-distribution-metadata=DISTRIBUTION
include_distribution_metadata: List[str] = []
class NuitkaBinaryInfo(Options):
"""
nuitka 构建的二进制文件的信息
nuitka build binary file information
"""
name = 'Nuitka Binary Info'
# --company-name=COMPANY_NAME
company_name: Optional[str] = None
# --product-name=PRODUCT_NAME
product_name: Optional[str] = None
# --file-version=FILE_VERSION
# --macos-app-version=MACOS_APP_VERSION
file_version: Optional[Union[str, Version]] = None
# --product-version=PRODUCT_VERSION
product_version: Optional[Union[str, Version]] = None
# --file-description=FILE_DESCRIPTION
file_description: Optional[str] = None
# --copyright=COPYRIGHT_TEXT
copyright: Optional[str] = None
# --trademarks=TRADEMARK_TEXT
trademarks: Optional[str] = None
# Icon
# --linux-icon=ICON_PATH
# --macos-app-icon=ICON_PATH
# --windows-icon-from-ico=ICON_PATH
# --windows-icon-from-exe=ICON_EXE_PATH
# 注意: 只有 Windows 下 才可以提供多个 ICO 文件
# 其他平台 和 EXE 下只会使用第一个路径
icon: Optional[List[Path]] = None
# Console
# --enable-console
# --disable-console
console: bool = True
# Windows UAC
# --windows-uac-admin
windows_uac_admin: bool = False
# --windows-uac-uiaccess
windows_uac_ui_access: bool = False
class NuitkaOutputConfig(Options):
"""
nuitka 构建的选项
nuitka build output information
"""
name = 'Nuitka Output Config'
# --output-dir=DIRECTORY
output_dir: Optional[Path] = None
# --output-filename=FILENAME
output_filename: Optional[str] = None
# --quiet
quiet: bool = False
# --no-progressbar
no_progressbar: bool = False
# --verbose
verbose: bool = False
# --verbose-output=PATH
verbose_output: Optional[Path] = None
# --show-progress
show_progress: bool = False
# --show-memory
show_memory: bool = False
# --show-scons
show_scons: bool = False
# --show-modules
show_modules: bool = False
# --show-modules-output=PATH
show_modules_output: Optional[Path] = None
# --xml=XML_FILENAME
xml: Optional[Path] = None
# --report=REPORT_FILENAME
report: Optional[Path] = None
# --report-diffable
report_diffable: bool = False
# --remove-output
remove_output: bool = False
# --no-pyo-file
no_pyo_file: bool = False
class NuitkaDebugConfig(Options):
"""
nuitka 构建的调试选项
nuikta build debug information
"""
name = 'Nuitka Debug Config'
# --debug
debug: bool = False
# --unstripped
strip: bool = True
# --profile
profile: bool = False
# --internal-graph
internal_graph: bool = False
# --trace-execution
trace_execution: bool = False
# --recompile-c-only
recompile_c_only: bool = False
# --generate-c-only
generate_c_only: bool = False
# --deployment
deployment: bool = False
# --no-deployment-flag=FLAG
deployment_flag: Optional[str] = None
# --experimental=FLAG
experimental: Optional[str] = None
class NuitkaTarget(Enum):
"""
用于指定 nuitka 构建的目标
Use to specify the target of nuitka build
exe: 不带任何参数
module: --module
standalone: --standalone
one_file: --onefile
"""
exe = ''
module = 'module'
standalone = 'standalone'
one_file = 'package'
class NuitkaScriptGenerator(Options):
"""
用于帮助生成 nuitka 构建脚本的类
Use to help generate nuitka build script
:arg main 需要编译的文件
"""
name = 'Nuitka Script Generator'
# --main=PATH
# 可以有多个 输入时需要包在列表里
main: List[Path]
# --run
run_after_build: bool = False
# --debugger
debugger: bool = False
# --execute-with-pythonpath
execute_with_python_path: bool = False
# --assume-yes-for-downloads
download_confirm: bool = True
# standalone/one_file/module/exe
target: NuitkaTarget = NuitkaTarget.exe
# --python-debug
python_debug: bool = False
# --python-flag=FLAG
python_flag: List[str] = []
# --python-for-scons=PATH
python_for_scons: Optional[Path] = None
class CompilerHelper(Options):
"""
用于帮助生成 nuitka 构建脚本的类
Use to help generate nuitka build script
"""
name = 'Nuitka Compiler Helper'
output_path: Path = Path('./build')
src_file: Path
python_cmd: str = 'python'
compat_nuitka_version: VersionRequirement = VersionRequirement("~1.8.0") # STATIC VERSION
# 以下为 nuitka 的参数
# nuitka options below
use_lto: bool = False # --lto=yes (no is faster)
use_clang: bool = True # --clang
use_msvc: bool = True # --msvc=latest
use_mingw: bool = False # --mingw64
onefile: bool = False # --onefile
onefile_tempdir: Optional[str] = '' # --onefile-tempdir-spec=
standalone: bool = True # --standalone
use_ccache: bool = True # not --disable-ccache
enable_console: bool = True # --enable-console / --disable-console
show_progress: bool = True # --show-progress
show_memory: bool = False # --show-memory
remove_output: bool = True # --remove-output
save_xml: bool = False # --xml
xml_path: Path = Path('build/compile_data.xml')
save_report: bool = False # --report
report_path: Path = Path('build/compile_report.xml')
download_confirm: bool = True # --assume-yes-for-download
run_after_build: bool = False # --run
company_name: Optional[str] = ''
product_name: Optional[str] = ''
file_version: Optional[Version] = None
product_version: Optional[Version] = None
file_description: Optional[str] = '' # --file-description
copy_right: Optional[str] = '' # --copyright
icon_path: Optional[Path] = None
follow_import: List[str] = []
no_follow_import: List[str] = []
include_data_dir: List[Tuple[str, str]] = []
include_packages: List[str] = []
enable_plugin: List[str] = [] # --enable-plugin=xxx,xxx
disable_plugin: List[str] = [] # --disable-plugin=xxx,xxx
def init(self, **kwargs) -> None:
if (compat_version := kwargs.get('compat_nuitka_version')) is not None:
if not self.compat_nuitka_version.accept(compat_version):
warnings.warn(
f"Nuitka version may not compat with {compat_version}\n"
"requirement: {self.compat_nuitka_version}"
)
# 非 windows 平台不使用 msvc
if platform.system() != 'Windows':
self.use_msvc = False
self.use_mingw = False
else:
self.use_mingw = self.use_mingw and not self.use_msvc
# Windows 平台下使用 msvc 时不使用 mingw
def __str__(self):
return self.as_markdown()
def as_markdown(self, longest: Optional[int] = None) -> str:
"""
输出编译器帮助信息
Output compiler help information
Args:
longest (Optional[int], optional):
输出信息的最大长度限制 The maximum length of output information.
Defaults to None.
Returns:
str: markdown 格式输出的编译器帮助信息
Compile helper information in markdown format
"""
front = super().as_markdown(longest)
gen_cmd = self.gen_subprocess_cmd()
return f"{front}\n\n```bash\n{' '.join(gen_cmd)}\n```"
def gen_subprocess_cmd(self) -> List[str]:
"""生成 nuitka 构建脚本
Generate nuitka build script
Returns:
List[str]:
生成的 nuitka 构建脚本
Generated nuitka build script
"""
cmd_list = [self.python_cmd, '-m', 'nuitka']
# macos 和 非 macos icon 参数不同
if platform.system() == 'Darwin':
cmd_list += format_cmd('--macos-app-version=', self.product_version, self.product_version)
cmd_list += format_cmd('--macos-app-icon=', self.icon_path.absolute(), self.icon_path)
elif platform.system() == 'Windows':
cmd_list += format_cmd('--windows-icon-from-ico=', self.icon_path.absolute(), self.icon_path)
elif platform.system() == 'Linux':
cmd_list += format_cmd('--linux-icon=', self.icon_path.absolute(), self.icon_path)
cmd_list += format_cmd('--lto=', 'yes' if self.use_lto else 'no')
cmd_list += format_cmd('--clang' if self.use_clang else None)
cmd_list += format_cmd('--msvc=latest' if self.use_msvc else None)
cmd_list += format_cmd('--mingw64' if self.use_mingw else None)
cmd_list += format_cmd('--standalone' if self.standalone else None)
cmd_list += format_cmd('--onefile' if self.onefile else None)
cmd_list += format_cmd('--onefile-tempdir-spec=', self.onefile_tempdir, self.onefile_tempdir)
cmd_list += format_cmd('--disable-ccache' if not self.use_ccache else None)
cmd_list += format_cmd('--show-progress' if self.show_progress else None)
cmd_list += format_cmd('--show-memory' if self.show_memory else None)
cmd_list += format_cmd('--remove-output' if self.remove_output else None)
cmd_list += format_cmd('--assume-yes-for-download' if self.download_confirm else None)
cmd_list += format_cmd('--run' if self.run_after_build else None)
cmd_list += format_cmd('--enable-console' if self.enable_console else '--disable-console')
cmd_list += format_cmd('--xml=', str(self.xml_path.absolute()), self.save_xml)
cmd_list += format_cmd('--report=', str(self.report_path.absolute()), self.save_report)
cmd_list += format_cmd('--output-dir=', str(self.output_path.absolute()), self.output_path)
cmd_list += format_cmd('--company-name=', self.company_name, self.company_name)
cmd_list += format_cmd('--product-name=', self.product_name, self.product_name)
cmd_list += format_cmd('--file-version=', str(self.file_version), self.file_version)
cmd_list += format_cmd('--product-version=', str(self.product_version), self.product_version)
cmd_list += format_cmd('--file-description=', self.file_description, self.file_description)
cmd_list += format_cmd('--copyright=', self.copy_right, self.copy_right)
cmd_list += format_cmd('--follow-import-to=', self.follow_import, self.follow_import)
cmd_list += format_cmd('--nofollow-import-to=', self.no_follow_import, self.no_follow_import)
cmd_list += format_cmd('--enable-plugin=', self.enable_plugin, self.enable_plugin)
cmd_list += format_cmd('--disable-plugin=', self.disable_plugin, self.disable_plugin)
if 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.append(f"--main={self.src_file}")
return cmd_list

View File

@ -0,0 +1,31 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from .options import (Options,
OptionsError,
OptionNotFound,
OptionNameNotDefined,
get_type_hints_)
from .version import (Version,
VersionRequirement,
VersionParsingError,
ExtraElement)
__all__ = [
# options
'get_type_hints_',
'Options',
'OptionsError',
'OptionNotFound',
'OptionNameNotDefined',
# version
'Version',
'VersionRequirement',
'VersionParsingError',
'ExtraElement'
]

View File

@ -0,0 +1,271 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import shutil
import traceback
from io import StringIO
from typing import get_type_hints, Type, List, Union, Dict, Any, Callable, Tuple, Optional, TYPE_CHECKING, Iterable
__all__ = [
'get_type_hints_',
'Options',
'OptionsError',
'OptionNotFound',
'OptionNameNotDefined'
]
def get_type_hints_(cls: Type):
try:
return get_type_hints(cls)
except ValueError:
return get_type_hints(cls, globalns={})
def to_str_value_(value: Any) -> Any:
"""递归的将输入值的每一个非 builtin type 转换成 str"""
if isinstance(value, (str, bytes, bytearray, int, float, bool, type(None))):
return value
elif isinstance(value, dict):
return {k: to_str_value_(v) for k, v in value.items()}
elif isinstance(value, (list, Iterable)):
return [to_str_value_(v) for v in value]
else:
return str(value)
class OptionsError(Exception):
""" option 的错误基类"""
class OptionNameNotDefined(OptionsError):
""" 向初始化的 option 里添加了一个不存在于选项里的选项 """
class OptionNotFound(OptionsError):
""" 某个选项没有找到 """
class Options:
"""
一个用于存储选项 / 提供 API 定义 的类
用法:
存储配置: 继承 Options
在类里定义 option: typing
(可选 定义 name: str = 'Option Base' 用于在打印的时候显示名字)
提供 API 接口: 继承 Options
在类里定义 option: typing
定义 一些需要的方法
子类: 继承 新的 Options
实现定义的方法
"""
name = 'Option Base'
cached_options: Dict[str, Union[str, Any]] = {}
def __init__(self, **kwargs):
"""
创建一个新的 Options 的时候的配置
如果存在 init 方法 会在设置完 kwargs 之后运行子类的 init 方法
:param kwargs: 需要设置的选项
"""
if TYPE_CHECKING:
self._options: Dict[str, Union[Callable, object]] = {}
self.flush_option()
for option, value in kwargs.items():
if option not in self.cached_options:
raise OptionNameNotDefined(f"option: {option} with value: {value} is not defined")
setattr(self, option, value)
run_load_file = True
if hasattr(self, 'init'):
run_load_file = self.init(**kwargs) # 默认 False/None
run_load_file = not run_load_file
if hasattr(self, 'load_file') and run_load_file:
try:
self.load_file()
except Exception:
traceback.print_exc()
self.flush_option()
def __str__(self):
return f"<{self.__class__.__name__} {self.name}>" if self.name else f"<{self.__class__.__name__}>"
def __repr__(self):
return self.__str__()
if TYPE_CHECKING:
_options: Dict[str, Union[Callable, object]] = {}
def init(self, **kwargs) -> bool:
""" 如果子类定义了这个函数,则会在 __init__ 之后调用这个函数
返回值为 True 则不会调用 load_file 函数
"""
def load_file(self) -> bool:
"""如果子类定义了这个函数,则会在 __init__ 和 init 之后再调用这个函数
请注意这个函数请尽量使用 try 包裹住可能出现错误的部分
否则会在控制台输出你的报错"""
return True
def option(self) -> Dict[str, Any]:
"""
获取配置类的所有配置
:return: 自己的所有配置
"""
values = {}
for ann in self.__annotations__: # 获取类型注释
values[ann] = getattr(self, ann, None)
if values[ann] is None:
values[ann] = self.__annotations__[ann]
if not hasattr(self, '_options'):
self._options: Dict[str, Union[Callable, object]] = {}
for option, a_fun in self._options.items(): # 获取额外内容
values[option] = a_fun
for option, a_fun in values.items(): # 检查是否为 property
if a_fun is bool and getattr(self, option, None) is not None:
values[option] = False
if isinstance(a_fun, property):
try:
values[option] = getattr(self, option)
except AttributeError:
raise OptionNotFound(f'Option {option} is not found in {self.name}') from None
return values
def str_option(self, shrink_to_long: Optional[int] = None) -> Dict[str, Union[str, Any]]:
"""
获取配置类的所有配置 并将所有非 BuiltIn 类型的值转换为 str
:return:
"""
raw_option = self.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:
"""
使用自己的选项给输入的字符串替换内容
:param text: 想替换的内容
:return: 替换之后的内容
"""
cache_option = self.flush_option()
for option, value in cache_option.items():
text = text.replace(f'{{{option}}}', str(value))
return text
def flush_option(self) -> Dict[str, Any]:
"""
刷新缓存 options 的内容
:return: 刷新过的 options
"""
self.cached_options = self.option()
return self.cached_options
def option_with_len(self) -> Tuple[List[Tuple[str, Any, Type]], int, int, int]:
"""
返回一个可以用于打印的 option 列表
:return:
"""
options = self.flush_option()
max_len_key = 1
max_len_value = 1
max_len_value_t = 1
option_list = []
for key, value in options.items():
value_t = type(value) if isinstance(value, type(value)) else type(value) # 判定这个类型 是不是 基本类型
max_len_key = max(max_len_key, len(key))
max_len_value = max(max_len_value, len(str(value)))
max_len_value_t = max(max_len_value_t, len(str(value_t)))
option_list.append([key, value, value_t])
return [option_list, max_len_key, max_len_value, max_len_value_t] # noqa
def as_markdown(self, longest: Optional[int] = None) -> str:
"""
返回一个 markdown 格式的 option 字符串
:param longest: 最长的输出长度
:return: markdown 格式的 option 字符串
"""
value = self.option_with_len()
cache = StringIO()
option_len = max(value[1], len('Option'))
value_len = max(value[2], len('Value'))
value_type_len = max(value[3], len('Value Type'))
# | Option | Value | Value Type |
shortest = len('Option | Value | Value Type')
if longest is not None:
console_width = max(longest, shortest)
else:
console_width = shutil.get_terminal_size(fallback=(100, 80)).columns
console_width = max(console_width, shortest)
# 为每一栏 预分配 1/3 或者 需要的宽度 (如果不需要 1/3)
option_len = min(option_len, console_width // 3)
value_len = min(value_len, console_width // 3)
value_type_len = min(value_type_len, console_width // 3)
# 先指定每一个列的输出最窄宽度, 然后去尝试增加宽度
# 循环分配新空间之前 首先检查是否已经不需要多分配 (and 后面)
while option_len + value_len + value_type_len + 16 < console_width\
and (option_len < value[1]
or value_len < value[2]
or value_type_len < value[3]):
# 每一个部分的逻辑都是
# 如果现在的输出长度小于原始长度
# 并且长度 + 1 之后的总长度依然在允许范围内
# 那么就 + 1
if option_len < value[1] and option_len + value_len + value_type_len + 16 < console_width:
option_len += 1
if value_len < value[2] and option_len + value_len + value_type_len + 16 < console_width:
value_len += 1
if value_type_len < value[3] and option_len + value_len + value_type_len + 16 < console_width:
value_type_len += 1
# 实际上 对于列表(可变对象) for 出来的这个值是一个引用
# 所以可以直接修改 string
for v in value[0]:
if len(str(v[0])) > option_len:
v[0] = f'{str(v[0])[:value_len - 3]}...'
if len(str(v[1])) > value_len:
v[1] = f'{str(v[1])[:value_len - 3]}...'
if len(str(v[2])) > value_type_len:
v[2] = f'{str(v[2])[:value_len - 3]}..'
cache.write(
f"| Option{' ' * (option_len - 3)}| Value{' ' * (value_len - 2)}| Value Type{' ' * (value_type_len - 7)}|\n")
cache.write(f'|:{"-" * (option_len + 3)}|:{"-" * (value_len + 3)}|:{"-" * (value_type_len + 3)}|\n')
for option, value, value_t in value[0]:
cache.write(f"| `{option}`{' ' * (option_len - len(option))} "
f"| `{value}`{' ' * (value_len - len(str(value)))} "
f"| `{value_t}`{' ' * (value_type_len - len(str(value_t)))} |\n")
result = cache.getvalue()
cache.close()
return result
@classmethod
def add_option(cls, name: str, value: Union[Callable, object]) -> Dict:
"""
向配置类中添加一个额外的配置
:param name: 配置的名字
:param value: 用于获取配置的函数或者类
:return: 配置类的所有配置
"""
if not hasattr(cls, '_options'):
cls._options: Dict[str, Union[Callable, object]] = {}
cls._options[name] = value
return cls._options
@staticmethod
def init_option(options_class: Type['Options'], init_value: Optional[dict] = None) -> 'Options':
return options_class(**init_value if init_value is not None else {})

View File

@ -0,0 +1,220 @@
# 本文件以 GNU Lesser General Public License v3.0GNU LGPL v3) 开源协议进行授权 (谢谢狐狸写出这么好的MCDR)
# 顺便说一句,我把所有的tab都改成了空格,因为我觉得空格比tab更好看(草,后半句是github copilot自动填充的)
"""
This part of code come from MCDReforged(https://github.com/Fallen-Breath/MCDReforged)
Thanks a lot to Fallen_Breath and MCDR contributors
GNU Lesser General Public License v3.0 (GNU LGPL v3)
"""
import re
from typing import List, Callable, Tuple, Optional, Union
"""
Plugin Version
"""
# beta.3 -> (beta, 3), random -> (random, None)
class ExtraElement:
DIVIDER = '.'
body: str
num: Optional[int]
def __init__(self, segment_str: str):
segments = segment_str.rsplit(self.DIVIDER, 1)
try:
self.body, self.num = segments[0], int(segments[1])
except (IndexError, ValueError):
self.body, self.num = segment_str, None
def __str__(self):
if self.num is None:
return self.body
return '{}{}{}'.format(self.body, self.DIVIDER, self.num)
def __lt__(self, other):
if not isinstance(other, type(self)):
raise TypeError()
if self.num is None or other.num is None:
return str(self) < str(other)
else:
return (self.body, self.num) < (other.body, other.num)
class Version:
"""
A version container that stores semver like version string
Example:
* ``"1.2.3"``
* ``"1.0.*"``
* ``"1.2.3-pre4+build.5"``
"""
EXTRA_ID_PATTERN = re.compile(r'|[-+0-9A-Za-z]+(\.[-+0-9A-Za-z]+)*')
WILDCARDS = ('*', 'x', 'X')
WILDCARD = -1
component: List[int]
has_wildcard: bool
pre: Optional[ExtraElement]
build: Optional[ExtraElement]
def __init__(self, version_str: str, *, allow_wildcard: bool = True):
"""
:param version_str: The version string to be parsed
:keyword allow_wildcard: If wildcard (``"*"``, ``"x"``, ``"X"``) is allowed. Default: ``True``
"""
if not isinstance(version_str, str):
raise VersionParsingError('Invalid input version string')
def separate_extra(text, char) -> Tuple[str, Optional[ExtraElement]]:
if char in text:
text, extra_str = text.split(char, 1)
if not self.EXTRA_ID_PATTERN.fullmatch(extra_str):
raise VersionParsingError('Invalid build string: ' + extra_str)
extra = ExtraElement(extra_str)
else:
extra = None
return text, extra
self.component = []
self.has_wildcard = False
version_str, self.build = separate_extra(version_str, '+')
version_str, self.pre = separate_extra(version_str, '-')
if len(version_str) == 0:
raise VersionParsingError('Version string is empty')
for comp in version_str.split('.'):
if comp in self.WILDCARDS:
self.component.append(self.WILDCARD)
self.has_wildcard = True
if not allow_wildcard:
raise VersionParsingError('Wildcard {} is not allowed'.format(comp))
else:
try:
num = int(comp)
except ValueError:
num = None
if num is None:
raise VersionParsingError('Invalid version number component: {}'.format(comp))
if num < 0:
raise VersionParsingError('Unsupported negatived number component: {}'.format(num))
self.component.append(num)
if len(self.component) == 0:
raise VersionParsingError('Empty version string')
def __str__(self):
version_str = '.'.join(map(lambda c: str(c) if c != self.WILDCARD else self.WILDCARDS[0], self.component))
if self.pre is not None:
version_str += '-' + str(self.pre)
if self.build is not None:
version_str += '+' + str(self.build)
return version_str
def __repr__(self):
return self.__str__()
def __getitem__(self, index: int) -> int:
if index < len(self.component):
return self.component[index]
else:
return self.WILDCARD if self.component[len(self.component) - 1] == self.WILDCARD else 0
def __lt__(self, other):
if not isinstance(other, Version):
raise TypeError('Cannot compare between instances of {} and {}'.format(Version.__name__, type(other).__name__))
for i in range(max(len(self.component), len(other.component))):
if self[i] == self.WILDCARD or other[i] == self.WILDCARD:
continue
if self[i] != other[i]:
return self[i] < other[i]
if self.pre is not None and other.pre is not None:
return self.pre < other.pre
elif self.pre is not None:
return not other.has_wildcard
elif other.pre is not None:
return False
else:
return False
def __eq__(self, other):
return not self < other and not other < self
def __le__(self, other):
return self == other or self < other
def compare_to(self, other):
if self < other:
return -1
elif self > other:
return 1
else:
return 0
DEFAULT_CRITERION_OPERATOR = '='
class Criterion:
def __init__(self, opt: str, base_version: Version, criterion: Callable[[Version, Version], bool]):
self.opt = opt
self.base_version = base_version
self.criterion = criterion
def test(self, target: Union[Version, str]):
return self.criterion(self.base_version, target)
def __str__(self):
return '{}{}'.format(self.opt if self.opt != DEFAULT_CRITERION_OPERATOR else '', self.base_version)
class VersionRequirement:
"""
A version requirement tester
It can test if a given :class:`Version` object matches its requirement
"""
CRITERIONS = {
'<=': lambda base, ver: ver <= base,
'>=': lambda base, ver: ver >= base,
'<': lambda base, ver: ver < base,
'>': lambda base, ver: ver > base,
'=': lambda base, ver: ver == base,
'^': lambda base, ver: ver >= base and ver[0] == base[0],
'~': lambda base, ver: ver >= base and ver[0] == base[0] and ver[1] == base[1],
}
def __init__(self, requirements: str):
"""
:param requirements: The requirement string, which contains several version predicates connected by space character.
e.g. ``">=1.0.x"``, ``"^2.9"``, ``">=1.2.0 <1.4.3"``
"""
if not isinstance(requirements, str):
raise VersionParsingError('Requirements should be a str, not {}'.format(type(requirements).__name__))
self.criterions = [] # type: List[Criterion]
for requirement in requirements.split(' '):
if len(requirement) > 0:
for prefix, func in self.CRITERIONS.items():
if requirement.startswith(prefix):
opt = prefix
base_version = requirement[len(prefix):]
break
else:
opt = DEFAULT_CRITERION_OPERATOR
base_version = requirement
self.criterions.append(Criterion(opt, Version(base_version), self.CRITERIONS[opt]))
def accept(self, version: Union[Version, str]):
if isinstance(version, str):
version = Version(version)
for criterion in self.criterions:
if not criterion.test(version):
return False
return True
def __str__(self):
return ' '.join(map(str, self.criterions))
class VersionParsingError(ValueError):
pass

View File

@ -9,7 +9,7 @@ import sys
from typing import TYPE_CHECKING
#: The release version
version = '2.0.9'
version = '2.0.10'
__version__ = version
MIN_PYTHON_VERSION = 3, 8
@ -31,8 +31,10 @@ _enable_optimisations = not __debug__
if getattr(sys, 'frozen', None):
_enable_optimisations = True
#: Global dict of pyglet options. To change an option from its default, you
#: must import ``pyglet`` before any sub-packages. For example::
#: Global dict of pyglet options.
#:
#: To change an option from its default, you must import
#: ``pyglet`` before any sub-packages. For example::
#:
#: import pyglet
#: pyglet.options['debug_gl'] = False
@ -48,14 +50,21 @@ if getattr(sys, 'frozen', None):
#: The non-development options are:
#:
#: audio
#: A sequence of the names of audio modules to attempt to load, in
#: order of preference. Valid driver names are:
#: A :py:class:`~typing.Sequence` of valid audio modules names. They will
#: be tried from first to last until either a driver loads or no entries
#: remain. See :ref:`guide-audio-driver-order` for more information.
#:
#: Valid driver names are:
#:
#: * ``'xaudio2'``, the Windows Xaudio2 audio module (Windows only)
#: * ``'directsound'``, the Windows DirectSound audio module (Windows only)
#: * ``'pulse'``, the :ref:`guide-audio-driver-pulseaudio` module
#: (Linux only, otherwise nearly ubiquitous. Limited features; use
#: ``'openal'`` for more.)
#: * ``'openal'``, the :ref:`guide-audio-driver-openal` audio module
#: (A library may need to be installed on Windows and Linux)
#: * ``'silent'``, no audio
#:
#: * xaudio2, the Windows Xaudio2 audio module (Windows only)
#: * directsound, the Windows DirectSound audio module (Windows only)
#: * pulse, the PulseAudio module (Linux only)
#: * openal, the OpenAL audio module
#: * silent, no audio
#: debug_lib
#: If True, prints the path of each dynamic library loaded.
#: debug_gl

View File

@ -1,4 +1,9 @@
import weakref
from enum import Enum
from typing import Tuple
import pyglet
from pyglet import gl
from pyglet.gl import gl_info
@ -162,7 +167,7 @@ class Config:
class CanvasConfig(Config):
"""OpenGL configuration for a particular canvas.
"""An OpenGL configuration for a particular canvas.
Use `Config.match` to obtain an instance of this class.
@ -212,7 +217,7 @@ class ObjectSpace:
class Context:
"""OpenGL context for drawing.
"""An OpenGL context for drawing.
Use `CanvasConfig.create_context` to create a context.
@ -237,9 +242,17 @@ class Context:
else:
self.object_space = ObjectSpace()
self._cached_programs = weakref.WeakValueDictionary()
def __repr__(self):
return f"{self.__class__.__name__}(id={id(self)}, share={self.context_share})"
def __enter__(self):
self.set_current()
def __exit__(self, exc_type, exc_val, exc_tb):
return
def attach(self, canvas):
if self.canvas is not None:
self.detach()
@ -266,7 +279,7 @@ class Context:
# Release Textures, Buffers, and VAOs on this context scheduled for
# deletion. Note that the garbage collector may introduce a race
# condition, so operate on a copy, and clear the list afterwards.
# condition, so operate on a copy, and clear the list afterward.
if self.object_space.doomed_textures:
textures = self.object_space.doomed_textures[:]
textures = (gl.GLuint * len(textures))(*textures)
@ -305,6 +318,34 @@ class Context:
if gl._shadow_window is not None:
gl._shadow_window.switch_to()
def create_program(self, *sources: Tuple[str, str], program_class=None):
"""Create a ShaderProgram from OpenGL GLSL source.
This is a convenience method that takes one or more tuples of
(source_string, shader_type), and returns a
:py:class:`~pyglet.graphics.shader.ShaderProgram` instance.
`source_string` is OpenGL GLSL source code as a str, and `shader_type`
is the OpenGL shader type, such as "vertex" or "fragment". See
:py:class:`~pyglet.graphics.shader.Shader` for more information.
.. note:: This method is cached. Given the same shader sources, the
same ShaderProgram instance will be returned. For more
control over the ShaderProgram lifecycle, it is recommended
to manually create Shaders and link ShaderPrograms.
.. versionadded:: 2.0.10
"""
if program := self._cached_programs.get(str(sources)):
return program
program_class = program_class or pyglet.graphics.shader.ShaderProgram
shaders = (pyglet.graphics.shader.Shader(src, srctype) for (src, srctype) in sources)
program = program_class(*shaders)
self._cached_programs[str(sources)] = program
return program
def delete_texture(self, texture_id):
"""Safely delete a Texture belonging to this context.

View File

@ -63,10 +63,12 @@ class GLInfo:
This method is called automatically for the default context.
"""
from pyglet.gl.gl import glGetString, glGetStringi, GL_NUM_EXTENSIONS
self._have_context = True
if not self._have_info:
from pyglet.gl.gl import glGetString, glGetStringi, GL_NUM_EXTENSIONS
self.vendor = asstr(cast(glGetString(GL_VENDOR), c_char_p).value)
self.renderer = asstr(cast(glGetString(GL_RENDERER), c_char_p).value)
self.version = asstr(cast(glGetString(GL_VERSION), c_char_p).value)

View File

@ -188,24 +188,9 @@ def get_default_batch():
return pyglet.gl.current_context.pyglet_graphics_default_batch
def get_default_group():
try:
return pyglet.gl.current_context.pyglet_graphics_default_group
except AttributeError:
pyglet.gl.current_context.pyglet_graphics_default_group = ShaderGroup(get_default_shader())
return pyglet.gl.current_context.pyglet_graphics_default_group
def get_default_shader():
try:
return pyglet.gl.current_context.pyglet_graphics_default_shader
except AttributeError:
_default_vert_shader = pyglet.graphics.shader.Shader(_vertex_source, 'vertex')
_default_frag_shader = pyglet.graphics.shader.Shader(_fragment_source, 'fragment')
default_shader_program = pyglet.graphics.shader.ShaderProgram(_default_vert_shader, _default_frag_shader)
pyglet.gl.current_context.pyglet_graphics_default_shader = default_shader_program
return pyglet.gl.current_context.pyglet_graphics_default_shader
return pyglet.gl.current_context.create_program((_vertex_source, 'vertex'),
(_fragment_source, 'fragment'))
class Batch:
"""Manage a collection of drawables for batched rendering.

View File

@ -729,8 +729,8 @@ class Shader:
result_str = create_string_buffer(log_length.value)
glGetShaderInfoLog(shader_id, log_length, None, result_str)
if result_str.value:
return ("OpenGL returned the following message when compiling the '{0}' shader: "
"\n{1}".format(self.type, result_str.value.decode('utf8')))
return (f"OpenGL returned the following message when compiling the "
f"'{self.type}' shader: \n{result_str.value.decode('utf8')}")
else:
return f"{self.type.capitalize()} Shader '{shader_id}' compiled successfully."
@ -936,8 +936,6 @@ class ShaderProgram:
class ComputeShaderProgram:
"""OpenGL Compute Shader Program"""
__slots__ = '_shader', '_id', '_context', '_uniforms', '_uniform_blocks', '__weakref__', 'limits'
def __init__(self, source: str):
"""Create an OpenGL ComputeShaderProgram from source."""
if not (gl_info.have_version(4, 3) or gl_info.have_extension("GL_ARB_compute_shader")):
@ -954,12 +952,10 @@ class ComputeShaderProgram:
self._uniforms = _introspect_uniforms(self._id, True)
self._uniform_blocks = _introspect_uniform_blocks(self)
self.limits = {
'work_group_count': self._get_tuple(GL_MAX_COMPUTE_WORK_GROUP_COUNT),
'work_group_size': self._get_tuple(GL_MAX_COMPUTE_WORK_GROUP_SIZE),
'work_group_invocations': self._get_value(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS),
'shared_memory_size': self._get_value(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE),
}
self.max_work_group_size = self._get_tuple(GL_MAX_COMPUTE_WORK_GROUP_SIZE)
self.max_work_group_count = self._get_tuple(GL_MAX_COMPUTE_WORK_GROUP_COUNT)
self.max_shared_memory_size = self._get_value(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE)
self.max_work_group_invocations = self._get_value(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS)
@staticmethod
def _get_tuple(parameter: int):

View File

@ -79,7 +79,6 @@ class VertexDomain:
self.program = program
self.attribute_meta = attribute_meta
self.allocator = allocation.Allocator(self._initial_count)
self.vao = vertexarray.VertexArray()
self.attributes = []
self.buffer_attributes = [] # list of (buffer, attributes)
@ -99,6 +98,15 @@ class VertexDomain:
attribute.buffer.attributes = (attribute,)
self.buffer_attributes.append((attribute.buffer, (attribute,)))
self.vao = vertexarray.VertexArray()
self.vao.bind()
for buffer, attributes in self.buffer_attributes:
buffer.bind()
for attribute in attributes:
attribute.enable()
attribute.set_pointer(buffer.ptr)
self.vao.unbind()
# Create named attributes for each attribute
self.attribute_names = {}
for attribute in self.attributes:
@ -163,12 +171,8 @@ class VertexDomain:
"""
self.vao.bind()
for buffer, attributes in self.buffer_attributes:
for buffer, _ in self.buffer_attributes:
buffer.bind()
for attribute in attributes:
attribute.enable()
attribute.set_pointer(attribute.buffer.ptr)
starts, sizes = self.allocator.get_allocated_regions()
primcount = len(starts)
@ -182,9 +186,6 @@ class VertexDomain:
sizes = (GLsizei * primcount)(*sizes)
glMultiDrawArrays(mode, starts, sizes, primcount)
for buffer, _ in self.buffer_attributes:
buffer.unbind()
def draw_subset(self, mode, vertex_list):
"""Draw a specific VertexList in the domain.
@ -199,18 +200,11 @@ class VertexDomain:
"""
self.vao.bind()
for buffer, attributes in self.buffer_attributes:
for buffer, _ in self.buffer_attributes:
buffer.bind()
for attribute in attributes:
attribute.enable()
attribute.set_pointer(attribute.buffer.ptr)
glDrawArrays(mode, vertex_list.start, vertex_list.count)
for buffer, _ in self.buffer_attributes:
buffer.unbind()
@property
def is_empty(self):
return not self.allocator.starts
@ -339,6 +333,10 @@ class IndexedVertexDomain(VertexDomain):
self.index_element_size = ctypes.sizeof(self.index_c_type)
self.index_buffer = BufferObject(self.index_allocator.capacity * self.index_element_size)
self.vao.bind()
self.index_buffer.bind_to_index_buffer()
self.vao.unbind()
def safe_index_alloc(self, count):
"""Allocate indices, resizing the buffers if necessary."""
try:
@ -414,13 +412,8 @@ class IndexedVertexDomain(VertexDomain):
"""
self.vao.bind()
for buffer, attributes in self.buffer_attributes:
for buffer, _ in self.buffer_attributes:
buffer.bind()
for attribute in attributes:
attribute.enable()
attribute.set_pointer(attribute.buffer.ptr)
self.index_buffer.bind_to_index_buffer()
starts, sizes = self.index_allocator.get_allocated_regions()
primcount = len(starts)
@ -436,10 +429,6 @@ class IndexedVertexDomain(VertexDomain):
sizes = (GLsizei * primcount)(*sizes)
glMultiDrawElements(mode, sizes, self.index_gl_type, starts, primcount)
self.index_buffer.unbind()
for buffer, _ in self.buffer_attributes:
buffer.unbind()
def draw_subset(self, mode, vertex_list):
"""Draw a specific IndexedVertexList in the domain.
@ -454,22 +443,13 @@ class IndexedVertexDomain(VertexDomain):
"""
self.vao.bind()
for buffer, attributes in self.buffer_attributes:
for buffer, _ in self.buffer_attributes:
buffer.bind()
for attribute in attributes:
attribute.enable()
attribute.set_pointer(attribute.buffer.ptr)
self.index_buffer.bind_to_index_buffer()
glDrawElements(mode, vertex_list.index_count, self.index_gl_type,
self.index_buffer.ptr +
vertex_list.index_start * self.index_element_size)
self.index_buffer.unbind()
for buffer, _ in self.buffer_attributes:
buffer.unbind()
class IndexedVertexList(VertexList):
"""A list of vertices within an :py:class:`IndexedVertexDomain` that are

View File

@ -2,11 +2,10 @@ from pyglet import compat_platform
# This file is automatically generated by 'pyglet/tools/gen_controller_db.py'
# Generated on: Wed Jan 18 14:06:46 2023
# Generated on: Wed Aug 30 15:53:55 2023
if compat_platform.startswith("linux"):
mapping_list = [
"xinput,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
@ -27,6 +26,8 @@ if compat_platform.startswith("linux"):
"05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000020000000000000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"06000000c82d00000020000006010000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000c82d00000660000000010000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
@ -87,10 +88,9 @@ if compat_platform.startswith("linux"):
"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,",
"03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
"050000004c050000f20d000000010000,DualSense Edge Wireless Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000790000001100000010010000,Elecom Gamepad,crc:e86c,a:b2,b:b3,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b0,y:b1,",
"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
@ -104,6 +104,7 @@ if compat_platform.startswith("linux"):
"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"03000000280400000140000000010000,Gravis Gamepad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
@ -137,6 +138,7 @@ if compat_platform.startswith("linux"):
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
@ -268,7 +270,8 @@ if compat_platform.startswith("linux"):
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000790000001100000010010000,Retrolink SNES Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
@ -299,6 +302,7 @@ if compat_platform.startswith("linux"):
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,",
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b6,leftstick:b13,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:+a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
@ -317,7 +321,6 @@ if compat_platform.startswith("linux"):
"03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,",
"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000790000000600000007010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
"03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,",
"05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
@ -332,17 +335,10 @@ if compat_platform.startswith("linux"):
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"050000005e040000050b000003090000,Xbox One Elite Series 2,a:b0,b:b1,back:b121,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"030000005e040000ea02000000000000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000ea02000001030000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"050000005e040000130b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,",
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,",
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
@ -408,9 +404,6 @@ elif compat_platform.startswith("darwin"):
"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
"030000000d0f00008400000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000000d0f00008500000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle3:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,",
"03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
@ -470,7 +463,8 @@ elif compat_platform.startswith("darwin"):
"03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
@ -508,6 +502,7 @@ elif compat_platform.startswith("darwin"):
"030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000000040000,Xin-Mo Dual Arcade,crc:82d5,a:b2,b:b4,back:b18,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b8,righttrigger:b10,start:b16,x:b0,y:b6,",
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
@ -607,9 +602,7 @@ elif compat_platform.startswith("win"):
"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
"03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000151900004000000000000000,Flydigi Vader 2,a:b11,b:b10,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,leftstick:b1,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b0,righttrigger:b4,rightx:a3,righty:a4,start:b2,x:b9,y:b8,",
"03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,",
"03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"03000000790000000600000000000000,G-Shark GS-GP702,crc:8e4f,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
"03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
@ -649,6 +642,7 @@ elif compat_platform.startswith("win"):
"030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000000d0f0000c100000000000000,Horipad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,",
"030000006f0e00002401000000000000,INJUSTICE FightStick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
@ -767,7 +761,8 @@ elif compat_platform.startswith("win"):
"030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,",
"03000000790000001100000000000000,Retrolink SNES Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
@ -824,6 +819,7 @@ elif compat_platform.startswith("win"):
"03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
"03000000c0160000e105000000000000,Xin-Mo Dual Arcade,crc:2246,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,",
"03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
"03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",

View File

@ -398,8 +398,6 @@ class WMFSource(Source):
def __init__(self, filename, file=None):
assert any([self.decode_audio, self.decode_video]), "Source must decode audio, video, or both, not none."
self._current_audio_sample = None
self._current_audio_buffer = None
self._current_video_sample = None
self._current_video_buffer = None
self._timestamp = 0
@ -615,20 +613,13 @@ class WMFSource(Source):
def get_audio_data(self, num_bytes, compensation_time=0.0):
flags = DWORD()
timestamp = ctypes.c_longlong()
audio_data_length = DWORD()
# If we have an audio sample already in use and we call this again, release the memory of buffer and sample.
# Can only release after the data is played or else glitches and pops can be heard.
if self._current_audio_sample:
self._current_audio_buffer.Release()
self._current_audio_sample.Release()
self._current_audio_sample = IMFSample()
self._current_audio_buffer = IMFMediaBuffer()
imf_sample = IMFSample()
imf_buffer = IMFMediaBuffer()
while True:
self._source_reader.ReadSample(self._audio_stream_index, 0, None, ctypes.byref(flags),
ctypes.byref(timestamp), ctypes.byref(self._current_audio_sample))
ctypes.byref(timestamp), ctypes.byref(imf_sample))
if flags.value & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED:
assert _debug('WMFAudioDecoder: Data is no longer valid.')
@ -638,20 +629,23 @@ class WMFSource(Source):
assert _debug('WMFAudioDecoder: End of data from stream source.')
break
if not self._current_audio_sample:
if not imf_sample:
assert _debug('WMFAudioDecoder: No sample.')
continue
# Convert to single buffer as a sample could potentially(rarely) have multiple buffers.
self._current_audio_sample.ConvertToContiguousBuffer(ctypes.byref(self._current_audio_buffer))
imf_sample.ConvertToContiguousBuffer(ctypes.byref(imf_buffer))
audio_data_ptr = POINTER(BYTE)()
audio_data_length = DWORD()
self._current_audio_buffer.Lock(ctypes.byref(audio_data_ptr), None, ctypes.byref(audio_data_length))
self._current_audio_buffer.Unlock()
imf_buffer.Lock(ctypes.byref(audio_data_ptr), None, ctypes.byref(audio_data_length))
audio_data = create_string_buffer(audio_data_length.value)
memmove(audio_data, audio_data_ptr, audio_data_length.value)
audio_data = ctypes.string_at(audio_data_ptr, audio_data_length.value)
imf_buffer.Unlock()
imf_buffer.Release()
imf_sample.Release()
return AudioData(audio_data,
audio_data_length.value,
@ -688,6 +682,7 @@ class WMFSource(Source):
# changes if the stride is added/changed before playback?
stride = ctypes.c_uint32()
new.GetUINT32(MF_MT_DEFAULT_STRIDE, ctypes.byref(stride))
new.Release()
self._stride = stride.value
@ -773,16 +768,15 @@ class WMFSource(Source):
assert _debug('WMFVideoDecoder: Setting configuration attributes.')
def __del__(self):
if self._source_reader:
self._source_reader.Release()
if self._stream_obj:
self._stream_obj.Release()
if self._imf_bytestream:
self._imf_bytestream.Release()
if self._current_audio_sample:
self._current_audio_buffer.Release()
self._current_audio_sample.Release()
if self._current_video_sample:
self._current_video_buffer.Release()
self._current_video_sample.Release()

View File

@ -109,7 +109,9 @@ class Player(pyglet.event.EventDispatcher):
self._playlists = deque()
self._audio_player = None
self._context = pyglet.gl.current_context
self._texture = None
# Desired play state (not an indication of actual state).
self._playing = False
@ -455,9 +457,12 @@ class Player(pyglet.event.EventDispatcher):
image = source.get_next_video_frame()
if image is not None:
if self._texture is None:
self._create_texture()
self._texture.blit_into(image, 0, 0, 0)
with self._context:
if self._texture is None:
self._create_texture()
self._texture.blit_into(image, 0, 0, 0)
elif bl.logger is not None:
bl.logger.log("p.P.ut.1.8")

View File

@ -87,25 +87,12 @@ def load(filename, file=None, decoder=None, batch=None, group=None):
def get_default_shader():
try:
return pyglet.gl.current_context.model_default_plain_shader
except AttributeError:
vert_shader = shader.Shader(MaterialGroup.default_vert_src, 'vertex')
frag_shader = shader.Shader(MaterialGroup.default_frag_src, 'fragment')
default_shader_program = shader.ShaderProgram(vert_shader, frag_shader)
pyglet.gl.current_context.model_default_plain_shader = default_shader_program
return pyglet.gl.current_context.model_default_plain_shader
return pyglet.gl.current_context.create_program((MaterialGroup.default_vert_src, 'vertex'),
(MaterialGroup.default_frag_src, 'fragment'))
def get_default_textured_shader():
try:
return pyglet.gl.current_context.model_default_textured_shader
except AttributeError:
vert_shader = shader.Shader(TexturedMaterialGroup.default_vert_src, 'vertex')
frag_shader = shader.Shader(TexturedMaterialGroup.default_frag_src, 'fragment')
default_shader_program = shader.ShaderProgram(vert_shader, frag_shader)
pyglet.gl.current_context.model_default_textured_shader = default_shader_program
return current_context.model_default_textured_shader
return pyglet.gl.current_context.create_program((TexturedMaterialGroup.default_vert_src, 'vertex'),
(TexturedMaterialGroup.default_frag_src, 'fragment'))
class Model:

View File

@ -102,21 +102,15 @@ fragment_source = """#version 150 core
def get_default_shader():
try:
return pyglet.gl.current_context.pyglet_shapes_default_shader
except AttributeError:
_default_vert_shader = pyglet.graphics.shader.Shader(vertex_source, 'vertex')
_default_frag_shader = pyglet.graphics.shader.Shader(fragment_source, 'fragment')
default_shader_program = pyglet.graphics.shader.ShaderProgram(_default_vert_shader, _default_frag_shader)
pyglet.gl.current_context.pyglet_shapes_default_shader = default_shader_program
return default_shader_program
return pyglet.gl.current_context.create_program((vertex_source, 'vertex'),
(fragment_source, 'fragment'))
def _rotate_point(center, point, angle):
prev_angle = math.atan2(point[1] - center[1], point[0] - center[0])
now_angle = prev_angle + angle
r = math.dist(point, center)
return (center[0] + r * math.cos(now_angle), center[1] + r * math.sin(now_angle))
return center[0] + r * math.cos(now_angle), center[1] + r * math.sin(now_angle)
def _sat(vertices, point):
@ -198,6 +192,7 @@ class ShapeBase(ABC):
"""
_rgba = (255, 255, 255, 255)
_rotation = 0
_visible = True
_x = 0
_y = 0
@ -258,6 +253,29 @@ class ShapeBase(ABC):
"""
raise NotImplementedError("_update_vertices must be defined"
"for every ShapeBase subclass")
@property
def rotation(self) -> float:
"""Clockwise rotation of the shape in degrees.
It will be rotated about its (anchor_x, anchor_y) position,
which defaults to the first vertex point of the shape.
For most shapes, this is the lower left corner. The shapes
below default to the points their ``radius`` values are
measured from:
* :py:class:`.Circle`
* :py:class:`.Ellipse`
* :py:class:`.Arc`
* :py:class:`.Sector`
* :py:class:`.Star`
"""
return self._rotation
@rotation.setter
def rotation(self, rotation: float) -> None:
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
def draw(self):
"""Draw the shape at its current position.
@ -551,22 +569,6 @@ class Arc(ShapeBase):
self._vertex_list.position[:] = vertices
@property
def rotation(self):
"""Clockwise rotation of the arc, in degrees.
The arc will be rotated about its (anchor_x, anchor_y)
position.
:type: float
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
@property
def angle(self):
"""The angle of the arc.
@ -629,6 +631,7 @@ class BezierCurve(ShapeBase):
Optional parent group of the curve.
"""
self._points = list(points)
self._x, self._y = self._points[0]
self._t = t
self._segments = segments
self._num_verts = self._segments * 2
@ -655,7 +658,7 @@ class BezierCurve(ShapeBase):
self._vertex_list = self._group.program.vertex_list(
self._num_verts, self._draw_mode, self._batch, self._group,
colors=('Bn', self._rgba * self._num_verts),
translation=('f', (self._points[0]) * self._num_verts))
translation=('f', (self._x, self._y) * self._num_verts))
def _update_vertices(self):
if not self._visible:
@ -902,22 +905,6 @@ class Ellipse(ShapeBase):
self._b = value
self._update_vertices()
@property
def rotation(self):
"""Clockwise rotation of the arc, in degrees.
The arc will be rotated about its (anchor_x, anchor_y)
position.
:type: float
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
class Sector(ShapeBase):
def __init__(self, x, y, radius, segments=None, angle=math.tau, start_angle=0,
@ -1048,22 +1035,6 @@ class Sector(ShapeBase):
self._radius = value
self._update_vertices()
@property
def rotation(self):
"""Clockwise rotation of the sector, in degrees.
The sector will be rotated about its (anchor_x, anchor_y)
position.
:type: float
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
class Line(ShapeBase):
def __init__(self, x, y, x2, y2, width=1, color=(255, 255, 255, 255),
@ -1286,22 +1257,6 @@ class Rectangle(ShapeBase):
self._height = value
self._update_vertices()
@property
def rotation(self):
"""Clockwise rotation of the rectangle, in degrees.
The Rectangle will be rotated about its (anchor_x, anchor_y)
position.
:type: float
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
class BorderedRectangle(ShapeBase):
def __init__(self, x, y, width, height, border=1, color=(255, 255, 255),
@ -1449,22 +1404,6 @@ class BorderedRectangle(ShapeBase):
self._height = value
self._update_vertices()
@property
def rotation(self):
"""Clockwise rotation of the rectangle, in degrees.
The Rectangle will be rotated about its (anchor_x, anchor_y)
position.
:type: float
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
@property
def border_color(self):
"""The rectangle's border color.
@ -1771,17 +1710,6 @@ class Star(ShapeBase):
self._num_spikes = value
self._update_vertices()
@property
def rotation(self):
"""Rotation of the star, in degrees.
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
class Polygon(ShapeBase):
def __init__(self, *coordinates, color=(255, 255, 255, 255), batch=None, group=None):
@ -1805,6 +1733,7 @@ class Polygon(ShapeBase):
# len(self._coordinates) = the number of vertices and sides in the shape.
self._rotation = 0
self._coordinates = list(coordinates)
self._x, self._y = self._coordinates[0]
self._num_verts = (len(self._coordinates) - 2) * 3
r, g, b, *a = color
@ -1826,7 +1755,7 @@ class Polygon(ShapeBase):
self._vertex_list = self._group.program.vertex_list(
self._num_verts, self._draw_mode, self._batch, self._group,
colors=('Bn', self._rgba * self._num_verts),
translation=('f', (self._coordinates[0]) * self._num_verts))
translation=('f', (self._x, self._y) * self._num_verts))
def _update_vertices(self):
if not self._visible:
@ -1846,21 +1775,5 @@ class Polygon(ShapeBase):
# Flattening the list before setting vertices to it.
self._vertex_list.position[:] = tuple(value for coordinate in triangles for value in coordinate)
@property
def rotation(self):
"""Clockwise rotation of the polygon, in degrees.
The Polygon will be rotated about its (anchor_x, anchor_y)
position.
:type: float
"""
return self._rotation
@rotation.setter
def rotation(self, rotation):
self._rotation = rotation
self._vertex_list.rotation[:] = (rotation,) * self._num_verts
__all__ = 'Arc', 'BezierCurve', 'Circle', 'Ellipse', 'Line', 'Rectangle', 'BorderedRectangle', 'Triangle', 'Star', 'Polygon', 'Sector'

View File

@ -146,25 +146,12 @@ fragment_array_source = """#version 150 core
def get_default_shader():
try:
return pyglet.gl.current_context.pyglet_sprite_default_shader
except AttributeError:
_default_vert_shader = graphics.shader.Shader(vertex_source, 'vertex')
_default_frag_shader = graphics.shader.Shader(fragment_source, 'fragment')
default_shader_program = graphics.shader.ShaderProgram(_default_vert_shader, _default_frag_shader)
pyglet.gl.current_context.pyglet_sprite_default_shader = default_shader_program
return pyglet.gl.current_context.pyglet_sprite_default_shader
return pyglet.gl.current_context.create_program((vertex_source, 'vertex'),
(fragment_source, 'fragment'))
def get_default_array_shader():
try:
return pyglet.gl.current_context.pyglet_sprite_default_array_shader
except AttributeError:
_default_vert_shader = graphics.shader.Shader(vertex_source, 'vertex')
_default_array_frag_shader = graphics.shader.Shader(fragment_array_source, 'fragment')
default_shader_program = graphics.shader.ShaderProgram(_default_vert_shader, _default_array_frag_shader)
pyglet.gl.current_context.pyglet_sprite_default_array_shader = default_shader_program
return pyglet.gl.current_context.pyglet_sprite_default_array_shader
return pyglet.gl.current_context.create_program((vertex_source, 'vertex'),
(fragment_array_source, 'fragment'))
class SpriteGroup(graphics.Group):

View File

@ -127,11 +127,175 @@ from pyglet import graphics
from pyglet.gl import *
from pyglet.event import EventDispatcher
from pyglet.text import runlist
from pyglet.graphics import shader
from pyglet.font.base import grapheme_break
_is_pyglet_doc_run = hasattr(sys, "is_pyglet_doc_run") and sys.is_pyglet_doc_run
layout_vertex_source = """#version 330 core
in vec3 position;
in vec4 colors;
in vec3 tex_coords;
in vec3 translation;
in vec2 anchor;
in float rotation;
out vec4 text_colors;
out vec2 texture_coords;
out vec4 vert_position;
uniform WindowBlock
{
mat4 projection;
mat4 view;
} window;
mat4 m_rotation = mat4(1.0);
mat4 m_anchor = mat4(1.0);
mat4 m_neganchor = mat4(1.0);
void main()
{
m_anchor[3][0] = anchor.x;
m_anchor[3][1] = anchor.y;
m_neganchor[3][0] = -anchor.x;
m_neganchor[3][1] = -anchor.y;
m_rotation[0][0] = cos(-radians(rotation));
m_rotation[0][1] = sin(-radians(rotation));
m_rotation[1][0] = -sin(-radians(rotation));
m_rotation[1][1] = cos(-radians(rotation));
gl_Position = window.projection * window.view * m_anchor * m_rotation * m_neganchor * vec4(position + translation, 1.0);
vert_position = vec4(position + translation, 1.0);
text_colors = colors;
texture_coords = tex_coords.xy;
}
"""
layout_fragment_source = """#version 330 core
in vec4 text_colors;
in vec2 texture_coords;
in vec4 vert_position;
out vec4 final_colors;
uniform sampler2D text;
uniform bool scissor;
uniform vec4 scissor_area;
void main()
{
final_colors = vec4(text_colors.rgb, texture(text, texture_coords).a * text_colors.a);
if (scissor == true) {
if (vert_position.x < scissor_area[0]) discard; // left
if (vert_position.y < scissor_area[1]) discard; // bottom
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
}
}
"""
layout_fragment_image_source = """#version 330 core
in vec4 text_colors;
in vec2 texture_coords;
in vec4 vert_position;
uniform sampler2D image_texture;
out vec4 final_colors;
uniform sampler2D text;
uniform bool scissor;
uniform vec4 scissor_area;
void main()
{
final_colors = texture(image_texture, texture_coords.xy);
if (scissor == true) {
if (vert_position.x < scissor_area[0]) discard; // left
if (vert_position.y < scissor_area[1]) discard; // bottom
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
}
}
"""
decoration_vertex_source = """#version 330 core
in vec3 position;
in vec4 colors;
in vec3 translation;
in vec2 anchor;
in float rotation;
out vec4 vert_colors;
out vec4 vert_position;
uniform WindowBlock
{
mat4 projection;
mat4 view;
} window;
mat4 m_rotation = mat4(1.0);
mat4 m_anchor = mat4(1.0);
mat4 m_neganchor = mat4(1.0);
void main()
{
m_anchor[3][0] = anchor.x;
m_anchor[3][1] = anchor.y;
m_neganchor[3][0] = -anchor.x;
m_neganchor[3][1] = -anchor.y;
m_rotation[0][0] = cos(-radians(rotation));
m_rotation[0][1] = sin(-radians(rotation));
m_rotation[1][0] = -sin(-radians(rotation));
m_rotation[1][1] = cos(-radians(rotation));
gl_Position = window.projection * window.view * m_anchor * m_rotation * m_neganchor * vec4(position + translation, 1.0);
vert_position = vec4(position + translation, 1.0);
vert_colors = colors;
}
"""
decoration_fragment_source = """#version 330 core
in vec4 vert_colors;
in vec4 vert_position;
out vec4 final_colors;
uniform bool scissor;
uniform vec4 scissor_area;
void main()
{
final_colors = vert_colors;
if (scissor == true) {
if (vert_position.x < scissor_area[0]) discard; // left
if (vert_position.y < scissor_area[1]) discard; // bottom
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
}
}
"""
def get_default_layout_shader():
return pyglet.gl.current_context.create_program((layout_vertex_source, 'vertex'),
(layout_fragment_source, 'fragment'))
def get_default_image_layout_shader():
return pyglet.gl.current_context.create_program((layout_vertex_source, 'vertex'),
(layout_fragment_image_source, 'fragment'))
def get_default_decoration_shader():
return pyglet.gl.current_context.create_program((decoration_vertex_source, 'vertex'),
(decoration_fragment_source, 'fragment'))
_distance_re = re.compile(r'([-0-9.]+)([a-zA-Z]+)')
@ -503,186 +667,7 @@ class _InvalidRange:
return self.end > self.start
layout_vertex_source = """#version 330 core
in vec3 position;
in vec4 colors;
in vec3 tex_coords;
in vec3 translation;
in vec2 anchor;
in float rotation;
out vec4 text_colors;
out vec2 texture_coords;
out vec4 vert_position;
uniform WindowBlock
{
mat4 projection;
mat4 view;
} window;
mat4 m_rotation = mat4(1.0);
mat4 m_anchor = mat4(1.0);
mat4 m_neganchor = mat4(1.0);
void main()
{
m_anchor[3][0] = anchor.x;
m_anchor[3][1] = anchor.y;
m_neganchor[3][0] = -anchor.x;
m_neganchor[3][1] = -anchor.y;
m_rotation[0][0] = cos(-radians(rotation));
m_rotation[0][1] = sin(-radians(rotation));
m_rotation[1][0] = -sin(-radians(rotation));
m_rotation[1][1] = cos(-radians(rotation));
gl_Position = window.projection * window.view * m_anchor * m_rotation * m_neganchor * vec4(position + translation, 1.0);
vert_position = vec4(position + translation, 1.0);
text_colors = colors;
texture_coords = tex_coords.xy;
}
"""
layout_fragment_source = """#version 330 core
in vec4 text_colors;
in vec2 texture_coords;
in vec4 vert_position;
out vec4 final_colors;
uniform sampler2D text;
uniform bool scissor;
uniform vec4 scissor_area;
void main()
{
final_colors = vec4(text_colors.rgb, texture(text, texture_coords).a * text_colors.a);
if (scissor == true) {
if (vert_position.x < scissor_area[0]) discard; // left
if (vert_position.y < scissor_area[1]) discard; // bottom
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
}
}
"""
layout_fragment_image_source = """#version 330 core
in vec4 text_colors;
in vec2 texture_coords;
in vec4 vert_position;
uniform sampler2D image_texture;
out vec4 final_colors;
uniform sampler2D text;
uniform bool scissor;
uniform vec4 scissor_area;
void main()
{
final_colors = texture(image_texture, texture_coords.xy);
if (scissor == true) {
if (vert_position.x < scissor_area[0]) discard; // left
if (vert_position.y < scissor_area[1]) discard; // bottom
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
}
}
"""
decoration_vertex_source = """#version 330 core
in vec3 position;
in vec4 colors;
in vec3 translation;
in vec2 anchor;
in float rotation;
out vec4 vert_colors;
out vec4 vert_position;
uniform WindowBlock
{
mat4 projection;
mat4 view;
} window;
mat4 m_rotation = mat4(1.0);
mat4 m_anchor = mat4(1.0);
mat4 m_neganchor = mat4(1.0);
void main()
{
m_anchor[3][0] = anchor.x;
m_anchor[3][1] = anchor.y;
m_neganchor[3][0] = -anchor.x;
m_neganchor[3][1] = -anchor.y;
m_rotation[0][0] = cos(-radians(rotation));
m_rotation[0][1] = sin(-radians(rotation));
m_rotation[1][0] = -sin(-radians(rotation));
m_rotation[1][1] = cos(-radians(rotation));
gl_Position = window.projection * window.view * m_anchor * m_rotation * m_neganchor * vec4(position + translation, 1.0);
vert_position = vec4(position + translation, 1.0);
vert_colors = colors;
}
"""
decoration_fragment_source = """#version 330 core
in vec4 vert_colors;
in vec4 vert_position;
out vec4 final_colors;
uniform bool scissor;
uniform vec4 scissor_area;
void main()
{
final_colors = vert_colors;
if (scissor == true) {
if (vert_position.x < scissor_area[0]) discard; // left
if (vert_position.y < scissor_area[1]) discard; // bottom
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
}
}
"""
def get_default_layout_shader():
try:
return pyglet.gl.current_context.pyglet_text_layout_shader
except AttributeError:
pyglet.gl.current_context.pyglet_text_layout_shader = shader.ShaderProgram(
shader.Shader(layout_vertex_source, 'vertex'),
shader.Shader(layout_fragment_source, 'fragment'),
)
return pyglet.gl.current_context.pyglet_text_layout_shader
def get_default_image_layout_shader():
try:
return pyglet.gl.current_context.pyglet_text_layout_image_shader
except AttributeError:
pyglet.gl.current_context.pyglet_text_layout_image_shader = shader.ShaderProgram(
shader.Shader(layout_vertex_source, 'vertex'),
shader.Shader(layout_fragment_image_source, 'fragment'),
)
return pyglet.gl.current_context.pyglet_text_layout_image_shader
def get_default_decoration_shader():
try:
return pyglet.gl.current_context.pyglet_text_decoration_shader
except AttributeError:
pyglet.gl.current_context.pyglet_text_decoration_shader = shader.ShaderProgram(
shader.Shader(decoration_vertex_source, 'vertex'),
shader.Shader(decoration_fragment_source, 'fragment'),
)
return pyglet.gl.current_context.pyglet_text_decoration_shader
# ####################
class TextLayoutGroup(graphics.Group):

View File

@ -213,7 +213,16 @@ MODESWITCH = 0xff7e
SCRIPTSWITCH = 0xff7e
FUNCTION = 0xffd2
# Text motion constants: these are allowed to clash with key constants
# Text motion constants
# These are allowed to clash with key constants since they are
# abstractions of keyboard shortcuts. See the following for more
# information:
#
# 1. doc/programming_guide/keyboard.rst
# 2. doc/modules/window_key.rst
#
# To add new motions, consult the Adding New Motions section of
# doc/programming_guide/keyboard.rst
MOTION_UP = UP
MOTION_RIGHT = RIGHT
MOTION_DOWN = DOWN

View File

@ -1,9 +1,12 @@
import locale
import unicodedata
import urllib.parse
from ctypes import *
from functools import lru_cache
import pyglet
from pyglet.window import WindowException, MouseCursorException
from pyglet.window import MouseCursor, DefaultMouseCursor, ImageMouseCursor
from pyglet.window import BaseWindow, _PlatformEventHandler, _ViewEventHandler
@ -47,8 +50,7 @@ XA_ATOM = 4
XDND_VERSION = 5
# Do we have the November 2000 UTF8 extension?
_have_utf8 = hasattr(xlib._lib, 'Xutf8TextListToTextProperty')
_have_utf8 = locale.getlocale()[1] == 'UTF-8'
# symbol,ctrl -> motion mapping
_motion_map = {

View File

@ -0,0 +1,7 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------

View File

@ -0,0 +1,9 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from lib_not_dr.types.options import Options

View File

@ -0,0 +1,33 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
import time
from types import FrameType
from typing import List, Optional
from lib_not_dr.types.options import Options
class LogMessage(Options):
name = 'LogMessage'
# 消息内容本身的属性
messages: List[str] = []
end: str = '\n'
split: str = ' '
# 消息的属性
flush: bool = True
level: int = 20
log_time: float = time.time_ns()
logger_name: str = 'root'
logger_tag: Optional[str] = None
stack_trace: Optional[FrameType] = None
# [App -> Logger] -> Queue(raw log) -> [Handler -> Formatter -> (File, Socket) Output] ?
# |-> Handler -> Formatter -> Console Output

View File

@ -9,12 +9,46 @@ import platform
import warnings
import traceback
from pathlib import Path
from typing import List, Tuple, Optional, Any
from typing import List, Tuple, Optional, Union, Any
from Difficult_Rocket.api.types import Options, Version, VersionRequirement
def _add_cmd(cmd: List[str], string: Optional[Any]) -> List[str]:
def ensure_cmd_readable(cmd: str) -> str:
"""
保证 参数中 不含空格
:param cmd: 要格式化的命令行参数
:return: 格式化后的命令行参数
"""
if ' ' in str(cmd):
return f'"{cmd}"'
return cmd
def format_cmd(arg_name: Optional[str] = None,
arg_value: Optional[Union[str, List[str]]] = None,
write: Optional[Any] = True) -> List[str]:
"""
用来格式化输出命令行参数
:param arg_name: 类似 --show-memory 之类的主项
:param arg_value: 类似 xxx 类的内容
:param write: 是否写入
:return: 直接拼接好的命令行参数 不带 =
"""
if not write:
return []
if arg_name is None:
return []
if arg_value is None:
return [arg_name]
if isinstance(arg_value, list):
arg_value = ','.join([ensure_cmd_readable(value) for value in arg_value])
return [f'{arg_name}{arg_value}']
arg_value = ensure_cmd_readable(arg_value)
return [f'{arg_name}{arg_value}']
def _add_cmd(cmd: List[str], string: Optional[str]) -> List[str]:
if string is not None and string:
cmd.append(string)
return cmd
@ -32,13 +66,16 @@ class CompilerHelper(Options):
src_file: Path = Path('DR.py')
python_cmd: str = 'python'
compat_nuitka_version: VersionRequirement = VersionRequirement("~1.7.1") # STATIC VERSION
compat_nuitka_version: VersionRequirement = VersionRequirement("~1.8.1") # STATIC VERSION
# 以下为 nuitka 的参数
use_lto: bool = False # --lto=yes (no is faster)
use_clang: bool = True # --clang
use_msvc: bool = True # --msvc=latest
use_mingw: bool = False # --mingw64
onefile: bool = False # --onefile
onefile_tempdir: Optional[str] = '' # --onefile-tempdir-spec=
standalone: bool = True # --standalone
use_ccache: bool = True # not --disable-ccache
enable_console: bool = True # --enable-console / --disable-console
@ -48,6 +85,8 @@ class CompilerHelper(Options):
remove_output: bool = True # --remove-output
save_xml: bool = False # --xml
xml_path: Path = Path('build/compile_data.xml')
save_report: bool = False # --report
report_path: Path = Path('build/compile_report.xml')
download_confirm: bool = True # --assume-yes-for-download
run_after_build: bool = False # --run
@ -71,7 +110,7 @@ class CompilerHelper(Options):
include_packages: List[str] = ['Difficult_Rocket.api']
enable_plugin: List[str] = [] # --enable-plugin=xxx,xxx
disable_plugin: List[str] = [] # --disable-plugin=xxx,xxx
disable_plugin: List[str] = ['pyqt5', 'tk-inter'] # --disable-plugin=xxx,xxx
def init(self, **kwargs) -> None:
if (compat_version := kwargs.get('compat_nuitka_version')) is not None:
@ -132,40 +171,43 @@ class CompilerHelper(Options):
cmd_list = [self.python_cmd, '-m', 'nuitka']
# macos 和 非 macos icon 参数不同
if platform.system() == 'Darwin':
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)
cmd_list += format_cmd('--macos-app-version=', self.product_version, self.product_version) # noqa
cmd_list += format_cmd('--macos-app-icon=', self.icon_path.absolute(), self.icon_path) # noqa
elif platform.system() == 'Windows':
_add_cmd(cmd_list, f'--windows-icon-from-ico={self.icon_path.absolute()}' if self.icon_path else None)
cmd_list += format_cmd('--windows-icon-from-ico=', self.icon_path.absolute(), self.icon_path) # noqa
elif platform.system() == 'Linux':
_add_cmd(cmd_list, f'--linux-icon={self.icon_path.absolute()}' if self.icon_path else None)
cmd_list += format_cmd('--linux-icon=', self.icon_path.absolute(), self.icon_path) # noqa
_add_cmd(cmd_list, '--lto=yes' if self.use_lto else '--lto=no')
_add_cmd(cmd_list, '--clang' if self.use_clang else None)
_add_cmd(cmd_list, '--msvc=latest' if self.use_msvc else None)
_add_cmd(cmd_list, '--mingw64' if self.use_mingw else None)
_add_cmd(cmd_list, '--standalone' if self.standalone else None)
cmd_list += format_cmd('--lto=', 'yes' if self.use_lto else 'no')
cmd_list += format_cmd('--clang' if self.use_clang else None)
cmd_list += format_cmd('--msvc=latest' if self.use_msvc else None)
cmd_list += format_cmd('--mingw64' if self.use_mingw else None)
cmd_list += format_cmd('--standalone' if self.standalone else None)
cmd_list += format_cmd('--onefile' if self.onefile else None)
cmd_list += format_cmd('--onefile-tempdir-spec=', self.onefile_tempdir, self.onefile_tempdir)
_add_cmd(cmd_list, '--disable-ccache' if not self.use_ccache else None)
_add_cmd(cmd_list, '--show-progress' if self.show_progress else None)
_add_cmd(cmd_list, '--show-memory' if self.show_memory else None)
_add_cmd(cmd_list, '--remove-output' if self.remove_output else None)
_add_cmd(cmd_list, '--assume-yes-for-download' if self.download_confirm else None)
_add_cmd(cmd_list, '--run' if self.run_after_build else None)
_add_cmd(cmd_list, '--enable-console' if self.enable_console else '--disable-console')
cmd_list += format_cmd('--disable-ccache' if not self.use_ccache else None)
cmd_list += format_cmd('--show-progress' if self.show_progress else None)
cmd_list += format_cmd('--show-memory' if self.show_memory else None)
cmd_list += format_cmd('--remove-output' if self.remove_output else None)
cmd_list += format_cmd('--assume-yes-for-download' if self.download_confirm else None)
cmd_list += format_cmd('--run' if self.run_after_build else None)
cmd_list += format_cmd('--enable-console' if self.enable_console else '--disable-console')
_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 += format_cmd('--xml=', str(self.xml_path.absolute()), self.save_xml)
cmd_list += format_cmd('--report=', str(self.report_path.absolute()), self.save_report)
cmd_list += format_cmd('--output-dir=', str(self.output_path.absolute()), self.output_path)
cmd_list += format_cmd('--company-name=', self.company_name, self.company_name)
cmd_list += format_cmd('--product-name=', self.product_name, self.product_name)
cmd_list += format_cmd('--file-version=', str(self.file_version), self.file_version)
cmd_list += format_cmd('--product-version=', str(self.product_version), self.product_version)
cmd_list += format_cmd('--file-description=', self.file_description, self.file_description)
cmd_list += format_cmd('--copyright=', self.copy_right, self.copy_right)
_add_cmd(cmd_list, f'--follow-import-to={",".join(self.follow_import)}' if self.follow_import else None)
_add_cmd(cmd_list, f'--nofollow-import-to={",".join(self.no_follow_import)}' if self.no_follow_import else None)
_add_cmd(cmd_list, f'--enable-plugin={",".join(self.enable_plugin)}' if self.enable_plugin else None)
_add_cmd(cmd_list, f'--disable-plugin={",".join(self.disable_plugin)}' if self.disable_plugin else None)
cmd_list += format_cmd('--follow-import-to=', self.follow_import, self.follow_import)
cmd_list += format_cmd('--nofollow-import-to=', self.no_follow_import, self.no_follow_import)
cmd_list += format_cmd('--enable-plugin=', self.enable_plugin, self.enable_plugin)
cmd_list += format_cmd('--disable-plugin=', self.disable_plugin, self.disable_plugin)
if self.include_data_dir:
cmd_list += [f"--include-data-dir={src}={dst}" for src, dst in self.include_data_dir]

View File

@ -4,7 +4,7 @@
# All rights reserved
# -------------------------------
from .lib import *
from .lib import * # noqa: F403
from typing import TYPE_CHECKING, Dict, Tuple, Optional, List

View File

@ -139,10 +139,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "indoc"
version = "1.0.9"
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "indoc"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]]
name = "libc"
@ -348,9 +354,9 @@ dependencies = [
[[package]]
name = "pyo3"
version = "0.19.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38"
checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b"
dependencies = [
"cfg-if",
"indoc",
@ -365,9 +371,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
version = "0.19.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5"
checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5"
dependencies = [
"once_cell",
"target-lexicon",
@ -375,9 +381,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
version = "0.19.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9"
checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b"
dependencies = [
"libc",
"pyo3-build-config",
@ -385,25 +391,26 @@ dependencies = [
[[package]]
name = "pyo3-macros"
version = "0.19.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1"
checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 1.0.109",
"syn 2.0.29",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.19.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536"
checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.29",
]
[[package]]
@ -622,9 +629,9 @@ checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]]
name = "unindent"
version = "0.1.11"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c"
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
[[package]]
name = "vec_map"

View File

@ -40,5 +40,5 @@ version = "0.17.2"
features = ["simd-stable"]
[dependencies.pyo3]
version = "0.19.2"
version = "0.20.0"
features = ["extension-module" , "macros"]

View File

@ -8,4 +8,4 @@
from typing import TYPE_CHECKING
if not TYPE_CHECKING:
from .Difficult_Rocket_rs import *
from .Difficult_Rocket_rs import * # noqa: F403

View File

@ -655,7 +655,6 @@ pub mod ship {
}
Err(e) => {
println!("{:?}", e);
// println!("{:?}", e.provide());
}
}
Ok(true)

View File

@ -1244,6 +1244,8 @@ pub mod dr {
pub shape_data: ShapeData,
}
/// 为了保证能使用到 所有类型的 碰撞体
/// 写了这么长一个玩意
pub enum ShapeData {
// rapier2d_f64::geometry::ColliderBuilder
/// 球
@ -1301,6 +1303,7 @@ pub mod dr {
/// 由一系列高度定义的某种东西,大概是地面之类的
Heightfield(Vec<(Real, Real)>),
/// 凸分解的复合形状
/// 就是不知道能不能真用上
Compound(Vec<(Isometry<Real>, SharedShape)>), //凸分解,好像可以略微提升复杂刚体碰撞的性能
}
@ -1314,21 +1317,28 @@ pub mod dr {
}
pub struct EngineData {
/// 推力大小if p_type==engine
pub power: f64,
/// 消耗速率if p_type==engine
pub consumption: f64,
pub size: f64,
/// 大小if p_type==engine
// pub size: f64,
/// 转向范围if p_type==engine
pub turn: f64,
/// 燃料类型if p_type==engine
pub fuel_type: f64,
pub throttle_exponential: f64,
// pub throttle_exponential: f64,
}
pub trait DRPartTypeAttrTrait {
fn name() -> String;
// fn get_all_attr() -> HashMap<String, >;
}
/// 用于描述一个零件的属性
pub struct DRPartType<T>
where
T: DRPartTypeAttrTrait,
T: DRPartTypeAttrTrait + Clone,
{
/// 部件 ID
pub id: String,
@ -1344,7 +1354,7 @@ pub mod dr {
pub description: String,
/// 贴图
pub sprite: String,
///pub r#type: SR1PartTypeEnum,
/// pub r#type: SR1PartTypeEnum,
/// 质量单位500kg
pub mass: f64,
/// 宽度,用于判断放置时是否回合其他零件重叠
@ -1371,4 +1381,25 @@ pub mod dr {
// 附加属性
pub attr: HashMap<String, T>,
}
impl<T: DRPartTypeAttrTrait> DRPartType<T>
where
T: DRPartTypeAttrTrait + Clone,
{
#[inline]
pub fn data_ref(&self, name: &str) -> Option<&T> {
if let Some(data) = self.attr.get(name) {
return Some(data);
}
None
}
#[inline]
pub fn data(&self, name: &str) -> Option<T> {
if let Some(data) = self.attr.get(name) {
return Some(data.clone());
}
None
}
}
}

28
mods/dr_game/menu.py Normal file
View File

@ -0,0 +1,28 @@
# -------------------------------
# Difficult Rocket
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from pyglet.graphics import Batch, Group
from Difficult_Rocket.client import ClientWindow
from Difficult_Rocket.api.screen import BaseScreen
# from . import DR_mod_runtime
class Menu(BaseScreen):
"""
DR game 菜单
"""
name = 'DR_game_menu'
def __init__(self,
main_window: ClientWindow):
super().__init__(main_window)
self.main_batch = Batch()
self.main_group = Group(parent=main_window.main_group, order=1)
# 占位, 高二看看能不能咕出来点啥 (20230911)
# 欸呀, 正好是 911 纪念日哦

View File

@ -10,7 +10,7 @@ import logging
import traceback
from pathlib import Path
from typing import List, TYPE_CHECKING, Dict, Optional, Generator, Tuple
from typing import List, Dict, Optional, Generator, Tuple
from pyglet.gl import gl
from pyglet.math import Mat4
@ -52,6 +52,11 @@ class SR1ShipRenderStatus(Options): # NOQA
focus: bool = True
moving: bool = False
# button status
show_moving: bool = False
show_focus: bool = False
show_scale: bool = False
# debug status
draw_d_pos: bool = False
draw_mouse_pos: bool = False
@ -61,6 +66,8 @@ class SR1ShipRenderStatus(Options): # NOQA
class SR1ShipRender(BaseScreen):
"""用于渲染 sr1 船的类"""
name = 'DR_game_sr1_ship_render'
def __init__(self,
main_window: ClientWindow):
super().__init__(main_window)
@ -95,8 +102,7 @@ class SR1ShipRender(BaseScreen):
x=main_window.width / 2, y=main_window.height / 2)
self.render_d_label.visible = self.status.draw_d_pos
self.test_button = PressTextButton(x=100, y=100,
width=150, height=30, text='test button',
self.test_button = PressTextButton(x=100, y=100, width=150, height=30, text='test button',
batch=self.main_batch, group=Group(5, parent=main_window.main_group))
# self.test_button.push_handlers(main_window)
main_window.push_handlers(self.test_button)
@ -277,8 +283,9 @@ class SR1ShipRender(BaseScreen):
def draw_batch(self, window: ClientWindow):
if self.status.draw_done:
self.render_d_label.text = f'x: {self.group_camera.view_x} y: {self.group_camera.view_y}'
self.render_d_label.position = self.group_camera.view_x + (self.window_pointer.width / 2), self.group_camera.view_y + (
self.window_pointer.height / 2) + 10, 0 # 0 for z
self.render_d_label.position = self.group_camera.view_x + (
self.window_pointer.width / 2), self.group_camera.view_y + (
self.window_pointer.height / 2) + 10, 0 # 0 for z
self.render_d_line.x2 = self.group_camera.view_x
self.render_d_line.y2 = self.group_camera.view_y
@ -480,7 +487,6 @@ class SR1ShipRender(BaseScreen):
self.window_pointer.view = value
if __name__ == '__main__':
from objprint import op

View File

@ -26,6 +26,7 @@ if __name__ == '__main__':
compiler.python_cmd = sys.executable
compiler.xml_path = Path(f"./build/compile_data-{time.time()}.xml")
compiler.report_path = Path(f"./build/compile_report-{time.time()}.xml")
# 检测 --github 参数
is_github = False
@ -43,6 +44,10 @@ if __name__ == '__main__':
compiler.save_xml = True
sys.argv.remove('--xml')
if '--report' in sys.argv:
compiler.save_report = True
sys.argv.remove('--report')
# 检测 --output xx 参数
if '--output' in sys.argv:
# 输入的是输出目录

View File

@ -6,7 +6,7 @@ build-backend = "pdm.pep517.api"
[project]
name = "difficult-rocket"
version = "0.8.6.0"
version = "0.8.7.1"
description = "A rocket game"
authors = [
{name = "shenjackyuanjie", email = "3695888@qq.com"}
@ -27,7 +27,7 @@ readme = "README.md"
build = [
"setuptools-rust>=1.5.2,<=1.6.0",
"wheel>=0.38.4,<1.0.0",
"nuitka>=1.4,<1.5.0",
"nuitka>=1.8.1,<1.9.0",
"setuptools>=65.5.0",
"viztracer<1.0.0,>=0.15.4",
"vizplugins<1.0.0,>=0.1.2",

View File

@ -18,7 +18,7 @@ defusedxml >= 0.7.1
objprint >= 0.2.2
# for compile
nuitka >= 1.7.5
nuitka >= 1.8.2
ordered-set >= 4.1.0
imageio >= 2.31.0; (platform_python_implementation == "PyPy" and python_version < "3.10") or platform_python_implementation == "CPython"
wheel >= 0.40.0

View File

@ -21,7 +21,7 @@ viztracer >= 0.15.6; platform_python_implementation != "PyPy"
vizplugins >= 0.1.3; platform_python_implementation != "PyPy"
# for compile
nuitka >= 1.7.5
nuitka >= 1.8.2
ordered-set >= 4.1.0
imageio >= 2.31.0; (platform_python_implementation == "PyPy" and python_version < "3.10") or platform_python_implementation == "CPython"
wheel >= 0.40.0