新的故事还在继续,现在提交方便帮忙同时开发

This commit is contained in:
2026-02-23 23:18:19 +08:00
parent 0e95a1e541
commit 3ee686c712
6 changed files with 153 additions and 112 deletions

View File

@@ -105,6 +105,10 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
license="Same as Musicreater", license="Same as Musicreater",
) )
# 暂时没有适配动画内容和替换顺序
# 金羿正在处理这个,不需要改
# 但是返回值和接口内容不会变,直接用即可
@staticmethod @staticmethod
def generate_progressbar( def generate_progressbar(
max_score: int, max_score: int,
@@ -129,7 +133,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
------- -------
list[MineCommand,] list[MineCommand,]
""" """
pgs_style = progressbar_style.base_style orignal_style_string = progressbar_style.style_base_string
"""用于被替换的进度条原始样式""" """用于被替换的进度条原始样式"""
""" """
@@ -143,19 +147,21 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
| `%%%` | 当前进度比率 | | `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位| | `_` | 用以表示进度条占位|
""" """
per_value_in_each = max_score / pgs_style.count("_") per_value_in_each = max_score / orignal_style_string.count("_")
"""每个进度条代表的分值""" """每个进度条代表的分值"""
result: List[MineCommand] = [] result: List[MineCommand] = []
if r"%^s" in pgs_style: if "%^s" in orignal_style_string:
pgs_style = pgs_style.replace(r"%^s", str(max_score)) orignal_style_string = orignal_style_string.replace("%^s", str(max_score))
if r"%^t" in pgs_style: if "%^t" in orignal_style_string:
pgs_style = pgs_style.replace(r"%^t", mctick2timestr(max_score)) orignal_style_string = orignal_style_string.replace(
"%^t", mctick2timestr(max_score)
)
sbn_pc = scoreboard_name[:2] sbn_pc = scoreboard_name[:2]
if r"%%%" in pgs_style: if "%%%" in orignal_style_string:
result.append( result.append(
MineCommand( MineCommand(
'scoreboard objectives add {}PercT dummy "百分比计算"'.format( 'scoreboard objectives add {}PercT dummy "百分比计算"'.format(
@@ -192,7 +198,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
+ "scoreboard players operation @s {} = @s {}".format( + "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "PercT", scoreboard_name sbn_pc + "PercT", scoreboard_name
), ),
annotation="赋值临时百分比", annotation="赋值当前进度",
) )
) )
result.append( result.append(
@@ -203,7 +209,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
+ "scoreboard players operation @s {} *= n100 {}".format( + "scoreboard players operation @s {} *= n100 {}".format(
sbn_pc + "PercT", scoreboard_name sbn_pc + "PercT", scoreboard_name
), ),
annotation="转换临时百分比之单位至%(扩大精度)", annotation="转换当前进度之单位至百分比(扩大精度)",
) )
) )
result.append( result.append(
@@ -214,11 +220,11 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
+ "scoreboard players operation @s {} /= MaxScore {}".format( + "scoreboard players operation @s {} /= MaxScore {}".format(
sbn_pc + "PercT", scoreboard_name sbn_pc + "PercT", scoreboard_name
), ),
annotation="计算百分比", annotation="计算进度百分比",
) )
) )
if r"%%t" in pgs_style: if "%%t" in orignal_style_string:
result.append( result.append(
MineCommand( MineCommand(
'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format( 'scoreboard objectives add {}TMinT dummy "时间计算:分"'.format(
@@ -241,7 +247,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
"@a[scores={" + scoreboard_name + "=1..}]" "@a[scores={" + scoreboard_name + "=1..}]"
) )
+ "scoreboard players set n20 {} 20".format(scoreboard_name), + "scoreboard players set n20 {} 20".format(scoreboard_name),
annotation="设置常量20", annotation="设置常量 20",
) )
) )
result.append( result.append(
@@ -250,7 +256,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
"@a[scores={" + scoreboard_name + "=1..}]" "@a[scores={" + scoreboard_name + "=1..}]"
) )
+ "scoreboard players set n60 {} 60".format(scoreboard_name), + "scoreboard players set n60 {} 60".format(scoreboard_name),
annotation="设置常量60", annotation="设置常量 60",
) )
) )
@@ -262,7 +268,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
+ "scoreboard players operation @s {} = @s {}".format( + "scoreboard players operation @s {} = @s {}".format(
sbn_pc + "TMinT", scoreboard_name sbn_pc + "TMinT", scoreboard_name
), ),
annotation="赋值临时分", annotation="赋值临时分变量",
) )
) )
result.append( result.append(
@@ -273,7 +279,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
+ "scoreboard players operation @s {} /= n20 {}".format( + "scoreboard players operation @s {} /= n20 {}".format(
sbn_pc + "TMinT", scoreboard_name sbn_pc + "TMinT", scoreboard_name
), ),
annotation="转换临时分之单位为秒(缩减精度)", annotation="转换临时分变量之单位为秒(缩减精度)",
) )
) )
result.append( result.append(
@@ -296,7 +302,7 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
+ "scoreboard players operation @s {} /= n60 {}".format( + "scoreboard players operation @s {} /= n60 {}".format(
sbn_pc + "TMinT", scoreboard_name sbn_pc + "TMinT", scoreboard_name
), ),
annotation="转换临时分之单位为分(缩减精度)", annotation="转换临时分变量之单位为分(缩减精度)",
) )
) )
@@ -312,54 +318,54 @@ class NoteDataConvert2CommandPlugin(LibraryPluginBase):
) )
) )
for i in range(pgs_style.count("_")): for i in range(orignal_style_string.count("_")):
npg_stl = ( npg_stl = (
pgs_style.replace("_", progressbar_style.played_style, i + 1) orignal_style_string.replace("_", progressbar_style.progress_played, i + 1)
.replace("_", progressbar_style.to_play_style) .replace("_", progressbar_style.progress_toplay)
.replace(r"%%N", music_name) .replace("%%N", music_name)
.replace( .replace(
r"%%s", "%%s",
'"},{"score":{"name":"*","objective":"' '"},{"score":{"name":"*","objective":"'
+ scoreboard_name + scoreboard_name
+ '"}},{"text":"', + '"}},{"text":"',
) )
.replace( .replace(
r"%%%", "%%%",
r'"},{"score":{"name":"*","objective":"' '"},{"score":{"name":"*","objective":"'
+ sbn_pc + sbn_pc
+ r'PercT"}},{"text":"%', + 'PercT"}},{"text":"%',
) )
.replace( .replace(
r"%%t", "%%t",
r'"},{"score":{"name":"*","objective":"{-}TMinT"}},{"text":":"},' '"},{"score":{"name":"*","objective":"{-}TMinT"}},{"text":":"},'
r'{"score":{"name":"*","objective":"{-}TSecT"}},{"text":"'.replace( '{"score":{"name":"*","objective":"{-}TSecT"}},{"text":"'.replace(
r"{-}", sbn_pc "{-}", sbn_pc
), ),
) )
) )
result.append( result.append(
MineCommand( MineCommand(
execute_command_head.format( execute_command_head.format(
r"@a[scores={" "@a[scores={"
+ scoreboard_name + scoreboard_name
+ f"={int(i * per_value_in_each)}..{ceil((i + 1) * per_value_in_each)}" + f"={int(i * per_value_in_each)}..{ceil((i + 1) * per_value_in_each)}"
+ r"}]" + "}]"
) )
+ r'titleraw @s actionbar {"rawtext":[{"text":"' + 'titleraw @s actionbar {"rawtext":[{"text":"'
+ npg_stl + npg_stl
+ r'"}]}', + '"}]}',
annotation="进度条显示", annotation="进度条显示",
) )
) )
if r"%%%" in pgs_style: if "%%%" in orignal_style_string:
result.append( result.append(
MineCommand( MineCommand(
"scoreboard objectives remove {}PercT".format(sbn_pc), "scoreboard objectives remove {}PercT".format(sbn_pc),
annotation="移除临时百分比变量", annotation="移除临时百分比变量",
) )
) )
if r"%%t" in pgs_style: if "%%t" in orignal_style_string:
result.append( result.append(
MineCommand( MineCommand(
"scoreboard objectives remove {}TMinT".format(sbn_pc), "scoreboard objectives remove {}TMinT".format(sbn_pc),

View File

@@ -26,23 +26,34 @@ from typing import BinaryIO, Optional, Dict, List, Callable, Tuple, Mapping
class ProgressBarStyle: class ProgressBarStyle:
"""进度条样式类""" """进度条样式类"""
base_style: str style_base_string: str
"""基础样式""" """基础样式"""
to_play_style: str progress_toplay: str
"""未播放之样式""" """未播放之样式"""
played_style: str progress_played: str
"""已播放之样式""" """已播放之样式"""
is_animate_autoloop: bool
"""所示动画是否循环"""
animate_circle: Dict[str, Dict[int, str]]
"""定义动画样式"""
def __init__( def __init__(
self, self,
base_s: Optional[str] = None, base_string: str = "%%N】%A%%%s/%^s (%%t|%^t) \n"
to_play_s: Optional[str] = None, "[§e_________________________§r] %%%",
played_s: Optional[str] = None, to_play_style: str = "§7=",
played_style: str = "=",
animate_loop: bool = True,
animate_circle: Dict[str, Dict[int, str]] = {
"%A%": {5: "-", 10: "\\\\", 15: "|", 20: "/"}
},
): ):
""" """
用于存储进度条样式的类 用于存储进度条样式的类,标识符替换顺序如下表
| 标识符 | 指定的可变量 | | 标识符 | 指定的可变量 |
|---------|----------------| |---------|----------------|
@@ -53,14 +64,15 @@ class ProgressBarStyle:
| `%^t` | 曲目总时长 | | `%^t` | 曲目总时长 |
| `%%%` | 当前进度比率 | | `%%%` | 当前进度比率 |
| `_` | 用以表示进度条占位| | `_` | 用以表示进度条占位|
| `%*%` | 指定*的动画内容 |a
Parameters Parameters
------------ ------------
base_s: str base_string: str
基础样式,用以定义进度条整体 基础样式,用以定义进度条整体
to_play_s: str to_play_style: str
进度条样式:尚未播放的样子 进度条样式:尚未播放的样子
played_s: str played_style: str
已经播放的样子 已经播放的样子
Returns Returns
@@ -68,54 +80,32 @@ class ProgressBarStyle:
ProgressBarStyle 类 ProgressBarStyle 类
""" """
self.base_style = ( self.style_base_string = base_string
base_s if base_s else r"%%N [ %%s/%^s %%% §e__________§r %%t|%^t ]" self.progress_toplay = to_play_style
) self.progress_played = played_style
self.to_play_style = to_play_s if to_play_s else r"§7=" self.is_animate_autoloop = animate_loop
self.played_style = played_s if played_s else r"=" self.animate_circle = animate_circle
@classmethod
def from_tuple(cls, tuplized_style: Optional[Tuple[str, Tuple[str, str]]]):
"""自旧版进度条元组表示法读入数据(已不建议使用)"""
if tuplized_style is None:
return cls(
r"%%N [ %%s/%^s %%% §e__________§r %%t|%^t ]",
r"§7=",
r"=",
)
if isinstance(tuplized_style, tuple):
if isinstance(tuplized_style[0], str) and isinstance(
tuplized_style[1], tuple
):
if isinstance(tuplized_style[1][0], str) and isinstance(
tuplized_style[1][1], str
):
return cls(
tuplized_style[0], tuplized_style[1][0], tuplized_style[1][1]
)
raise ValueError(
"元组表示的进度条样式组 {} 格式错误,已不建议使用此功能,请尽快更换。".format(
tuplized_style
)
)
def set_base_style(self, value: str): def set_base_style(self, value: str):
"""设置基础样式""" """设置基础样式"""
self.base_style = value self.style_base_string = value
def set_to_play_style(self, value: str): def set_to_play_style(self, value: str):
"""设置未播放之样式""" """设置未播放之样式"""
self.to_play_style = value self.progress_toplay = value
def set_played_style(self, value: str): def set_played_style(self, value: str):
"""设置已播放之样式""" """设置已播放之样式"""
self.played_style = value self.progress_played = value
def copy(self): def copy(self):
dst = ProgressBarStyle(self.base_style, self.to_play_style, self.played_style) return ProgressBarStyle(
return dst self.style_base_string,
self.progress_toplay,
self.progress_played,
self.is_animate_autoloop,
self.animate_circle,
)
def play_output( def play_output(
self, self,
@@ -141,24 +131,37 @@ class ProgressBarStyle:
进度条字符串 进度条字符串
""" """
return ( alpha_string = (
self.base_style.replace(r"%%N", music_name) self.style_base_string.replace("%%N", music_name)
.replace(r"%%s", str(played_ticks)) .replace("%%s", str(played_ticks))
.replace(r"%^s", str(total_ticks)) .replace("%^s", str(total_ticks))
.replace(r"%%t", mctick2timestr(played_ticks)) .replace("%%t", mctick2timestr(played_ticks))
.replace(r"%^t", mctick2timestr(total_ticks)) .replace("%^t", mctick2timestr(total_ticks))
.replace( .replace(
r"%%%", "%%%",
"{:0>5.2f}%".format(int(10000 * played_ticks / total_ticks) / 100), "{:0>5.2f}%".format(int(10000 * played_ticks / total_ticks) / 100),
) )
.replace( .replace(
"_", "_",
self.played_style, self.progress_played,
(played_ticks * self.base_style.count("_") // total_ticks) + 1, (played_ticks * self.style_base_string.count("_") // total_ticks) + 1,
) )
.replace("_", self.to_play_style) .replace("_", self.progress_toplay)
) )
for key, animate_dict in self.animate_circle.items():
max_animate_tick = max(animate_dict.keys())
if self.is_animate_autoloop:
animate_time_key = 0
for time_key in animate_dict.keys():
animate_time_key = time_key
if time_key > played_ticks % max_animate_tick:
break
else:
animate_time_key = max_animate_tick
alpha_string = alpha_string.replace(key, animate_dict[animate_time_key])
return alpha_string
def mctick2timestr(mc_tick: int) -> str: def mctick2timestr(mc_tick: int) -> str:
""" """
@@ -167,11 +170,7 @@ def mctick2timestr(mc_tick: int) -> str:
return "{:0>2d}:{:0>2d}".format(mc_tick // 1200, (mc_tick // 20) % 60) return "{:0>2d}:{:0>2d}".format(mc_tick // 1200, (mc_tick // 20) % 60)
DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle( DEFAULT_PROGRESSBAR_STYLE = ProgressBarStyle()
r"%%N [ %%s/%^s %%% §e__________§r %%t|%^t ]",
r"§7=",
r"=",
)
""" """
默认的进度条样式 默认的进度条样式
""" """

View File

@@ -28,7 +28,7 @@ from typing import (
Literal, Literal,
) )
from Musicreater import MineNote from Musicreater import MineNote, SingleNote
from Musicreater.constants import MM_INSTRUMENT_DEVIATION_TABLE from Musicreater.constants import MM_INSTRUMENT_DEVIATION_TABLE
@@ -44,15 +44,15 @@ def minenote_to_command_parameters(
""" """
将 MineNote 对象转为《我的世界》音符播放所需之参数 将 MineNote 对象转为《我的世界》音符播放所需之参数
Parameters 参数
------------ ----
mine_note: MineNote mine_note: MineNote
音符对象 我的世界音符对象
deviation: float deviation: float
音调偏移量 音调偏移量
Returns 返回
--------- ----
tuple[float, float, float], float, float tuple[float, float, float], float, float
播放视角坐标, 指令音量参数, 指令音调参数 播放视角坐标, 指令音量参数, 指令音调参数
""" """
@@ -77,3 +77,39 @@ def minenote_to_command_parameters(
) )
), ),
) )
def calculate_minecraft_pitch(
note: MineNote, pitch_deviation: float = 0
) -> Optional[float]:
"""
计算音符的音调参数
参数
----
note: MineNote
我的世界音符对象
deviation: float
音调偏移量
返回
----
Optional[float]
音调参数, 当为打击乐器时为 None
"""
return (
None
if note.percussive
else (
2
** (
(
note.pitch
- 60
- MM_INSTRUMENT_DEVIATION_TABLE.get(note.instrument, 6)
+ pitch_deviation
)
/ 12
)
)
)

View File

@@ -1,5 +1,5 @@
# 示例插件:导入音符数据 # 教程:编写插件
> 版权所有 © 2026 金羿 > 版权所有 © 2026 金羿
> Copyright © 2026 Eilles > Copyright © 2026 Eilles
@@ -20,8 +20,8 @@ Email [TriM-Organization@hotmail.com](mailto:TriM-Organization@hotmail.com)
``` ```
本教程文档的关联文件是 本教程文档的关联文件是
- 全曲导入音轨导入插件示例[exp_importdata_plugin.py](../examples/exp_importdata_plugin.py) - 全曲导入音轨导入插件示例[exp_importdata_plugin.py](../examples/exp_importdata_plugin.py)
- 导出曲目导出音轨插件示例[exp_dataexport_plugin.py](../examples/exp_dataexport_plugin.py) - 导出曲目导出音轨插件示例[exp_dataexport_plugin.py](../examples/exp_dataexport_plugin.py)
## 新建文件 ## 新建文件
@@ -159,7 +159,7 @@ class ...:
| 支持库 | | | | | | | 支持库 | | | | | |
| 服务 | `serve` | `Callable[[Optional[PluginConfig]], None]` | | | 用于提供后台服务或一次性任务由运行时调用暂无设计思路相关讨论请见[项目待办清单](../TO-DO.md#讨论) | | 服务 | `serve` | `Callable[[Optional[PluginConfig]], None]` | | | 用于提供后台服务或一次性任务由运行时调用暂无设计思路相关讨论请见[项目待办清单](../TO-DO.md#讨论) |
也就是说举个例子一个**用于导入**的插件类必须包含一个 `loadbytes` 方法用于从字节流中导入数据可选是否单独实现 `load` 方法如果不单独实现则在调用时直接通过打开文件后传参数给 `loadbytes` 来实现 也就是说举个例子一个**用于导入**的插件类必须定义一个 `loadbytes` 方法用于从字节流中导入数据可选是否单独实现 `load` 方法如果不单独实现已经继承的方法会在调用时直接通过打开文件后传参数给 `loadbytes` 来实现
```python ```python
@... @...

View File

@@ -501,7 +501,7 @@ class FutureMidiConvertJavaE(MidiConvert):
------- -------
list[MineCommand,] list[MineCommand,]
""" """
pgs_style = progressbar_style.base_style pgs_style = progressbar_style.style_base_string
"""用于被替换的进度条原始样式""" """用于被替换的进度条原始样式"""
""" """
@@ -686,8 +686,8 @@ class FutureMidiConvertJavaE(MidiConvert):
for i in range(pgs_style.count("_")): for i in range(pgs_style.count("_")):
npg_stl = ( npg_stl = (
pgs_style.replace("_", progressbar_style.played_style, i + 1) pgs_style.replace("_", progressbar_style.progress_played, i + 1)
.replace("_", progressbar_style.to_play_style) .replace("_", progressbar_style.progress_toplay)
.replace(r"%%N", self.music_name) .replace(r"%%N", self.music_name)
.replace( .replace(
r"%%s", r"%%s",

View File

@@ -1308,7 +1308,7 @@ class MidiConvert(MusicSequence):
------- -------
list[MineCommand,] list[MineCommand,]
""" """
pgs_style = progressbar_style.base_style pgs_style = progressbar_style.style_base_string
"""用于被替换的进度条原始样式""" """用于被替换的进度条原始样式"""
""" """
@@ -1493,8 +1493,8 @@ class MidiConvert(MusicSequence):
for i in range(pgs_style.count("_")): for i in range(pgs_style.count("_")):
npg_stl = ( npg_stl = (
pgs_style.replace("_", progressbar_style.played_style, i + 1) pgs_style.replace("_", progressbar_style.progress_played, i + 1)
.replace("_", progressbar_style.to_play_style) .replace("_", progressbar_style.progress_toplay)
.replace(r"%%N", self.music_name) .replace(r"%%N", self.music_name)
.replace( .replace(
r"%%s", r"%%s",