mirror of
https://github.com/TriM-Organization/Musicreater.git
synced 2024-11-11 01:27:35 +08:00
更新一点点
This commit is contained in:
parent
3ba8fdad8c
commit
64292a21b3
@ -1,120 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
# W-YI 金羿
|
||||
# QQ 2647547478
|
||||
# 音·创 开发交流群 861684859
|
||||
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
|
||||
# 版权所有 Team-Ryoun 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray")
|
||||
# 若需转载或借鉴 请附作者
|
||||
|
||||
|
||||
"""
|
||||
音·创 (Musicreater)
|
||||
一款免费开源的 《我的世界:基岩版》 音乐制作软件
|
||||
Musicreater (音·创)
|
||||
A free opensource software which is used for creating all kinds of musics in Minecraft
|
||||
|
||||
Copyright 2022 Team-Ryoun
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
# 代码写的并非十分的漂亮,还请大佬多多包涵;本软件源代码依照Apache软件协议公开
|
||||
|
||||
|
||||
# 下面为正文
|
||||
|
||||
# 一定会好起来的
|
||||
|
||||
|
||||
from msctLib.buildIN import version
|
||||
|
||||
__ver__ = f'{version.version[1]} {version.version[0]}'
|
||||
__author__ = '金羿Eilles'
|
||||
|
||||
import msctLib.display as disp
|
||||
|
||||
from msctLib.function import *
|
||||
|
||||
from msctLib.data import uniteIO
|
||||
|
||||
|
||||
hb = r''' __ __
|
||||
/\ \/\ \
|
||||
\ \ \_\ \ __ _____ _____ __ __
|
||||
\ \ _ \ /'__`\ /\ '__`\ /\ '__`\ /\ \/\ \
|
||||
\ \ \ \ \ /\ \L\.\_\ \ \L\ \\ \ \L\ \\ \ \_\ \
|
||||
\ \_\ \_\\ \__/.\_\\ \ ,__/ \ \ ,__/ \/`____ \
|
||||
\/_/\/_/ \/__/\/_/ \ \ \/ \ \ \/ `/___/> \
|
||||
\ \_\ \ \_\ /\___/
|
||||
\/_/ \/_/ \/__/
|
||||
____ __ __ __
|
||||
/\ _`\ __ /\ \__ /\ \ /\ \
|
||||
\ \ \L\ \ /\_\ _ __ \ \ ,_\\ \ \___ \_\ \ __ __ __
|
||||
\ \ _ <'\/\ \ /\`'__\\ \ \/ \ \ _ `\ /'_` \ /'__`\ /\ \/\ \
|
||||
\ \ \L\ \\ \ \\ \ \/ \ \ \_ \ \ \ \ \ /\ \L\ \ /\ \L\.\_\ \ \_\ \
|
||||
\ \____/ \ \_\\ \_\ \ \__\ \ \_\ \_\\ \___,_\\ \__/.\_\\/`____ \
|
||||
\/___/ \/_/ \/_/ \/__/ \/_/\/_/ \/__,_ / \/__/\/_/ `/___/> \
|
||||
/\___/
|
||||
\/__/ '''
|
||||
|
||||
|
||||
def __main__():
|
||||
import datetime, time, random, os, sys, zhdate
|
||||
|
||||
if datetime.date.today().month == 4 and datetime.date.today().day == 3:
|
||||
if sys.platform == 'win32':
|
||||
os.system('color 4e')
|
||||
os.system('cls')
|
||||
for i in range(len(hb)):
|
||||
print(hb[i], end='', flush=True)
|
||||
time.sleep(random.random() * 0.001)
|
||||
input("金羿 生日快乐!")
|
||||
elif '三月初五' in zhdate.ZhDate.today().chinese():
|
||||
input('缅怀先祖 祭祀忠勇 勿忘国耻 振兴中华')
|
||||
|
||||
else:
|
||||
|
||||
def test():
|
||||
print('!!!', end=' ')
|
||||
|
||||
def test2():
|
||||
print('???', end=' ')
|
||||
|
||||
window = disp.disp(
|
||||
disp.root,
|
||||
geometry='1200x800',
|
||||
menuWidget={
|
||||
'文件': {'新建': test, '打开': test},
|
||||
'编辑': {'撤销': test, '重做': test},
|
||||
'视图': {'缩放': test},
|
||||
'帮助': {'关于': disp.authorWindowStarter},
|
||||
},
|
||||
title='音·创 0.2 测试中',
|
||||
buttons=[
|
||||
{
|
||||
'新建': ('', test2),
|
||||
'打开': ('', test2)
|
||||
},
|
||||
{
|
||||
'测试': ('', test2)
|
||||
}
|
||||
],
|
||||
debug=True,
|
||||
)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
__main__()
|
54
Musicreater.New.update.py
Normal file
54
Musicreater.New.update.py
Normal file
@ -0,0 +1,54 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
# 金羿 Eilles
|
||||
# QQ 2647547478
|
||||
# 音·创 开发交流群 861684859
|
||||
# Email EillesWan2006@163.com W-YI_DoctorYI@outlook.com EillesWan@outlook.com
|
||||
# 版权所有 Team-Ryoun 金羿("Eilles Wan") & 诸葛亮与八卦阵("bgArray")
|
||||
# 若需转载或借鉴 请附作者
|
||||
|
||||
|
||||
"""
|
||||
音·创 (Musicreater)
|
||||
一款免费开源的 《我的世界:基岩版》 音乐制作软件
|
||||
Musicreater (音·创)
|
||||
A free opensource software which is used for creating all kinds of musics in Minecraft
|
||||
|
||||
Copyright 2022 Team-Ryoun
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
# 代码写的并非十分的漂亮,还请大佬多多包涵;本软件源代码依照 Apache 2.0 软件协议公开
|
||||
|
||||
|
||||
# 下面为正文
|
||||
|
||||
# 一定会好起来的
|
||||
|
||||
|
||||
from msctLib.buildIN import version
|
||||
|
||||
__ver__ = f'{version.version[1]} {version.version[0]}'
|
||||
__author__ = '金羿Eilles'
|
||||
|
||||
|
||||
|
||||
def __main__():
|
||||
pass
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
__main__()
|
@ -1,425 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''音·创的Tkinter GUI窗口界面显示主程序
|
||||
:若要使用其他界面显示,请详见:
|
||||
:开发说明|指南'''
|
||||
|
||||
|
||||
import tkinter as tk
|
||||
import tkinter.simpledialog as sdialog
|
||||
import tkinter.filedialog as fdialog
|
||||
from msctLib.log import log
|
||||
|
||||
|
||||
DEFAULTBLUE = (0, 137, 242)
|
||||
# 0089F2
|
||||
|
||||
WEAKBLUE = (0, 161, 231)
|
||||
LIGHTBLUE = (38, 226, 255)
|
||||
# 26E2FF
|
||||
|
||||
RED = (255, 52, 50)
|
||||
# FF3432
|
||||
|
||||
PURPLE = (171, 112, 255)
|
||||
# AB70FF
|
||||
|
||||
GREEN = (0, 255, 33)
|
||||
# 00FF21
|
||||
|
||||
WHITE = (242, 244, 246)
|
||||
# F2F4F6
|
||||
|
||||
BLACK = (18, 17, 16)
|
||||
# 121110
|
||||
|
||||
|
||||
backgroundColor = WHITE
|
||||
frontgroundColor = BLACK
|
||||
loadingColor = DEFAULTBLUE
|
||||
errorColor = RED
|
||||
okColor = GREEN
|
||||
tipsColor = PURPLE
|
||||
|
||||
# 注:UI界面字体、代码字体
|
||||
fontPattern = ('DengXian Light', 'Fira Code')
|
||||
|
||||
|
||||
|
||||
# =========================================================
|
||||
# 设定函数部分
|
||||
# =========================================================
|
||||
|
||||
def setTitle(__root, title_: str = '') -> None:
|
||||
'''设置窗口标题
|
||||
:param title: str 窗口标题'''
|
||||
|
||||
if title:
|
||||
self.title = title_
|
||||
__root.title(self.title)
|
||||
if self.debug:
|
||||
log(f"设置窗口标题 {self.title}")
|
||||
|
||||
def setGeometry(__root, geometry: str = '0x0') -> None:
|
||||
'''设置窗口大小
|
||||
:param geometry: str 窗口大小'''
|
||||
__root.geometry(geometry)
|
||||
if self.debug:
|
||||
log(f"设置窗口大小{geometry}")
|
||||
|
||||
def setIcon(__root, bitmap: str = './musicreater.ico', default: str = '') -> bool:
|
||||
'''设置窗口图标
|
||||
:param bitmap: str 图标路径
|
||||
:param default: str 设置对于全局的默认图标路径
|
||||
注意,default参数仅在Windows下有效,其意为将所有没有图标的窗口设置默认图标。如果在非Windows环境使用default参数,将会引发一个错误
|
||||
:retuen bool 是否成功设置图标'''
|
||||
|
||||
try:
|
||||
if default:
|
||||
__root.iconbitmap(bitmap, default)
|
||||
log(f'设置图标为{bitmap},默认为{default}')
|
||||
else:
|
||||
__root.iconbitmap(bitmap)
|
||||
log(f'设置图标为{bitmap}')
|
||||
return True
|
||||
except Exception as e:
|
||||
log(str(e), 'ERROR')
|
||||
if self.debug:
|
||||
raise e
|
||||
return False
|
||||
|
||||
def setMenu(__root) -> None:
|
||||
'''设置根菜单'''
|
||||
if not self.menuWidgets:
|
||||
# 如果传入空参数则返回当前菜单
|
||||
try:
|
||||
return self._RootMenu
|
||||
except Exception as E:
|
||||
if self.debug:
|
||||
raise E
|
||||
log('无法读取菜单信息', 'WARRING')
|
||||
# 如果不是空参数则新建菜单
|
||||
log('新建一个菜单')
|
||||
|
||||
self._RootMenu = {}
|
||||
self._mainMenuBar = tk.Menu(__root)
|
||||
for menuName, menuCmd in self.menuWidgets.items():
|
||||
# 取得一个菜单名和一堆菜单函数及其显示名称
|
||||
menu = tk.Menu(self._mainMenuBar, tearoff=0)
|
||||
for cmdName, cmdFunc in menuCmd.items():
|
||||
if cmdName:
|
||||
menu.add_command(label=cmdName, command=cmdFunc)
|
||||
log('菜单项 -- ' + cmdName)
|
||||
else:
|
||||
menu.add_separator()
|
||||
log('分隔符 -- 分隔符')
|
||||
self._mainMenuBar.add_cascade(label=menuName, menu=menu)
|
||||
self._RootMenu[menuName] = menu
|
||||
log('计入一个菜单 -- ' + menuName)
|
||||
__root.config(menu=self._mainMenuBar)
|
||||
log('菜单设置完毕')
|
||||
|
||||
def addMenu(menuRoot: str = '', menuLabel: str = '', menuCommand=None):
|
||||
'''增加一个菜单项
|
||||
:param menuRoot : str
|
||||
菜单的根菜单,即所属的菜单上的文字
|
||||
:param menuLabel : str
|
||||
所需要增加的项目显示的文字
|
||||
:param menuCommand : <function>
|
||||
'''
|
||||
if menuRoot in self._RootMenu.keys:
|
||||
# 如果已经有父菜单
|
||||
if menuLabel:
|
||||
# 增加菜单指令
|
||||
self._RootMenu[menuRoot].add_command(
|
||||
label=menuLabel, command=menuCommand
|
||||
)
|
||||
else:
|
||||
# 增加分隔栏
|
||||
self._RootMenu[menuRoot].add_separator()
|
||||
else:
|
||||
# 没有父菜单则新增一个父菜单
|
||||
menu = tk.Menu(self._mainMenuBar, tearoff=False)
|
||||
if menuLabel:
|
||||
menu.add_command(label=menuLabel, command=menuCommand)
|
||||
else:
|
||||
menu.add_separator()
|
||||
self._mainMenuBar.add_cascade(label=menuRoot, menu=menu)
|
||||
self._RootMenu[menuRoot] = menu
|
||||
|
||||
def initWidget(__root) -> None:
|
||||
'''设置窗口小部件,分为:
|
||||
:言·论 WordView
|
||||
:快捷按钮面板 ButtonBar
|
||||
:设置框 SettingBar
|
||||
:音轨框 TrackBar
|
||||
:各个音轨的显示框 TrackFrame
|
||||
:信息显示版 InfoBar
|
||||
'''
|
||||
self._wordviewBar = tk.Label(
|
||||
__root,
|
||||
bg='black',
|
||||
fg='white',
|
||||
text=self.wordView,
|
||||
font=(fontPattern[0], 30),
|
||||
)
|
||||
# 定义 言·论 版面
|
||||
log('言·论版面设置完成')
|
||||
|
||||
self._infoBar = tk.Label(
|
||||
__root,
|
||||
bg='white',
|
||||
fg='black',
|
||||
text=self.infoBar,
|
||||
font=(fontPattern[0], 10),
|
||||
)
|
||||
# 定义 信息显示版
|
||||
log('信息显示版设置完成')
|
||||
|
||||
self._buttonBar = tk.Frame(
|
||||
__root,
|
||||
bd=2,
|
||||
)
|
||||
# 定义 快捷按钮面板. 注意!这里是以一个Frame为容器,而不是一个Button列表,后面的版面也以Frame容器居多
|
||||
|
||||
self.setButtonBar(self.buttons)
|
||||
|
||||
self._wordviewBar.pack(side='top', fill='x')
|
||||
self._buttonBar.pack(side='top', fill='x')
|
||||
|
||||
self._infoBar.pack(side='bottom', fill='x')
|
||||
|
||||
def setButtonBar(
|
||||
self,
|
||||
buttonList: list = [],
|
||||
defaultMissingTexturePath: str = './resources/uimage/missing_texture.png',
|
||||
separatorButtonTexturePath: str = './resources/uimage/separator_line.png',
|
||||
) -> None:
|
||||
'''设置快捷按钮面板
|
||||
:param buttonList : list
|
||||
快捷按钮列表,每个元素为一个字典,字典的键为按钮名称,值为一个元组,元组中第一项为按钮的图标,第二项为按钮的回调函数
|
||||
'''
|
||||
|
||||
# 图标应该如下
|
||||
# 新建 打开 保存 |
|
||||
|
||||
self._buttonBarList = []
|
||||
'''按钮对象列表,注意软件调用的时候千万别动!'''
|
||||
|
||||
separatorimg = tk.PhotoImage(file=separatorButtonTexturePath)
|
||||
|
||||
for buttons in buttonList:
|
||||
# 循环每个按钮组
|
||||
for name, args in buttons.items():
|
||||
# 循环每个按钮
|
||||
try:
|
||||
img = tk.PhotoImage(file=args[0])
|
||||
except:
|
||||
log('载入图片失败,使用默认图片','WARNING')
|
||||
if self.debug:
|
||||
raise FileNotFoundError(f'图片{args[0]}不存在')
|
||||
img = tk.PhotoImage(file=defaultMissingTexturePath)
|
||||
button = tk.Button(
|
||||
self._buttonBar,
|
||||
text=name,
|
||||
command=args[1],
|
||||
image=img,
|
||||
bd=2,
|
||||
compound='center',
|
||||
font=(fontPattern[0], 10),
|
||||
)
|
||||
button.pack(side='left', padx=5, pady=5)
|
||||
self._buttonBarList.append(button)
|
||||
# 添加按钮
|
||||
tk.Label(self._buttonBar, image=separatorimg).pack(
|
||||
side='left', padx=5, pady=5
|
||||
)
|
||||
|
||||
def setWordView(self, text: str) -> None:
|
||||
'''重新设置言·论版的文字'''
|
||||
self._wordviewBar['text'] = text
|
||||
|
||||
def setInfoBar(self, text: str) -> None:
|
||||
'''重新设置信息显示版的文字'''
|
||||
self._infoBar['text'] = text
|
||||
|
||||
# =========================================================
|
||||
# 预置函数部分
|
||||
# =========================================================
|
||||
|
||||
def authorWindowStarter(
|
||||
authors: tuple = (
|
||||
('金羿', 'Email EillesWan@outlook.com', 'QQ 2647547478'),
|
||||
('诸葛亮与八卦阵', 'QQ 474037765'),
|
||||
)
|
||||
):
|
||||
'''自定义作者界面'''
|
||||
from languages.lang import _
|
||||
from languages.lang import DEFAULTLANGUAGE
|
||||
from msctLib.buildIN import version
|
||||
|
||||
authorWindow = tk.Tk()
|
||||
authorWindow.title(_('关于'))
|
||||
authorWindow.geometry('550x600') # 像素
|
||||
tk.Label(authorWindow, text='', font=('', 15)).pack()
|
||||
tk.Label(authorWindow, text=_('F音创'), font=('', 35)).pack()
|
||||
tk.Label(
|
||||
authorWindow,
|
||||
text='{} {}'.format(version.version[1] , version.version[0]),
|
||||
font=('', 15),
|
||||
).pack()
|
||||
# pack 的side可以赋值为LEFT RTGHT TOP BOTTOM
|
||||
# grid 的row 是列数、column是行排,注意,这是针对空间控件本身大小来的,即是指向当前控件的第几个。
|
||||
# place的 x、y是(x,y)坐标
|
||||
rylogo = tk.PhotoImage(file='./resources/RyounLogo.png')
|
||||
tk.Label(
|
||||
authorWindow,
|
||||
image=rylogo,
|
||||
width=200,
|
||||
height=200,
|
||||
).pack()
|
||||
tk.Label(authorWindow, text=_('凌云pairs'), font=('', 20)).pack()
|
||||
tk.Label(authorWindow, text='', font=('', 15)).pack()
|
||||
tk.Label(authorWindow, text=_('开发者'), font=('', 15)).pack()
|
||||
for i in authors:
|
||||
for j in i:
|
||||
tk.Label(
|
||||
authorWindow,
|
||||
text=j,
|
||||
font=(
|
||||
'',
|
||||
17 if i.index(j) == 0 else 15,
|
||||
'bold' if i.index(j) == 0 else '',
|
||||
),
|
||||
).pack()
|
||||
tk.Label(authorWindow, text='', font=('', 5)).pack()
|
||||
if DEFAULTLANGUAGE != 'zh-CN':
|
||||
tk.Label(authorWindow, text=_('译者'), font=('', 15)).pack()
|
||||
for i in _('TRANSLATERS').split(';'):
|
||||
for j in i.split(','):
|
||||
tk.Label(
|
||||
authorWindow,
|
||||
text=j,
|
||||
font=(
|
||||
'',
|
||||
17 if i.split(',').index(j) == 0 else 15,
|
||||
'bold' if i.split(',').index(j) == 0 else '',
|
||||
),
|
||||
).pack()
|
||||
|
||||
def exitAboutWindow():
|
||||
authorWindow.destroy()
|
||||
|
||||
tk.Button(authorWindow, text=_('确定'), command=exitAboutWindow).pack()
|
||||
|
||||
authorWindow.mainloop()
|
||||
|
||||
|
||||
class ProgressBar:
|
||||
def __init__(
|
||||
self,
|
||||
root: tk.Tk = tk.Tk(),
|
||||
style: tuple = (DEFAULTBLUE, BLACK, WHITE),
|
||||
type: bool = False,
|
||||
info: str = '',
|
||||
debug: bool = False,
|
||||
) -> None:
|
||||
'''建立一个进度条或者加载等待界面
|
||||
:param root : tk.Tk
|
||||
建立进度条的根窗口
|
||||
:param style : tuple
|
||||
设置主题颜色,第一个参数为进度条或者等待转圈圈的颜色,第二个参数为前景色,第三个是背景色
|
||||
:param type : bool
|
||||
类型,为 False 时为进度条,为 True 时为等待板
|
||||
:param info : str
|
||||
显示的附加信息
|
||||
:param debug : bool
|
||||
是否输出日志到控制台'''
|
||||
self.root = root
|
||||
|
||||
|
||||
# TODO
|
||||
# 单选框与复选框
|
||||
|
||||
|
||||
if __name__ == '__mian__':
|
||||
|
||||
# __root,
|
||||
# debug: bool = False,
|
||||
# title: str = '音·创',
|
||||
# geometry: str = '0x0',
|
||||
# iconbitmap: tuple = ('./resources/musicreater.ico', './resources/musicreater.ico'),
|
||||
# menuWidget: dict = {},
|
||||
# wordView: str = '音·创 Musicreater',
|
||||
# buttons: list = [],
|
||||
# settingBox: list = [],
|
||||
# notemap: list = [],
|
||||
# infobar: str = '就绪',
|
||||
|
||||
'''使用参数建立基本的 音·创 窗口
|
||||
:param root 根窗口
|
||||
:param debug 是否将日志输出到控制台
|
||||
:param title 窗口标题
|
||||
wordview: str #言论部分显示的字样
|
||||
button: list = [ # 操作按钮部分
|
||||
dict = {
|
||||
按钮名称 : tuple(按钮图标,执行函数)
|
||||
},
|
||||
],
|
||||
settingbox: list = [ # 设置部分显示的字样及其对应的设置函数
|
||||
(
|
||||
设置名称:str,
|
||||
值类型:tuple,
|
||||
显示内容:str,
|
||||
设置操作函数:<function>,
|
||||
)
|
||||
],
|
||||
map: list = [ # 一首曲目的音符数据
|
||||
音符数据
|
||||
]
|
||||
:param infobar str 显示信息用
|
||||
'''
|
||||
|
||||
if debug:
|
||||
log('载入参数')
|
||||
|
||||
# 载入参量 注意!图标将不被载入参数
|
||||
|
||||
|
||||
self.title = title
|
||||
'''窗口标题'''
|
||||
|
||||
self.menuWidgets = menuWidget
|
||||
'''菜单设定项'''
|
||||
|
||||
self.wordView = wordView
|
||||
'''言·论 所显示的文字'''
|
||||
|
||||
self.buttons = buttons
|
||||
'''快捷功能按钮'''
|
||||
|
||||
self.settingBox = settingBox
|
||||
'''设置框'''
|
||||
|
||||
self.notemap = notemap
|
||||
'''音符列表'''
|
||||
|
||||
self.infoBar = infobar
|
||||
'''信息显示版所显示的文字'''
|
||||
|
||||
self.debug = debug
|
||||
'''是否打开调试模式'''
|
||||
|
||||
self.setTitle(__root,)
|
||||
|
||||
self.setGeometry(__root, geometry)
|
||||
self.setIcon(__root, *iconbitmap)
|
||||
|
||||
self.setMenu(__root)
|
||||
|
||||
self.initWidget(__root)
|
||||
|
||||
self.start(__root)
|
||||
|
||||
def start(self, __root) -> None:
|
||||
# 启动主消息循环
|
||||
__root.mainloop()
|
2005
Musicreater.py
2005
Musicreater.py
File diff suppressed because it is too large
Load Diff
@ -1,170 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:2个---未解决;警告(二级)错误:2个;语法(一级)错误:17个
|
||||
|
||||
|
||||
__version__ = '0.0.1'
|
||||
__all__ = []
|
||||
__author__ = 'Fuckcraft <https://gitee.com/fuckcraft>'
|
||||
|
||||
'''
|
||||
Fuckcraft Websocket Library (FCWSLIB)
|
||||
A library to develop minecraft websocket server easily.
|
||||
|
||||
Copyright (C) 2021 Fuckcraft
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
'''
|
||||
|
||||
from main import *
|
||||
|
||||
# import os
|
||||
import json
|
||||
import uuid
|
||||
# import logging
|
||||
import asyncio
|
||||
import time
|
||||
import websockets
|
||||
|
||||
|
||||
# 写这段代码的时候,只有我和上帝知道这段代码是干什么的。
|
||||
# 现在只有上帝知道。
|
||||
# ----
|
||||
# 没毛病,我讨厌两种人:一种是要我写注释的人,一种是给我代码看但没有写注释的人。
|
||||
|
||||
# 此函数用于向 Minecraft 订阅请求
|
||||
async def subscribe(websocket, event_name):
|
||||
"""
|
||||
参数:
|
||||
: websocket : websocket 对象 :
|
||||
: event_name : 需要订阅的请求 :
|
||||
|
||||
返回:
|
||||
None
|
||||
"""
|
||||
|
||||
response = {
|
||||
'body': {
|
||||
'eventName': str(event_name) # 示例:PlayerMessage
|
||||
},
|
||||
'header': {
|
||||
'requestId': str(uuid.uuid4()),
|
||||
'messagePurpose': 'subscribe',
|
||||
'version': 1,
|
||||
'messageType': 'commandRequest'
|
||||
}
|
||||
}
|
||||
|
||||
# 增加 json 的可读性
|
||||
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
response = json.dumps(response)
|
||||
|
||||
await websocket.send(response)
|
||||
|
||||
|
||||
# 此函数用于向 Minecraft 消除订阅请求
|
||||
async def unsubscribe(webscket):
|
||||
"""
|
||||
参数:
|
||||
: websocket : websocket 对象 :
|
||||
: event_name : 需要消除订阅的请求 :
|
||||
|
||||
返回:
|
||||
None
|
||||
"""
|
||||
print(webscket)
|
||||
|
||||
response = {
|
||||
"body": {
|
||||
"eventName": str(event_name) # PlayerMessage
|
||||
},
|
||||
"header": {
|
||||
"requestId": str(uuid.uuid4()),
|
||||
"messagePurpose": "unsubscribe",
|
||||
"version": 1,
|
||||
"messageType": "commandRequest"
|
||||
}
|
||||
}
|
||||
|
||||
# 增加 json 的可读性
|
||||
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
response = json.dumps(response)
|
||||
|
||||
await websocket.send(response)
|
||||
|
||||
|
||||
# 此函数用于向 Minecraft 执行命令
|
||||
async def send_command(websocket, command):
|
||||
"""
|
||||
参数:
|
||||
: websocket : websocket 对象 :
|
||||
: command : 执行的命令 :
|
||||
|
||||
返回:
|
||||
None
|
||||
"""
|
||||
|
||||
response = {
|
||||
'body': {
|
||||
'origin': {
|
||||
'type': 'player'
|
||||
},
|
||||
'commandLine': str(command),
|
||||
'version': 1
|
||||
},
|
||||
'header': {
|
||||
'requestId': str(uuid.uuid4()),
|
||||
'messagePurpose': 'commandRequest',
|
||||
'version': 1,
|
||||
'messageType': 'commandRequest'
|
||||
}
|
||||
}
|
||||
|
||||
# 增加 json 的可读性
|
||||
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
response = json.dumps(response)
|
||||
|
||||
await websocket.send(response)
|
||||
|
||||
|
||||
# 此函数用于向 Minecraft 发送消息
|
||||
async def tellraw(websocket, message):
|
||||
"""
|
||||
参数:
|
||||
: websocket : websocket 对象 :
|
||||
: message : 发送的消息 :
|
||||
|
||||
返回:
|
||||
None
|
||||
"""
|
||||
|
||||
command = {
|
||||
'rawtext': [
|
||||
{
|
||||
'text': '[{}] {}'.format(time.asctime(), message)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 增加 json 可读性
|
||||
# command = json.dumps(command, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
command = json.dumps(command)
|
||||
command = 'tellraw @a {}'.format(command)
|
||||
|
||||
await send_command(websocket, command)
|
||||
|
||||
|
||||
def run_server(function):
|
||||
# 修改 ip 地址和端口
|
||||
start_server = websockets.serve(function, 'localhost', 8080)
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
160
fcwslib/main.py
160
fcwslib/main.py
@ -1,160 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__version__ = '0.0.1'
|
||||
__all__ = ['run_server', 'subscribe', 'unsubscribe', 'send_command', 'tellraw']
|
||||
__author__ = 'Fuckcraft <https://gitee.com/fuckcraft>'
|
||||
|
||||
'''
|
||||
Fuckcraft Websocket Library (FCWSLIB)
|
||||
A library to develop minecraft websocket server easily.
|
||||
|
||||
Copyright (C) 2021 Fuckcraft
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
'''
|
||||
|
||||
import os
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import asyncio
|
||||
import time
|
||||
import websockets
|
||||
|
||||
# 写这段代码的时候,只有我和上帝知道这段代码是干什么的。
|
||||
# 现在只有上帝知道。
|
||||
|
||||
# 此函数用于向 Minecraft 订阅请求
|
||||
async def subscribe(websocket, event_name):
|
||||
'''
|
||||
输入:
|
||||
: websocket : websocket 对象 :
|
||||
: event_name : 需要订阅的请求 :
|
||||
|
||||
输出:
|
||||
None
|
||||
'''
|
||||
|
||||
response = {
|
||||
'body': {
|
||||
'eventName': str(event_name) # 示例:PlayerMessage
|
||||
},
|
||||
'header': {
|
||||
'requestId': str(uuid.uuid4()),
|
||||
'messagePurpose': 'subscribe',
|
||||
'version': 1,
|
||||
'messageType': 'commandRequest'
|
||||
}
|
||||
}
|
||||
|
||||
# 增加 json 的可读性
|
||||
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
response = json.dumps(response)
|
||||
|
||||
await websocket.send(response)
|
||||
|
||||
# 此函数用于向 Minecraft 消除订阅请求
|
||||
async def unsubscribe(webscket):
|
||||
'''
|
||||
输入:
|
||||
: websocket : websocket 对象 :
|
||||
: event_name : 需要消除订阅的请求 :
|
||||
|
||||
输出:
|
||||
None
|
||||
'''
|
||||
|
||||
response = {
|
||||
"body": {
|
||||
"eventName": str(event_name) # 示例:PlayerMessage
|
||||
},
|
||||
"header": {
|
||||
"requestId": str(uuid.uuid4()),
|
||||
"messagePurpose": "unsubscribe",
|
||||
"version": 1,
|
||||
"messageType": "commandRequest"
|
||||
}
|
||||
}
|
||||
|
||||
# 增加 json 的可读性
|
||||
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
response = json.dumps(response)
|
||||
|
||||
await websocket.send(response)
|
||||
|
||||
# 我个人不负责这块的质量,因为他们逼迫我违心的写了这段代码
|
||||
|
||||
# 此函数用于向 Minecraft 执行命令
|
||||
async def send_command(websocket, command):
|
||||
'''
|
||||
输入:
|
||||
: websocket : websocket 对象 :
|
||||
: command : 执行的命令 :
|
||||
|
||||
输出:
|
||||
None
|
||||
'''
|
||||
|
||||
response = {
|
||||
'body': {
|
||||
'origin': {
|
||||
'type': 'player'
|
||||
},
|
||||
'commandLine': str(command),
|
||||
'version': 1
|
||||
},
|
||||
'header': {
|
||||
'requestId': str(uuid.uuid4()),
|
||||
'messagePurpose': 'commandRequest',
|
||||
'version': 1,
|
||||
'messageType': 'commandRequest'
|
||||
}
|
||||
}
|
||||
|
||||
# 增加 json 的可读性
|
||||
# response = json.dumps(response, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
response = json.dumps(response)
|
||||
|
||||
await websocket.send(response)
|
||||
|
||||
# 此函数用于向 Minecraft 发送消息
|
||||
async def tellraw(websocket, message):
|
||||
'''
|
||||
输入:
|
||||
: websocket : websocket 对象 :
|
||||
: message : 发送的消息 :
|
||||
|
||||
输出:
|
||||
None
|
||||
'''
|
||||
|
||||
command = {
|
||||
'rawtext':[
|
||||
{
|
||||
'text':'[{}] {}'.format(time.asctime(), message)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 增加 json 可读性
|
||||
# command = json.dumps(command, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False)
|
||||
command = json.dumps(command)
|
||||
command = 'tellraw @a {}'.format(command)
|
||||
|
||||
await send_command(websocket, command)
|
||||
|
||||
def run_server(function):
|
||||
# 修改 ip 地址和端口
|
||||
start_server = websockets.serve(function, 'localhost', 8080)
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
asyncio.get_event_loop().run_forever()
|
||||
|
BIN
fcwslib/版权声明.png
BIN
fcwslib/版权声明.png
Binary file not shown.
Before Width: | Height: | Size: 67 KiB |
@ -5,8 +5,8 @@
|
||||
|
||||
class version:
|
||||
libraries = (
|
||||
'mido', 'amulet', 'amulet-core', 'amulet-nbt', 'piano_transcription_inference', 'pypinyin',
|
||||
'pyinstaller', 'py7zr','websockets', 'zhdate', 'requests'
|
||||
'wxPython', 'mido', 'amulet', 'amulet-core', 'amulet-nbt', 'piano_transcription_inference', 'pypinyin',
|
||||
'pyinstaller', 'py7zr','websockets', 'zhdate', 'requests',
|
||||
)
|
||||
"""当前所需库"""
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,216 +0,0 @@
|
||||
import os
|
||||
import brotli
|
||||
|
||||
'''感谢由 Charlie_Ping “查理平” 带来的bdx转换代码'''
|
||||
|
||||
|
||||
class BdxConverter:
|
||||
__header = "BD@"
|
||||
__bin_header = b"BDX"
|
||||
__generator_author = b"& Musicreater"
|
||||
|
||||
keys = {
|
||||
# x--, x++, addSmallX(-128~127), addX(-32768~32767), addBigX(-2147483648~2147483647)
|
||||
"x": [b"\x0f", b"\x0e", b"\x1c", b"\x14", b"\x15"],
|
||||
"y": [b"\x11", b"\x10", b"\x1d", b"\x16", b"\x17"],
|
||||
"z": [b"\x13", b"\x12", b"\x1e", b"\x18", b"\x19"],
|
||||
"end": b"\x58",
|
||||
"isSigned": b"\x5a",
|
||||
"placeCommandBlockWithData": b"\x1b",#用不上
|
||||
"placeBlock": b"\x07"
|
||||
}
|
||||
|
||||
def __init__(self, file_path: str, author: str, blocks):
|
||||
self.author = author
|
||||
self.blocks = blocks
|
||||
self.file_path = file_path
|
||||
self.direction = [0, 0, 0]
|
||||
self.block_type = self.get_block_type
|
||||
self.__file = self.create_and_upload_file
|
||||
|
||||
@property
|
||||
def get_block_type(self):
|
||||
"""
|
||||
blocks
|
||||
[
|
||||
{
|
||||
"direction": [x: int, y: int, z: int],
|
||||
block_name: str,
|
||||
particular_value: int,
|
||||
}
|
||||
]
|
||||
:return: list 给出的所有方块种类名称
|
||||
"""
|
||||
block_type = set()
|
||||
for block in self.blocks:
|
||||
block_type.add(block["block_name"])
|
||||
block_type = list(block_type)
|
||||
return block_type
|
||||
|
||||
@property
|
||||
def create_and_upload_file(self):
|
||||
"""
|
||||
创建一个bdx文件
|
||||
:return: 一个文件对象
|
||||
"""
|
||||
_dir = os.path.dirname(self.file_path)
|
||||
if not os.path.isdir(_dir):
|
||||
os.makedirs(_dir)
|
||||
_bytes = self.__bin_header
|
||||
_bytes += b"\x00"
|
||||
_bytes += self.author.encode("utf-8") + self.__generator_author
|
||||
for i in self.block_type:
|
||||
_bytes += b"\x00\x01"
|
||||
_bytes += bytes(i, encoding="utf-8")
|
||||
_bytes += b"\x00"
|
||||
_bytes += self.upload_blocks()
|
||||
_bytes += b"X"
|
||||
with open(self.file_path, "w+") as f:
|
||||
f.write("BD@")
|
||||
f.close()
|
||||
with open(self.file_path, "ab+") as f:
|
||||
f.write(brotli.compress(_bytes))
|
||||
f.close()
|
||||
return open(self.file_path,'a+')
|
||||
|
||||
def upload_blocks(self):
|
||||
"""
|
||||
计算差值
|
||||
写入移动过程
|
||||
写入方块
|
||||
更新差值
|
||||
:return:
|
||||
"""
|
||||
_types = b""
|
||||
for block in self.blocks:
|
||||
# print(f"当前方块:{block['block_name']}, 位置: {block['direction']}]")
|
||||
diff = self.move_pointer(self.direction, block["direction"])
|
||||
_types += diff
|
||||
if block["block_name"] in ["command_block",
|
||||
"chain_command_block",
|
||||
"repeating_command_block"]:
|
||||
_types += self.obtain_command_block(block)
|
||||
else:
|
||||
_types += self.obtain_universal_block(block)
|
||||
self.direction = block["direction"]
|
||||
|
||||
|
||||
return _types
|
||||
|
||||
def move_pointer(self, direction: list, new_direction):
|
||||
"""
|
||||
给出 两个[x, y, z]坐标,返回pointer的移动过程
|
||||
:param direction: 坐标 1
|
||||
:param new_direction: 坐标 2
|
||||
:return: bytes
|
||||
"""
|
||||
_bytes = b""
|
||||
for i, sign in enumerate(["x", "y", "z"]):
|
||||
# print(f"<{sign}> 新-旧={new_direction[i]-direction[i]}")
|
||||
distance = new_direction[i] - direction[i]
|
||||
if distance == 0:
|
||||
# print("距离是0?跳过了")
|
||||
continue
|
||||
_bytes += self.obtain_pointer_type(distance, sign)
|
||||
# print(f"向 {sign} 运动了 {distance} 格子")
|
||||
return _bytes
|
||||
|
||||
@classmethod
|
||||
def obtain_pointer_type(cls, num: int, coordinate: str):
|
||||
"""
|
||||
|
||||
用于确定辅助玩家以某一数据类型走指定长度
|
||||
|
||||
-1 -> 0
|
||||
1 -> 1
|
||||
[128, 127] -> 2
|
||||
[-32768, 32767] -> 3
|
||||
[-2147483648, 2147483647] -> 4
|
||||
:param num:
|
||||
:param coordinate: 坐标轴种类,x y 或 z
|
||||
:return:
|
||||
"""
|
||||
if num == 0:
|
||||
return
|
||||
pointer = 0
|
||||
condition = (num != -1, # byte=0, pointer=1
|
||||
num < -1 or num > 1, # byte=1, pointer=2
|
||||
num < -128 or num > 127, # byte=2, pointer=3
|
||||
num < -32768 or num > 32767, # byte=4, pointer=4
|
||||
)
|
||||
for i in condition:
|
||||
if i:
|
||||
pointer += 1
|
||||
pointer_type = cls.keys[coordinate][pointer]
|
||||
|
||||
byte_len = 2 ** (pointer - 2)
|
||||
if byte_len >= 1:
|
||||
num_byte = num.to_bytes(byte_len, byteorder="big", signed=True)
|
||||
return pointer_type + num_byte
|
||||
return pointer_type
|
||||
|
||||
def obtain_universal_block(self, block):
|
||||
"""
|
||||
给定一个方块, 返回此方块在这个bdx中的id和方块data
|
||||
:param block: {block_name: str,particular_value: int}
|
||||
:return: bytes
|
||||
"""
|
||||
block_id = b"\x07" + self.block_type.index(block["block_name"]).to_bytes(2, byteorder="big", signed=False)
|
||||
particular_value = block["particular_value"].to_bytes(2, byteorder="big", signed=False)
|
||||
block_header = block_id + particular_value
|
||||
return block_header
|
||||
|
||||
def obtain_command_block(self, block):
|
||||
"""
|
||||
给定一个命令方块,返回命令方块各种数据
|
||||
:param block: {
|
||||
"direction": [x: int, y: int, z: int]
|
||||
"block_name": str,
|
||||
"particular_value": int,
|
||||
"impluse": int, # unsigned_int32
|
||||
"command": str,
|
||||
"customName": str,
|
||||
"lastOutput": str, # 没特殊要求写个\x00就得了
|
||||
"tickdelay": int, # int32
|
||||
"executeOnFirstTick": int, # 1 bytes
|
||||
"trackOutput": int, # 1 bytes
|
||||
"conditional": int, # 1 bytes
|
||||
"needRedstone": int # 1 bytes
|
||||
}
|
||||
:return: bytes of command_block
|
||||
"""
|
||||
|
||||
block_id = b"\x24"
|
||||
particular_value = block["particular_value"].to_bytes(2, byteorder="big", signed=False)
|
||||
block_header = block_id + particular_value
|
||||
for i in [
|
||||
block["impluse"].to_bytes(4, byteorder="big", signed=False),
|
||||
bytes(block["command"], encoding="utf-8") + b"\x00",
|
||||
bytes(block["customName"], encoding="utf-8") + b"\x00",
|
||||
bytes(block["lastOutput"], encoding="utf-8") + b"\x00",
|
||||
block["tickdelay"].to_bytes(4, byteorder="big", signed=True),
|
||||
block["executeOnFirstTick"].to_bytes(1, byteorder="big"),
|
||||
block["trackOutput"].to_bytes(1, byteorder="big"),
|
||||
block["conditional"].to_bytes(1, byteorder="big"),
|
||||
block["needRedstone"].to_bytes(1, byteorder="big")
|
||||
]:
|
||||
block_header += i
|
||||
return block_header
|
||||
|
||||
if __name__ == '__main__':
|
||||
block = [{"direction": [-1, -1, -1], "block_name": "concrete", "particular_value": 5},
|
||||
{"direction": [1, 5, 1], "block_name": "stained_glass", "particular_value": 7},
|
||||
{"direction": [2, 4, 1], "block_name": "command_block", "particular_value": 3,
|
||||
"impluse": 0,
|
||||
"command": "say A generator test",
|
||||
"customName": "test",
|
||||
"lastOutput": "",
|
||||
"tickdelay": 24,
|
||||
"executeOnFirstTick": 0,
|
||||
"trackOutput": 0,
|
||||
"conditional": 0,
|
||||
"needRedstone": 1
|
||||
},
|
||||
{"direction": [3, 4, 1], "block_name": "concrete", "particular_value": 6},
|
||||
{"direction": [-123412133, 4, 1], "block_name": "concrete", "particular_value": 7}]
|
||||
bdx = BdxConverter("./test02.bdx", "Charlie_Ping",block)
|
@ -1,93 +0,0 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
"""提供错误报告的基本操作及方法 顺便提供版本更新、安装库等功能"""
|
||||
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:1个;语法(一级)错误:72个
|
||||
import os
|
||||
|
||||
|
||||
def makeZip(sourceDir, outFilename, compression=8, exceptFile=None):
|
||||
import zipfile
|
||||
"""使用compression指定的算法打包目录为zip文件\n
|
||||
默认算法为DEFLATED(8),可用算法如下:\n
|
||||
STORED = 0\n
|
||||
DEFLATED = 8\n
|
||||
BZIP2 = 12\n
|
||||
LZMA = 14\n
|
||||
"""
|
||||
zipf = zipfile.ZipFile(outFilename, 'w', compression)
|
||||
pre_len = len(os.path.dirname(sourceDir))
|
||||
for parent, dirnames, filenames in os.walk(sourceDir):
|
||||
for filename in filenames:
|
||||
if filename == exceptFile:
|
||||
continue
|
||||
print(filename)
|
||||
pathfile = os.path.join(parent, filename)
|
||||
arcname = pathfile[pre_len:].strip(os.path.sep) # 相对路径
|
||||
zipf.write(pathfile, arcname)
|
||||
|
||||
zipf.close()
|
||||
del zipf, pre_len
|
||||
|
||||
|
||||
# 以上函数节选并修改自 正在攀登的小蜗牛 的博客:https://blog.csdn.net/qq_21127151/article/details/107503942
|
||||
|
||||
|
||||
class report:
|
||||
"""发送报告以及相应的任务处理"""
|
||||
|
||||
def __init__(self, senderName: str = 'Unknown', senderContact: str = 'None', describetion: str = ''):
|
||||
""":param senderName 发送者名称
|
||||
:param senderContact 发送者联系方式
|
||||
:param describetion 问题描述"""
|
||||
self.senderName = senderName
|
||||
self.senderContact = senderContact
|
||||
self.describetion = describetion
|
||||
if not self.senderName:
|
||||
self.senderName = 'Unknown'
|
||||
if not self.senderContact:
|
||||
self.senderContact = 'None'
|
||||
|
||||
def emailReport(self):
|
||||
"""使用E-mail方法发送当前的日志和临时文件等"""
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.header import Header
|
||||
from nmcsup.log import log
|
||||
log("发送错误报告")
|
||||
import os
|
||||
log("添加标题与正文")
|
||||
msg = MIMEMultipart()
|
||||
# 发送者与接收者显示名称
|
||||
msg["From"] = Header(self.senderName, 'utf-8')
|
||||
msg["To"] = Header("W-YI (QQ2647547478)", 'utf-8')
|
||||
# 标题
|
||||
msg["Subject"] = '音·创 - 来自 ' + self.senderName + ' 的错误报告'
|
||||
# 正文
|
||||
msg.attach(
|
||||
MIMEText("来自" + self.senderName + "( " + self.senderContact + " )的错误描述:\n" + self.describetion,
|
||||
'utf-8'))
|
||||
log("添加完毕,正在生成压缩包...")
|
||||
makeZip("./", "Temps&Logs.zip", exceptFile="Temps&Logs.zip")
|
||||
attafile = MIMEText(str(open("Temps&Logs.zip", 'rb').read()), "base64", 'gb2312')
|
||||
attafile["Content-Type"] = 'application/octet-stream'
|
||||
attafile["Content-Disposition"] = 'attachmentfilename="BugReport_from_' + self.senderName + '.zip"'
|
||||
msg.attach(attafile)
|
||||
log("完毕,准备发送")
|
||||
try:
|
||||
smtp = smtplib.SMTP()
|
||||
smtp.connect("smtp.163.com")
|
||||
# smtp.login("RyounDevTeam@163.com","RyounDaiYi99")
|
||||
# SIQQKQQYCZRVIDFJ是授权密码
|
||||
smtp.login("RyounDevTeam@163.com", "SIQQKQQYCZRVIDFJ")
|
||||
smtp.sendmail("RyounDevTeam@163.com", ["RyounDevTeam@163.com", ], msg.as_string())
|
||||
log("错误汇报邮件已发送")
|
||||
except smtplib.SMTPException as e:
|
||||
log("错误汇报邮件发送失败:\n" + str(e))
|
||||
log("清空内存和临时文件")
|
||||
del msg, attafile
|
||||
os.remove("./Temps&Logs.zip")
|
||||
|
||||
|
||||
from msctLib.buildIN import version
|
@ -1,422 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""音·创 的函数操作和一些其他功能"""
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:0个;语法(一级)错误:91个
|
||||
|
||||
|
||||
from nmcsup.log import log
|
||||
|
||||
|
||||
def delPart(Data, starter, ender, includeStart: bool = True, includend: bool = True):
|
||||
"""删除序列从starter物件到ender物件之间的部分\n
|
||||
includeStart与inclodend分别控制此函数是否包括starter和ender物件所在部分,默认为真\n
|
||||
starter与ender若为None则默认从首或尾开始"""
|
||||
try:
|
||||
if starter is None:
|
||||
includeStart = True
|
||||
starter = Data[0]
|
||||
if ender is None:
|
||||
includend = True
|
||||
ender = Data[len(Data) - 1]
|
||||
if includend:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):len(Data) - Data[len(Data)::-1].index(ender)]
|
||||
else:
|
||||
return Data[Data.index(starter) + 1:len(Data) - Data[len(Data)::-1].index(ender)]
|
||||
else:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):len(Data) - Data[len(Data)::-1].index(ender) - 1]
|
||||
else:
|
||||
return Data[Data.index(starter) + 1:len(Data) - Data[len(Data)::-1].index(ender) - 1]
|
||||
except:
|
||||
return 0
|
||||
|
||||
|
||||
def keepart(Data, starter, ender, includeStart: bool = True, includend: bool = True):
|
||||
"""保留序列从starter物件到ender物件之间的部分\n
|
||||
includeStart与inclodend分别控制此函数是否包括starter和ender物件所在部分,默认为真\n
|
||||
starter与ender若为None则默认从首或尾开始"""
|
||||
try:
|
||||
if starter is None:
|
||||
includeStart = True
|
||||
starter = Data[0]
|
||||
if ender is None:
|
||||
includend = True
|
||||
ender = Data[len(Data) - 1]
|
||||
if includend:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):Data.index(ender) + 1]
|
||||
else:
|
||||
return Data[Data.index(starter) + 1:Data.index(ender) + 1]
|
||||
else:
|
||||
if includeStart:
|
||||
return Data[Data.index(starter):Data.index(ender)]
|
||||
else:
|
||||
return Data[Data.index(starter) + 1:Data.index(ender)]
|
||||
except:
|
||||
return 0
|
||||
|
||||
|
||||
def lenFunction(fun) -> int:
|
||||
"""取得函数指令部分长度,即忽略#开头的注释"""
|
||||
try:
|
||||
f = 0
|
||||
for i in fun:
|
||||
if i.replace(" ", '')[0] == '#':
|
||||
f += 1
|
||||
return len(fun) - f
|
||||
except:
|
||||
return -1
|
||||
|
||||
|
||||
def funSplit(bigFile, maxCmdLen: int = 10000):
|
||||
"""分割bigFile大的函数文件,bigFile需要读入文件流\n
|
||||
返回的部分,每行指令皆带有行尾换行符\\n\n
|
||||
返回-1为大小低于maxCmdLen最长函数指令长度"""
|
||||
bigFile = bigFile.readlines()
|
||||
if lenFunction(bigFile) < maxCmdLen:
|
||||
return -1
|
||||
part = []
|
||||
parts = []
|
||||
h = 0
|
||||
for i in bigFile:
|
||||
if i.replace(" ", '')[0] == '#':
|
||||
part.append(i + '\n')
|
||||
else:
|
||||
part.append(i + '\n')
|
||||
h += 1
|
||||
if h >= 10000:
|
||||
parts.append(part)
|
||||
part = []
|
||||
h = 0
|
||||
return parts
|
||||
|
||||
|
||||
def makeFuncFiles(musicset, path='./'):
|
||||
"""在指定目录下生成函数文件"""
|
||||
from nmcsup.trans import Note2Cmd
|
||||
commands = []
|
||||
starts = []
|
||||
log("=========================正在在此处生成文件:" + path)
|
||||
maxlen = -1
|
||||
for i in range(len(musicset['musics'])):
|
||||
log('写入第' + str(i) + '个数据')
|
||||
commands.append("scoreboard players add @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\"] " +
|
||||
musicset['musics'][i]['set']['ScoreboardName'] + " 1\n")
|
||||
commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
musicset['musics'][i]['set']['ScoreboardName'] + "=1..10}] ~~~ title @a" + musicset['mainset'][
|
||||
'PlayerSelect'] + " title " + musicset['mainset']['MusicTitle'] + "\n")
|
||||
commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
musicset['musics'][i]['set']['ScoreboardName'] + "=1..10}] ~~~ title @a" + musicset['mainset'][
|
||||
'PlayerSelect'] + " subtitle 本函数乐曲由§b§l凌云§r§3函数音乐创建§r生成\n")
|
||||
if len(musicset['musics'][i]['notes']) > maxlen:
|
||||
maxlen = len(musicset['musics'][i]['notes'])
|
||||
starts.append("scoreboard objectives add " + musicset['musics'][i]['set']['ScoreboardName'] + " dummy\n")
|
||||
starts.append("summon armor_stand " + musicset['musics'][i]['set']['EntityName'] + '\n')
|
||||
with open(path + musicset['mainset']['MusicTitle'] + '_Part' + str(i) + '.mcfunction', 'w',
|
||||
encoding='UTF-8') as f:
|
||||
f.writelines(Note2Cmd(musicset['musics'][i]['notes'], musicset['musics'][i]['set']['ScoreboardName'],
|
||||
musicset['musics'][i]['set']['Instrument'], musicset['mainset']['PlayerSelect'],
|
||||
True))
|
||||
if musicset['mainset']['IsRepeat']:
|
||||
log("增加重复语句")
|
||||
for i in range(len(musicset['musics'])):
|
||||
commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
musicset['musics'][i]['set']['ScoreboardName'] + "=" + str(
|
||||
(maxlen + 2) * 10) + "}] ~~~ scoreboard players set @e[name=\"" + musicset['musics'][i]['set'][
|
||||
'EntityName'] + "\"] " + musicset['musics'][i]['set']['ScoreboardName'] + " -1\n")
|
||||
log("增加版权语句")
|
||||
commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
starts.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
log("写入支持文件")
|
||||
with open(path + musicset['mainset']['MusicTitle'] + '_Support.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(commands)
|
||||
log("写入开始文件")
|
||||
with open(path + 'Start_' + musicset['mainset']['MusicTitle'] + '.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(starts)
|
||||
del commands, starts, maxlen
|
||||
log("完成============================")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def makeFunDir(musicset, path='./'):
|
||||
"""在指定目录下生成函数包文件夹"""
|
||||
import os
|
||||
import uuid
|
||||
log("=============================生成函数包文件夹")
|
||||
# note,packname="Ryoun",FileName="Music",EntityName_='music_support',ScoreboardName_='music_support',
|
||||
# MusicTitle_='Noname',PlayerSelect_='',Repeat_=False,Instrument_='harp'
|
||||
try:
|
||||
os.makedirs(path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions")
|
||||
log("已创建目录" + path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions")
|
||||
except FileExistsError:
|
||||
log("目录已有无需创建")
|
||||
pass
|
||||
# 判断文件皆存在
|
||||
if not (os.path.exists(
|
||||
path + musicset['mainset']['PackName'] + "Pack/world_behavior_packs.json") and os.path.exists(
|
||||
path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/manifest.json")):
|
||||
log("创建manifest.json以及world_behavior_packs.json")
|
||||
behaviorUuid = uuid.uuid4()
|
||||
with open(path + musicset['mainset']['PackName'] + "Pack/world_behavior_packs.json", "w") as f:
|
||||
f.write("[\n {\"pack_id\": \"" + str(behaviorUuid) + "\",\n \"version\": [ 0, 0, 1 ]}\n]")
|
||||
p = path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset']['PackName'] + \
|
||||
"/manifest.json"
|
||||
with open(p, "w") as f:
|
||||
f.write("{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" + musicset['mainset'][
|
||||
'PackName'] + " Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" +
|
||||
musicset['mainset']['PackName'] + "Pack\",\n \"uuid\": \"" + str(
|
||||
behaviorUuid) + "\"\n },\n \"modules\": [\n {\n \"description\": \"" + musicset['mainset'][
|
||||
'PackName'] + " Pack : behavior pack\",\n \"type\": \"data\",\n \"version\":"
|
||||
" [ 0, 0, 1 ],\n \"uuid\": \"" + str(
|
||||
uuid.uuid4()) + "\"\n }\n ]\n}")
|
||||
makeFuncFiles(musicset, path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions/")
|
||||
log("完成============================")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def makeNewFuncFiles(musicset, path='./', isProsess:bool = False):
|
||||
"""在指定目录下生成函数文件"""
|
||||
from msctspt.transfer import newList_conversion_SinglePlayer
|
||||
commands = []
|
||||
starts = []
|
||||
starts.__len__()
|
||||
starts.append("scoreboard objectives add " + musicset['musics'][0]['set']['ScoreboardName'] + " dummy\n")
|
||||
# starts.append("summon armor_stand " + musicset['musics'][0]['set']['EntityName'] + '\n')
|
||||
# starts.append("scoreboard objectives setdisplay sidebar " + musicset['musics'][0]['set']['ScoreboardName'] + '\n')
|
||||
# starts.append("scoreboard players set @e[type=armor_stand, name=\"" + musicset['musics'][0]['set']['EntityName'] +"\"] " + musicset['musics'][0]['set']['ScoreboardName'] + " 0" + '\n')
|
||||
|
||||
log("=========================正在在此处生成文件:" + path)
|
||||
|
||||
# commands.append("scoreboard players add @e[name=\"" + musicset['musics'][0]['set']['EntityName'] + "\"] " + musicset['musics'][0]['set']['ScoreboardName'] + " 1\n")
|
||||
maxlen = -1
|
||||
for i in range(len(musicset['musics'])):
|
||||
log('写入第' + str(i) + '个数据')
|
||||
|
||||
if len(musicset['musics'][i]['notes']) > maxlen:
|
||||
maxlen = len(musicset['musics'][i]['notes'])
|
||||
with open(path + musicset['mainset']['MusicTitle'] + '_Part' + str(i) + '.mcfunction', 'w',
|
||||
encoding='UTF-8') as f:
|
||||
f.writelines(newList_conversion_SinglePlayer(musicset['musics'][i]['notes'],
|
||||
musicset['musics'][i]['set']['ScoreboardName'],
|
||||
musicset['musics'][i]['set']['Instrument']))
|
||||
if musicset['mainset']['IsRepeat']:
|
||||
log("增加重复语句")
|
||||
for i in range(len(musicset['musics'])):
|
||||
commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
musicset['musics'][i]['set']['ScoreboardName'] + "=" + str(
|
||||
(maxlen + 2) * 10) + "}] ~~~ scoreboard players set @e[name=\"" + musicset['musics'][i]['set'][
|
||||
'EntityName'] + "\"] " + musicset['musics'][i]['set']['ScoreboardName'] + " -1\n")
|
||||
log("增加版权语句")
|
||||
commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿),bgArray(诸葛亮与八卦阵)\n")
|
||||
starts.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿),bgArray(诸葛亮与八卦阵)\n")
|
||||
log("写入支持文件")
|
||||
with open(path + musicset['mainset']['MusicTitle'] + '_Support.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(commands)
|
||||
log("写入开始文件")
|
||||
with open(path + 'Start_' + musicset['mainset']['MusicTitle'] + '.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(starts)
|
||||
del commands, starts, maxlen
|
||||
log("完成============================")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def makeNewFunDir(musicset, path='./'):
|
||||
"""在指定目录下生成函数包文件夹"""
|
||||
import os
|
||||
import uuid
|
||||
log("=============================生成函数包文件夹")
|
||||
# note,packname="Ryoun",FileName="Music",EntityName_='music_support',ScoreboardName_='music_support',
|
||||
# MusicTitle_='Noname',PlayerSelect_='',Repeat_=False,Instrument_='harp'
|
||||
try:
|
||||
os.makedirs(path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions")
|
||||
log("已创建目录" + path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions")
|
||||
except FileExistsError:
|
||||
log("目录已有无需创建")
|
||||
pass
|
||||
# 判断文件皆存在
|
||||
if not (os.path.exists(
|
||||
path + musicset['mainset']['PackName'] + "Pack/world_behavior_packs.json") and os.path.exists(
|
||||
path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/manifest.json")):
|
||||
log("创建manifest.json以及world_behavior_packs.json")
|
||||
behaviorUuid = uuid.uuid4()
|
||||
with open(path + musicset['mainset']['PackName'] + "Pack/world_behavior_packs.json", "w") as f:
|
||||
f.write("[\n {\"pack_id\": \"" + str(behaviorUuid) + "\",\n \"version\": [ 0, 0, 1 ]}\n]")
|
||||
p = path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset']['PackName'] + \
|
||||
"/manifest.json"
|
||||
with open(p, "w") as f:
|
||||
f.write("{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" + musicset['mainset'][
|
||||
'PackName'] + " Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" +
|
||||
musicset['mainset']['PackName'] + "Pack\",\n \"uuid\": \"" + str(
|
||||
behaviorUuid) + "\"\n },\n \"modules\": [\n {\n \"description\": \"" + musicset['mainset'][
|
||||
'PackName'] + " Pack : behavior pack\",\n \"type\": \"data\",\n \"version\":"
|
||||
" [ 0, 0, 1 ],\n \"uuid\": \"" + str(
|
||||
uuid.uuid4()) + "\"\n }\n ]\n}")
|
||||
makeNewFuncFiles(musicset, path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions/")
|
||||
log("完成============================")
|
||||
|
||||
|
||||
def makeClassFuncFiles(musicset, path='./'):
|
||||
"""在指定目录下生成函数文件"""
|
||||
from msctspt.transfer import classList_conversion_SinglePlayer
|
||||
commands = []
|
||||
starts = []
|
||||
starts.__len__()
|
||||
starts.append("scoreboard objectives add " + musicset['musics'][0]['set']['ScoreboardName'] + " dummy\n")
|
||||
starts.append("summon armor_stand " + musicset['musics'][0]['set']['EntityName'] + '\n')
|
||||
starts.append("scoreboard objectives setdisplay sidebar " + musicset['musics'][0]['set']['ScoreboardName'] + '\n')
|
||||
starts.append("scoreboard players set @e[type=armor_stand, name=\"" + musicset['musics'][0]['set']['EntityName'] +
|
||||
"\"] " + musicset['musics'][0]['set']['ScoreboardName'] + " 0" + '\n')
|
||||
log("=========================正在在此处生成文件:" + path)
|
||||
commands.append("scoreboard players add @e[name=\"" + musicset['musics'][0]['set']['EntityName'] + "\"] " +
|
||||
musicset['musics'][0]['set']['ScoreboardName'] + " 1\n")
|
||||
maxlen = -1
|
||||
for i in range(len(musicset['musics'])):
|
||||
log('写入第' + str(i) + '个数据')
|
||||
# commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
# musicset['musics'][i]['set']['ScoreboardName'] + "=1..10}] ~~~ title @a" + musicset['mainset']
|
||||
# [
|
||||
# 'PlayerSelect'] + " title " + musicset['mainset']['MusicTitle'] + "\n")
|
||||
# commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
# musicset['musics'][i]['set']['ScoreboardName'] + "=1..10}] ~~~ title @a" + musicset['mainset']
|
||||
# [
|
||||
# 'PlayerSelect'] + " subtitle 本函数乐曲由§b§l凌云§r§3函数音乐创建§r生成\n")
|
||||
if len(musicset['musics'][i]['notes']) > maxlen:
|
||||
maxlen = len(musicset['musics'][i]['notes'])
|
||||
with open(path + musicset['mainset']['MusicTitle'] + '_Part' + str(i) + '.mcfunction', 'w',
|
||||
encoding='UTF-8') as f:
|
||||
f.writelines(classList_conversion_SinglePlayer(musicset['musics'][i]['notes'],
|
||||
musicset['musics'][i]['set']['ScoreboardName'],
|
||||
musicset['mainset']['PlayerSelect'],
|
||||
True))
|
||||
if musicset['mainset']['IsRepeat']:
|
||||
log("增加重复语句")
|
||||
for i in range(len(musicset['musics'])):
|
||||
commands.append("execute @e[name=\"" + musicset['musics'][i]['set']['EntityName'] + "\",scores={" +
|
||||
musicset['musics'][i]['set']['ScoreboardName'] + "=" + str(
|
||||
(maxlen + 2) * 10) + "}] ~~~ scoreboard players set @e[name=\"" + musicset['musics'][i]['set'][
|
||||
'EntityName'] + "\"] " + musicset['musics'][i]['set']['ScoreboardName'] + " -1\n")
|
||||
log("增加版权语句")
|
||||
commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿),bgArray(诸葛亮与八卦阵)\n")
|
||||
starts.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿),bgArray(诸葛亮与八卦阵)\n")
|
||||
log("写入支持文件")
|
||||
with open(path + musicset['mainset']['MusicTitle'] + '_Support.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(commands)
|
||||
log("写入开始文件")
|
||||
with open(path + 'Start_' + musicset['mainset']['MusicTitle'] + '.mcfunction', 'w', encoding='UTF-8') as f:
|
||||
f.writelines(starts)
|
||||
del commands, starts, maxlen
|
||||
log("完成============================")
|
||||
|
||||
|
||||
def makeClassFunDir(musicset, path='./'):
|
||||
"""在指定目录下生成函数包文件夹"""
|
||||
import os
|
||||
import uuid
|
||||
log("=============================生成函数包文件夹")
|
||||
# note,packname="Ryoun",FileName="Music",EntityName_='music_support',ScoreboardName_='music_support',
|
||||
# MusicTitle_='Noname',PlayerSelect_='',Repeat_=False,Instrument_='harp'
|
||||
try:
|
||||
os.makedirs(path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions")
|
||||
log("已创建目录" + path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions")
|
||||
except FileExistsError:
|
||||
log("目录已有无需创建")
|
||||
pass
|
||||
# 判断文件皆存在
|
||||
if not (os.path.exists(
|
||||
path + musicset['mainset']['PackName'] + "Pack/world_behavior_packs.json") and os.path.exists(
|
||||
path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/manifest.json")):
|
||||
log("创建manifest.json以及world_behavior_packs.json")
|
||||
behaviorUuid = uuid.uuid4()
|
||||
with open(path + musicset['mainset']['PackName'] + "Pack/world_behavior_packs.json", "w") as f:
|
||||
f.write("[\n {\"pack_id\": \"" + str(behaviorUuid) + "\",\n \"version\": [ 0, 0, 1 ]}\n]")
|
||||
p = path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset']['PackName'] + \
|
||||
"/manifest.json"
|
||||
with open(p, "w") as f:
|
||||
f.write("{\n \"format_version\": 1,\n \"header\": {\n \"description\": \"" + musicset['mainset'][
|
||||
'PackName'] + " Pack : behavior pack\",\n \"version\": [ 0, 0, 1 ],\n \"name\": \"" +
|
||||
musicset['mainset']['PackName'] + "Pack\",\n \"uuid\": \"" + str(
|
||||
behaviorUuid) + "\"\n },\n \"modules\": [\n {\n \"description\": \"" + musicset['mainset'][
|
||||
'PackName'] + " Pack : behavior pack\",\n \"type\": \"data\",\n \"version\":"
|
||||
" [ 0, 0, 1 ],\n \"uuid\": \"" + str(
|
||||
uuid.uuid4()) + "\"\n }\n ]\n}")
|
||||
makeClassFuncFiles(musicset, path + musicset['mainset']['PackName'] + "Pack/behavior_packs/" + musicset['mainset'][
|
||||
'PackName'] + "/functions/")
|
||||
log("完成============================")
|
||||
|
||||
|
||||
"""
|
||||
这里是往事,用于记载一些用不到的功能
|
||||
|
||||
#存在于 Musicreater.py 播放(试听)音乐
|
||||
def PlayNote(Notes, t=480): # Notes是音符列表,t是一拍占有的毫秒数
|
||||
tkinter.messagebox.showinfo(title='提示!', message="播放发音不一定标准\n说不定还会坏音响/(ㄒoㄒ)/~~qwq\n请注意。")
|
||||
import winsound
|
||||
import time
|
||||
from nmcsup.trans import mcnote2freq
|
||||
Notes = mcnote2freq(Notes)
|
||||
for frequency, duration in Notes:
|
||||
log("播放:"+str([int(frequency), int(duration*t)]))
|
||||
if int(frequency) != 0:
|
||||
winsound.Beep(int(frequency), int(duration*t))
|
||||
elif int(frequency) == 0:
|
||||
time.sleep(duration*t/1000)
|
||||
|
||||
#同上,执行播放命令
|
||||
def PlayOne():
|
||||
log("试听")
|
||||
tkinter.messagebox.showwarning(title="警告⚠", message="试听音质可能引起您的不适,更可能引起您的扬声器的不适,请酌情播放。")
|
||||
global NowMusic
|
||||
PlayNote(dataset[0]['musics'][NowMusic]['notes'])
|
||||
|
||||
|
||||
|
||||
#同上,是早期 MinecraftMusicFunctionMaker.py (函数音创)的代码转移至音·创时的注解
|
||||
n2c(dataset[0]['musics'][i]['notes'],EntityName=dataset[0]['musics'][i]['set']['EntityName'],ScoreboardName=dataset[0]['
|
||||
musics'][i]['set']['ScoreboardName'],PlayerSelect=dataset[0]['mainset']['PlayerSelect'],Instrument=dataset[0]['musics']
|
||||
i]['set']["Instrument"])
|
||||
|
||||
|
||||
"""
|
@ -1,27 +0,0 @@
|
||||
|
||||
|
||||
|
||||
import threading
|
||||
|
||||
|
||||
class NewThread(threading.Thread):
|
||||
'''新建一个进程来运行函数,函数运行完毕后可以使用.getResult方法获取其返回值'''
|
||||
def __init__(self, func, args=()):
|
||||
super(NewThread, self).__init__()
|
||||
self.func = func
|
||||
self.args = args
|
||||
self.result = None
|
||||
|
||||
def run(self):
|
||||
self.result = self.func(*self.args)
|
||||
|
||||
def getResult(self):
|
||||
threading.Thread.join(self) # 等待线程执行完毕
|
||||
return self.result
|
||||
|
||||
#
|
||||
# ————————————————
|
||||
# 版权声明:上面的类NewThread修改自CSDN博主「星火燎愿」的原创文章中的内容,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
|
||||
# 原文链接:https://blog.csdn.net/xpt211314/article/details/109543014
|
||||
# ————————————————
|
||||
#
|
@ -1,577 +0,0 @@
|
||||
"""音·创 的转换工具库"""
|
||||
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:4个--未解决1个;语法(一级)错误:302个
|
||||
|
||||
|
||||
# 可序列化对象,即可迭代对象
|
||||
from typing import Iterable
|
||||
|
||||
import amulet
|
||||
|
||||
from amulet.api.block import Block
|
||||
from amulet.utils.world_utils import block_coords_to_chunk_coords as bc2cc
|
||||
from amulet_nbt import TAG_String as ts
|
||||
from msctLib.log import log
|
||||
|
||||
|
||||
def hans2pinyin(hans, style=3):
|
||||
"""将汉字字符串转化为拼音字符串"""
|
||||
from pypinyin import lazy_pinyin
|
||||
result = lazy_pinyin(hans=hans, style=style)
|
||||
final = ''
|
||||
for i in result:
|
||||
final += i
|
||||
return final
|
||||
|
||||
|
||||
def classList_conversion_SinglePlayer(List: list, ScoreboardName: str, playerSelection: str = '',
|
||||
isProsess: bool = False) -> list:
|
||||
from bgArrayLib.compute import round_up
|
||||
from bgArrayLib.pitchStrConstant import pitch
|
||||
from bgArrayLib.instrumentConstant import instrument_list
|
||||
commands = []
|
||||
length = len(List)
|
||||
j = 1
|
||||
for k in range(len(List)):
|
||||
i = List[k][0]
|
||||
try:
|
||||
commands.append(
|
||||
f"execute @a{playerSelection} ~ ~ ~ execute @s[scores={{{ScoreboardName}="
|
||||
f"{str(round_up(i.time_position)).replace('.0', '')}}}] ~ ~{127 - i.velocity} "
|
||||
f"~ playsound note.{instrument_list.get(str(i.instrument))} @s ~ ~ ~ "
|
||||
f"1000 {pitch.get(str(i.pitch))} 1000\n")
|
||||
if isProsess:
|
||||
commands.append(
|
||||
f"execute @a{playerSelection} ~ ~ ~ execute @s[scores={{{ScoreboardName}="
|
||||
f"{str(round_up(i.time_position)).replace('.0', '')}}}] ~ ~ ~ "
|
||||
f"title @s actionbar §e▶ 播放中: §a{j}/{length} || {int(j / length * 1000) / 10}\n")
|
||||
j += 1
|
||||
except Exception:
|
||||
pass
|
||||
# a += List[i][1]
|
||||
# commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
return commands
|
||||
|
||||
|
||||
def newList_conversion_SinglePlayer(List: list, ScoreboardName: str, playerSelection: str = '',
|
||||
isProsess: bool = False) -> list:
|
||||
from bgArrayLib.compute import round_up
|
||||
commands = []
|
||||
length = len(List)
|
||||
j = 1
|
||||
print(List)
|
||||
for k in range(len(List)):
|
||||
i = List[k][0]
|
||||
print(i)
|
||||
print(type(i))
|
||||
try:
|
||||
if i.instrument > 119:
|
||||
pass
|
||||
else:
|
||||
commands.append(
|
||||
f"execute @a{playerSelection} ~ ~ ~ execute @s[scores={{{ScoreboardName}="
|
||||
f"{str(round_up(i.time_position)).replace('.0', '')}}}] ~ ~{127 - i.velocity} "
|
||||
f"~ playsound {i.instrument}{i.CD}.{i.pitch} @s ~ ~ ~ 1000 1.0 1000\n")
|
||||
if isProsess:
|
||||
commands.append(
|
||||
f"execute @a{playerSelection} ~ ~ ~ execute @s[scores={{{ScoreboardName}="
|
||||
f"{str(round_up(i.time_position)).replace('.0', '')}}}] ~ ~ ~ "
|
||||
f"title @s actionbar §e▶ 播放中: §a{j}/{length} || {int(j / length * 1000) / 10}\n")
|
||||
j += 1
|
||||
except:
|
||||
pass
|
||||
# a += List[i][1]
|
||||
# commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
print(commands)
|
||||
return commands
|
||||
|
||||
|
||||
def classList_conversion(List: list, ScoreboardName: str, isProsess: bool = False) -> list:
|
||||
from bgArrayLib.compute import round_up
|
||||
commands = []
|
||||
length = len(List)
|
||||
j = 1
|
||||
print(List)
|
||||
for k in range(len(List)):
|
||||
i = List[k][0]
|
||||
print(i)
|
||||
print(type(i))
|
||||
try:
|
||||
if i.instrument > 119:
|
||||
pass
|
||||
else:
|
||||
commands.append("execute @e[scores={" +
|
||||
ScoreboardName + "=" + str(round_up(i.time_position)).replace(".0", "") + "}] ~ ~" +
|
||||
str(127 - i.velocity) +
|
||||
" ~ playsound " +
|
||||
str(i.instrument) +
|
||||
str(i.CD) + "." +
|
||||
str(i.pitch)
|
||||
+ " @a ~ ~ ~ 1000 1.0 1000\n")
|
||||
if isProsess:
|
||||
commands.append("execute @a"" ~ ~ ~ execute @s[scores={" + ScoreboardName + "=" +
|
||||
str(round_up(i.time_position)).replace(".0", "") +
|
||||
"}] ~ ~ ~ title @s actionbar §e▶ 播放中: §a" +
|
||||
str(j) + "/" + str(length) + " || " + str(int(j / length * 1000) / 10) + "\n")
|
||||
j += 1
|
||||
except AttributeError:
|
||||
pass
|
||||
# a += List[i][1]
|
||||
# commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
print(commands)
|
||||
return commands
|
||||
|
||||
|
||||
def formCmdBlock(direction: Iterable, command: str, particularValue: int, impluse: int = 0, condition: bool = False,
|
||||
needRedstone: bool = True, tickDelay: int = 0, customName: str = '', lastOutput: str = '',
|
||||
executeOnFirstTick: bool = False, trackOutput: bool = True):
|
||||
"""
|
||||
使用指定项目返回指定的指令方块格式字典
|
||||
:param direction: `list[x: int, y: int, z: int]`
|
||||
方块位置
|
||||
:param command: `str`
|
||||
指令
|
||||
:param particularValue:
|
||||
方块特殊值,即朝向
|
||||
:0 下 无条件
|
||||
:1 上 无条件
|
||||
:2 z轴负方向 无条件
|
||||
:3 z轴正方向 无条件
|
||||
:4 x轴负方向 无条件
|
||||
:5 x轴正方向 无条件
|
||||
:6 下 无条件
|
||||
:7 下 无条件
|
||||
|
||||
:8 下 有条件
|
||||
:9 上 有条件
|
||||
:10 z轴负方向 有条件
|
||||
:11 z轴正方向 有条件
|
||||
:12 x轴负方向 有条件
|
||||
:13 x轴正方向 有条件
|
||||
:14 下 有条件
|
||||
:14 下 有条件
|
||||
注意!此处特殊值中的条件会被下面condition参数覆写
|
||||
:param impluse: `int 0|1|2`
|
||||
方块类型
|
||||
0脉冲 1循环 2连锁
|
||||
:param condition: `bool`
|
||||
是否有条件
|
||||
:param needRedstone: `bool`
|
||||
是否需要红石
|
||||
:param tickDelay: `int`
|
||||
执行延时
|
||||
:param customName: `str`
|
||||
悬浮字
|
||||
:param lastOutput: `str`
|
||||
上次输出字符串,注意此处需要留空
|
||||
:param executeOnFirstTick: `bool`
|
||||
执行第一个已选项(循环指令方块是否激活后立即执行,若为False,则从激活时起延迟后第一次执行)
|
||||
:param trackOutput: `bool`
|
||||
是否输出
|
||||
|
||||
:return: 指令方块字典结构,如下
|
||||
"""
|
||||
'''
|
||||
:param block: {
|
||||
"direction": [x: int, y: int, z: int] #方块位置
|
||||
"block_name": str, #方块名称(无需指定,默认为command_block)
|
||||
"particular_value": int, #方块特殊值
|
||||
"impluse": int, #方块类型0脉冲 1循环 2连锁 unsigned_int32
|
||||
"command": str, #指令
|
||||
"customName": str, #悬浮字
|
||||
"lastOutput": str, #上次输出
|
||||
"tickdelay": int, #方块延时 int32
|
||||
"executeOnFirstTick": int, #执行第一个选项 1 bytes
|
||||
"trackOutput": int, #是否输出 1 bytes
|
||||
"conditional": int, #是否有条件 1 bytes
|
||||
"needRedstone": int #是否需要红石 1 bytes
|
||||
}
|
||||
'''
|
||||
# for particularValue, is like this
|
||||
# :0 下 无条件
|
||||
# :1 上 无条件
|
||||
# :2 z轴负方向 无条件
|
||||
# :3 z轴正方向 无条件
|
||||
# :4 x轴负方向 无条件
|
||||
# :5 x轴正方向 无条件
|
||||
print(f"==[DEBUG]=={direction}: {command} {'下' if particularValue == 0 else '上' if particularValue ==1 else 'z-' if particularValue ==2 else 'z+' if particularValue==3 else 'x-' if particularValue==4 else 'x+'} {'脉冲' if impluse==0 else '循环' if impluse ==1 else '连锁'} {'有条件' if condition else '无条件'} {'需要红石' if needRedstone else '不需要红石'}")
|
||||
return {"direction": direction,
|
||||
"block_name": "command_block",
|
||||
"particular_value": particularValue,
|
||||
"impluse": impluse,
|
||||
"command": command,
|
||||
"customName": customName,
|
||||
"lastOutput": lastOutput,
|
||||
"tickdelay": tickDelay,
|
||||
"executeOnFirstTick": executeOnFirstTick,
|
||||
"trackOutput": trackOutput,
|
||||
"conditional": condition,
|
||||
"needRedstone": needRedstone
|
||||
}
|
||||
|
||||
|
||||
def note2bdx(filePath: str, dire: list, Notes: list, ScoreboardName: str, Instrument: str,
|
||||
PlayerSelect: str = '', isProsess: bool = False, height: int = 200):
|
||||
"""使用方法同Note2Cmd
|
||||
:param 参数说明:
|
||||
filePath: 生成.bdx文件的位置
|
||||
dire: 指令方块在地图中生成的起始位置(相对位置)
|
||||
Notes: 以 list[ list[ float我的世界playsound指令音调 , float延续时常(单位s) ] ] 格式存储的音符列表
|
||||
例如Musicreater.py的(dataset[0]['musics'][NowMusic]['notes'])
|
||||
ScoreboardName: 用于执行的计分板名称
|
||||
Instrument: 播放的乐器
|
||||
PlayerSelect: 执行的玩家选择器
|
||||
isProsess: 是否显示进度条(会很卡)
|
||||
height: 生成结构的最高高度
|
||||
:return 返回一个BdxConverter类,同时在指定位置生成.bdx文件"""
|
||||
|
||||
from nmcsup.trans import Note2Cmd
|
||||
from msctspt.bdxOpera_CP import BdxConverter
|
||||
cmd = Note2Cmd(Notes, ScoreboardName, Instrument, PlayerSelect, isProsess)
|
||||
cdl = []
|
||||
|
||||
for i in cmd:
|
||||
if '#' in i:
|
||||
if (i[:i.index('#')].replace(' ', '') != '\n') and (i[:i.index('#')].replace(' ', '') != ''):
|
||||
cdl.append(i[:i.index('#')])
|
||||
else:
|
||||
cdl.append(i)
|
||||
i = 0
|
||||
down = False
|
||||
blocks = [formCmdBlock(dire, cdl.pop(0), 1, 1)]
|
||||
dire[1] += 1
|
||||
for j in cdl:
|
||||
if dire[1] + i > height:
|
||||
dire[0] += 1
|
||||
i = 0
|
||||
down = not down
|
||||
if dire[1] + i == height:
|
||||
blocks.append(formCmdBlock([dire[0], dire[1] + i, dire[2]], j, 5, 2, False, False))
|
||||
else:
|
||||
if down:
|
||||
blocks.append(formCmdBlock([dire[0], dire[1] + i, dire[2]], j, 0, 2, False, False))
|
||||
else:
|
||||
blocks.append(formCmdBlock([dire[0], dire[1] + i, dire[2]], j, 1, 2, False, False))
|
||||
i += 1
|
||||
del i, cdl, down, cmd
|
||||
return BdxConverter(filePath, 'Build by RyounMusicreater', blocks)
|
||||
|
||||
|
||||
|
||||
def music2cmdBlocks(direction: Iterable, music: dict, isProsess: bool = False, height: int = 200,
|
||||
isSquare: bool = False):
|
||||
"""使用方法同Note2Cmd
|
||||
:param 参数说明:
|
||||
filePath: 生成.bdx文件的位置
|
||||
dire: 指令方块在地图中生成的起始位置(相对位置)
|
||||
music: 详见 Musicreater.py - dataset[0]
|
||||
isProsess: 是否显示进度条(会很卡)
|
||||
height: 生成结构的最高高度
|
||||
isSquare: 生成的结构是否需要遵循生成正方形原则
|
||||
:return 返回一个列表,其中包含了音乐生成的所有的指令方块数据"""
|
||||
from msctspt.threadOpera import NewThread
|
||||
|
||||
|
||||
allblocks = []
|
||||
'''需要放置的方块'''
|
||||
baseDire = direction
|
||||
|
||||
direction = list(direction)
|
||||
|
||||
def trackDealing(direction,track):
|
||||
# print('=========DEBUG=========音轨起方块:', direction)
|
||||
blocks = []
|
||||
cmdList = classList_conversion_SinglePlayer(track['notes'], track['set']['ScoreboardName'],
|
||||
music['mainset']['PlayerSelect'], isProsess)
|
||||
if len(cmdList) == 0:
|
||||
return []
|
||||
elif cmdList is []:
|
||||
return []
|
||||
dire = direction.copy()
|
||||
down = False
|
||||
'''当前是否为向下的阶段?'''
|
||||
# 开头的指令方块
|
||||
blocks.append(formCmdBlock(dire,
|
||||
f"scoreboard players add @a{music['mainset']['PlayerSelect']} "
|
||||
f"{track['set']['ScoreboardName']} 1",
|
||||
1, 1))
|
||||
dire[1] += 1
|
||||
blocks.append(formCmdBlock(dire, cmdList.pop(0), 2, needRedstone=False))
|
||||
dire[1] += 1
|
||||
# :0 下 无条件
|
||||
# :1 上 无条件
|
||||
# :2 z轴负方向 无条件
|
||||
# :3 z轴正方向 无条件
|
||||
# :4 x轴负方向 无条件
|
||||
# :5 x轴正方向 无条件
|
||||
for cmd in cmdList:
|
||||
# print('=========DEBUG=========方块:', dire)
|
||||
blocks.append(formCmdBlock(dire, cmd, 5 if (down is False and dire[1] == height + direction[1]) or (
|
||||
down and dire[1] == direction[1] + 1) else 0 if down else 1, 2, needRedstone=False))
|
||||
if down:
|
||||
if dire[1] > direction[1] + 1:
|
||||
dire[1] -= 1
|
||||
else:
|
||||
if dire[1] < height + direction[1]:
|
||||
dire[1] += 1
|
||||
|
||||
if (down is False and dire[1] == height + direction[1]) or (down and dire[1] == direction[1] + 1):
|
||||
down = not down
|
||||
dire[0] += 1
|
||||
return blocks
|
||||
|
||||
threads = []
|
||||
for track in music['musics']:
|
||||
threads.append(NewThread(trackDealing,(direction.copy(),track)))
|
||||
threads[-1].start()
|
||||
direction[2] += 2
|
||||
|
||||
for th in threads:
|
||||
allblocks += th.getResult()
|
||||
|
||||
print(allblocks)
|
||||
return allblocks
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def music2BDX(filePath: str, direction: Iterable, music: dict, isProsess: bool = False, height: int = 200,
|
||||
isSquare: bool = False):
|
||||
"""使用方法同Note2Cmd
|
||||
:param 参数说明:
|
||||
filePath: 生成.bdx文件的位置
|
||||
dire: 指令方块在地图中生成的起始位置(相对位置)
|
||||
music: 详见 Musicreater.py - dataset[0]
|
||||
isProsess: 是否显示进度条(会很卡)
|
||||
height: 生成结构的最高高度
|
||||
isSquare: 生成的结构是否需要遵循生成正方形原则
|
||||
:return 返回一个BdxConverter类,同时在指定位置生成.bdx文件"""
|
||||
from msctspt.bdxOpera_CP import BdxConverter
|
||||
return BdxConverter(filePath, 'Build by Ryoun Musicreater', music2cmdBlocks(direction,music,isProsess,height,isSquare)
|
||||
)
|
||||
|
||||
|
||||
def note2webs(Notes: list, Instrument: str, speed: float = 5.0, PlayerSelect: str = '', isProsess: bool = False):
|
||||
"""传入音符,在oaclhost:8080上建立websocket服务器以供我的世界connect/wssever指令连接
|
||||
:param 参数说明:
|
||||
Notes: 以 list[ list[ float我的世界playsound指令音调 , float延续时常(单位s) ] ] 格式存储的音符列表
|
||||
例如Musicreater.py的(dataset[0]['musics'][NowMusic]['notes'])
|
||||
Instrument: 播放的乐器
|
||||
speed: 用于控制播放速度,数值越大,播放速度越快,相当于把一秒变为几拍
|
||||
PlayerSelect: 执行的玩家选择器
|
||||
isProsess: 是否显示进度条
|
||||
:return None"""
|
||||
|
||||
import time
|
||||
import fcwslib
|
||||
# import asyncio
|
||||
from nmcsup.log import log
|
||||
from nmcsup.vers import VER
|
||||
|
||||
async def run_server(websocket): # , path
|
||||
log('服务器连接创建')
|
||||
await fcwslib.tellraw(websocket, '已连接服务器——音·创' + VER[1] + VER[0] + ' 作者:金羿(W-YI)')
|
||||
length = len(Notes)
|
||||
j = 1
|
||||
for i in range(len(Notes)):
|
||||
await fcwslib.send_command(websocket,
|
||||
f'execute @a{PlayerSelect} ~ ~ ~ playsound {Instrument} @s ~ ~ ~ 1000 '
|
||||
f'{Notes[i][0]} 1000')
|
||||
if isProsess:
|
||||
await fcwslib.send_command(websocket,
|
||||
'execute @a' + PlayerSelect + ' ~ ~ ~ title @s actionbar §e▶ 播放中: §a' +
|
||||
str(
|
||||
j) + '/' + str(length) + ' || ' + str(int(j / length * 1000) / 10))
|
||||
j += 1
|
||||
time.sleep(Notes[i][1] / speed)
|
||||
|
||||
fcwslib.run_server(run_server)
|
||||
|
||||
|
||||
def note2RSworld(world: str, startpos: list, notes: list, instrument: str, speed: float = 2.5,
|
||||
posadder: Iterable = (1, 0, 0), baseblock: str = 'stone'): # -> bool
|
||||
"""传入音符,生成以音符盒存储的红石音乐
|
||||
:param 参数说明:
|
||||
world: 地图文件的路径
|
||||
startpos: list[int,int,int] 开始生成的坐标
|
||||
notes: list[list[float,float]] 以 list[ list[ float我的世界playsound指令音调 , float延续时常(单位s) ] ]
|
||||
格式存储的音符列表 例如Musicreater.py的dataset[0]['musics'][NowMusic]['notes']
|
||||
instrument: 播放的乐器
|
||||
speed: 一拍占多少个中继器延迟(红石刻/rt)
|
||||
posadder: list[int,int,int] 坐标增加规律,即红石的延长时按照此增加规律增加坐标
|
||||
baseblock: 在中继器下垫着啥方块呢~
|
||||
:return 是否生成成功
|
||||
"""
|
||||
|
||||
from msctspt.values import height2note, instuments
|
||||
|
||||
def formNoteBlock(note: int, instrument1: str = 'note.harp', powered: bool = False):
|
||||
"""生成音符盒方块
|
||||
:param powered:
|
||||
:param instrument1:
|
||||
:param note: 0~24
|
||||
:return Block()"""
|
||||
if powered:
|
||||
powered = 'true'
|
||||
else:
|
||||
powered = 'false'
|
||||
return Block('universal_minecraft', 'notebooks',
|
||||
{"instrument": ts(instrument1.replace("note.", '')), 'note': ts(str(note)),
|
||||
'powered': ts(powered)})
|
||||
|
||||
def formRepeater(delay: int, facing: str, locked: bool = False, powered: bool = False):
|
||||
"""生成中继器方块
|
||||
:param powered:
|
||||
:param locked:
|
||||
:param facing:
|
||||
:param delay: 1~4
|
||||
:return Block()"""
|
||||
if powered:
|
||||
powered = 'true'
|
||||
else:
|
||||
powered = 'false'
|
||||
if locked:
|
||||
locked = 'true'
|
||||
else:
|
||||
locked = 'false'
|
||||
return Block('universal_minecraft', 'repeater',
|
||||
{"delay": ts(str(delay)), 'facing': ts(facing), 'locked': ts(locked), 'powered': ts(powered)})
|
||||
|
||||
level = amulet.load_level(world)
|
||||
|
||||
def setblock(block: Block, pos: list):
|
||||
"""pos : list[int,int,int]"""
|
||||
cx, cz = bc2cc(pos[0], pos[2])
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = pos[0] - 16 * cx, pos[2] - 16 * cz
|
||||
chunk.blocks[offset_x, pos[1], offset_z] = level.block_palette.get_add_block(block)
|
||||
chunk.changed = True
|
||||
|
||||
# 1拍 x 2.5 rt
|
||||
def placeNoteBlock():
|
||||
for i in notes:
|
||||
error = True
|
||||
try:
|
||||
setblock(formNoteBlock(height2note[i[0]], instrument), [startpos[0], startpos[1] + 1, startpos[2]])
|
||||
setblock(Block("universal_minecraft", instuments[i[0]][1]), startpos)
|
||||
error = False
|
||||
except ValueError:
|
||||
log("无法放置音符:" + str(i) + '于' + str(startpos))
|
||||
setblock(Block("universal_minecraft", baseblock), startpos)
|
||||
setblock(Block("universal_minecraft", baseblock), [startpos[0], startpos[1] + 1, startpos[2]])
|
||||
finally:
|
||||
if error is True:
|
||||
log("无法放置音符:" + str(i) + '于' + str(startpos))
|
||||
setblock(Block("universal_minecraft", baseblock), startpos)
|
||||
setblock(Block("universal_minecraft", baseblock), [startpos[0], startpos[1] + 1, startpos[2]])
|
||||
delay = int(i[1] * speed + 0.5)
|
||||
if delay <= 4:
|
||||
startpos[0] += 1
|
||||
setblock(formRepeater(delay, 'west'), [startpos[0], startpos[1] + 1, startpos[2]])
|
||||
setblock(Block("universal_minecraft", baseblock), startpos)
|
||||
else:
|
||||
for j in range(int(delay / 4)):
|
||||
startpos[0] += 1
|
||||
setblock(formRepeater(4, 'west'), [startpos[0], startpos[1] + 1, startpos[2]])
|
||||
setblock(Block("universal_minecraft", baseblock), startpos)
|
||||
if delay % 4 != 0:
|
||||
startpos[0] += 1
|
||||
setblock(formRepeater(delay % 4, 'west'), [startpos[0], startpos[1] + 1, startpos[2]])
|
||||
setblock(Block("universal_minecraft", baseblock), startpos)
|
||||
startpos[0] += posadder[0]
|
||||
startpos[1] += posadder[1]
|
||||
startpos[2] += posadder[2]
|
||||
|
||||
# e = True
|
||||
try:
|
||||
placeNoteBlock()
|
||||
# e = False
|
||||
except: # ValueError
|
||||
log("无法放置方块了,可能是因为区块未加载叭")
|
||||
# finally:
|
||||
# if e:
|
||||
# log("无法放置方块了,可能是因为区块未加载叭")
|
||||
level.save()
|
||||
level.close()
|
||||
|
||||
|
||||
class ryStruct:
|
||||
|
||||
def __init__(self, world: str) -> None:
|
||||
|
||||
self.RyStruct = dict()
|
||||
self._world = world
|
||||
self._level = amulet.load_level(world)
|
||||
|
||||
def reloadLevel(self):
|
||||
# e = True
|
||||
try:
|
||||
self._level = amulet.load_level(self.world)
|
||||
# e = False
|
||||
except: # ValueError
|
||||
log("无法重载地图")
|
||||
# finally:
|
||||
# if e:
|
||||
# log("无法重载地图")
|
||||
|
||||
def closeLevel(self):
|
||||
# e = True
|
||||
try:
|
||||
self._level.close()
|
||||
# e = False
|
||||
except: # ValueError
|
||||
log("无法关闭地图")
|
||||
# finally:
|
||||
# if e:
|
||||
# log("无法重载地图")
|
||||
|
||||
def world2Rys(self, startp: list, endp: list, includeAir: bool = False):
|
||||
"""将世界转换为RyStruct字典,注意,此函数运行成功后将关闭地图,若要打开需要运行 reloadLevel
|
||||
:param startp: [x,y,z] 转化的起始坐标
|
||||
:param endp : [x,y,z] 转换的终止坐标,注意,终止坐标需要大于起始坐标,且最终结果包含终止坐标
|
||||
:param includeAir : bool = False 是否包含空气,即空气是否在生成之时覆盖地图内容
|
||||
:return dict RyStruct """
|
||||
|
||||
level = self._level
|
||||
|
||||
for x in range(startp[0], endp[0] + 1):
|
||||
for y in range(startp[1], endp[1] + 1):
|
||||
for z in range(startp[2], endp[2] + 1):
|
||||
|
||||
RyStructBlock = dict()
|
||||
|
||||
cx, cz = bc2cc(x, z)
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
universal_block = chunk.block_palette[chunk.blocks[x - 16 * cx, y, z - 16 * cz]]
|
||||
if universal_block == Block("universal_minecraft", "air") and includeAir:
|
||||
continue
|
||||
universal_block_entity = chunk.block_entities.get((x, y, z), None)
|
||||
|
||||
RyStructBlock["block"] = str(universal_block)
|
||||
RyStructBlock["blockEntity"] = str(universal_block_entity)
|
||||
|
||||
log("载入方块数据" + str(RyStructBlock))
|
||||
|
||||
self.RyStruct[(x, y, z)] = RyStructBlock
|
||||
|
||||
level.close()
|
||||
|
||||
return self.RyStruct
|
||||
|
||||
|
||||
"""
|
||||
RyStruct = {
|
||||
(0,0,0) = {
|
||||
"block": str 完整的方块结构
|
||||
"blockEntity": str | 'None'
|
||||
}
|
||||
}
|
||||
"""
|
@ -1,56 +0,0 @@
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:0个;语法(一级)错误:40个
|
||||
|
||||
instuments = {
|
||||
'note.banjo': ['班卓琴', 'hay_block'],
|
||||
'note.bass': ['贝斯', 'planks'],
|
||||
'note.bassattack': ['低音鼓/贝斯', 'log'],
|
||||
'note.bd': ['底鼓', 'stone'], # 即basedrum
|
||||
'note.bell': ['铃铛/钟琴', 'gold_block'],
|
||||
'note.bit': ['比特/“芯片”(方波)', 'emerald_block'],
|
||||
'note.chime': ['管钟', 'packed_ice'],
|
||||
'note.cow_bell': ['牛铃', 'soul_sand'],
|
||||
'note.didgeridoo': ['迪吉里杜管', 'pumpkin'],
|
||||
'note.flute': ['长笛', 'clay'],
|
||||
'note.guitar': ['吉他', 'wool'],
|
||||
'note.harp': ['竖琴/钢琴', 'concrete'], # 任意其他类型的方块皆可
|
||||
'note.hat': ['击鼓沿/架子鼓', 'glass'],
|
||||
'note.iron_xylophone': ['“铁木琴”(颤音琴)', 'iron_block'],
|
||||
'note.pling': ['“扣弦”(电钢琴)', 'glowstone'],
|
||||
'note.snare': ['小军鼓', 'sand'],
|
||||
'note.xylophone': ['木琴', 'bone_block']
|
||||
}
|
||||
'''乐器对照表\n
|
||||
乐器英文:[中文, 对应音符盒下方块名称]
|
||||
注:方块仅取一个'''
|
||||
|
||||
height2note = {
|
||||
0.5: 0,
|
||||
0.53: 1,
|
||||
0.56: 2,
|
||||
0.6: 3,
|
||||
0.63: 4,
|
||||
0.67: 5,
|
||||
0.7: 6,
|
||||
0.75: 7,
|
||||
0.8: 8,
|
||||
0.84: 9,
|
||||
0.9: 10,
|
||||
0.94: 11,
|
||||
1.0: 12,
|
||||
|
||||
1.05: 13,
|
||||
1.12: 14,
|
||||
1.2: 15,
|
||||
1.25: 16,
|
||||
1.33: 17,
|
||||
1.4: 18,
|
||||
1.5: 19,
|
||||
1.6: 20,
|
||||
1.7: 21,
|
||||
1.8: 22,
|
||||
1.9: 23,
|
||||
2.0: 24,
|
||||
}
|
||||
'''音高对照表\n
|
||||
MC音高:音符盒音调'''
|
Binary file not shown.
@ -1,62 +0,0 @@
|
||||
《我的世界》函数音乐生成器
|
||||
C++版本开发日志
|
||||
|
||||
我在本年初提出此计划,由于学业原因,便延迟计划开始编写代码。
|
||||
|
||||
Beta V0.1 - 20200920
|
||||
0.新增命令help
|
||||
1.新增命令make
|
||||
2.新增命令form
|
||||
3.新增命令exit
|
||||
4.能够根据输入的CDEFGAB转换成.mcfunction
|
||||
5.命令行界面操作
|
||||
|
||||
Beta V0.2 - 20200921
|
||||
0.修改命令make为write
|
||||
1.新增可设置代替实体名
|
||||
2.新增可设置计分板名
|
||||
3.新增乐曲标题设定项
|
||||
4.新增循环模式设定项
|
||||
5.由于"器"一字被网易屏蔽,修改程序名为"我的世界函数音乐生成者"
|
||||
|
||||
Beta V0.3 - 20200922
|
||||
0.修改命令write为make
|
||||
1.将代替实体名加入设定项
|
||||
2.将计分板名加入设定项
|
||||
3.将乐曲标题加入设定项
|
||||
|
||||
Beta V0.4 - 20200923
|
||||
0.新增生成文件名称设定项
|
||||
1.新增bug:最后三个音符的指令不写入文件(DE001)
|
||||
2.新增命令ver可显示版本及关于信息
|
||||
|
||||
Beta V0.5 - 20200925
|
||||
0.修改命令make为write
|
||||
1.新增设定项文件路径
|
||||
2.支持音符由简谱1234567音调表示
|
||||
3.支持休止符0
|
||||
|
||||
Beta V0.6 - 20200926
|
||||
0.修改命令write为make
|
||||
1.修复bug:最后三个音符的指令不写入文件(DE001)
|
||||
2.新增命令buld
|
||||
3.新增命令comd
|
||||
4.由help打开的帮助菜单由一页变为两页
|
||||
5.命令行窗口大小自动调整
|
||||
|
||||
Beta V0.7 - 20200927
|
||||
0.新增命令mdir,可以直接生成整个函数包
|
||||
1.新增命令ldir,可以查看当前目录信息
|
||||
3.新增指令look,可以显示指定文本文件内容
|
||||
4.删除退出时的等待按键提示
|
||||
5.新增bug:使用look查看文件结束后有几率卡崩或无法显示提示符">>>"(DE002、DE003)
|
||||
6.新增bug:mdir无法使用(DE004)
|
||||
|
||||
TO-DO Beta V0.8_中秋国庆版 - 20200929
|
||||
0.新增彩蛋命令国庆,在国庆期间输入可以得到一份中国国旗字符画
|
||||
1.新增彩蛋命令中秋,在中秋期间输入可以得到一份月亮字符画
|
||||
——此版本直接跳过
|
||||
|
||||
Beta V0.9 - 20201224
|
||||
0.修复bug:mdir无法使用(DE004)
|
||||
1.新增bug:mdir一运行立马产生错误并停止运行(DE005)
|
@ -1,126 +0,0 @@
|
||||
这是MMFM(我的世界函数音乐生成器)的Python版本日志
|
||||
我从2021年5月移植,中间停更了一段时间。
|
||||
|
||||
Beta V 0.0.0
|
||||
2021 5 ?15 - 2021 5 23
|
||||
1.将C++版本全部有用的功能移植至Python版本
|
||||
2.新增了可更改的音乐乐器
|
||||
3.新增了可更改的语言包Chinese
|
||||
4.附带应用"jsonread - lang"可用于新增语言文本
|
||||
5.支持全部音阶,但不支持附点、X分音符等
|
||||
|
||||
Beta V 0.0.1
|
||||
2021 6 5
|
||||
1.可读取不同的语言文件,通过lang指令完成
|
||||
2.新增English语言包
|
||||
3.在输入非内部指令时以命令行运行
|
||||
|
||||
Beta V 0.0.2
|
||||
2021 6 13
|
||||
1.支持设置项保存
|
||||
2.语言设置移至设置项中
|
||||
3.新增RESET命令以重置所有设置项至默认
|
||||
4.支持休止符(“0”)
|
||||
5.设置项更加人性化
|
||||
|
||||
Beta V 0.0.3
|
||||
2021 6 14
|
||||
1.支持全平台(能运行Python的平台)
|
||||
2.安卓系统下不需要从源地址运行
|
||||
3.设置中给出乐器列表并需要使用在列表内的乐器
|
||||
|
||||
Beta V 0.0.4
|
||||
2021 6 14
|
||||
1.新增win指令支持窗口化输入
|
||||
2.语言包English停止支持
|
||||
3.停止支持的语言包部分将使用Chinese语言包
|
||||
4.输出结果更加人性化
|
||||
5.停止支持输入非内部命令以系统指令运行
|
||||
|
||||
Formal V 0.0.1
|
||||
2021 6 21 - 2021 6 22
|
||||
1*.支持附点、延音等时间延长谱号
|
||||
2*.支持X分音符等时间缩短谱号
|
||||
3.删除win指令支持的窗口化输入,即禁止窗口运行
|
||||
4.新增日志系统,程序运行将载入日志以便检查
|
||||
*实际上输入的时候是不支持的,只是支持了修改音符延长时间而已
|
||||
|
||||
|
||||
Formal V 0.0.2
|
||||
2121 6 22
|
||||
1.解决了字符串解析为列表时出现的问题
|
||||
2.停止调整命令行窗口大小
|
||||
3.解决了输入的音符被除重的问题
|
||||
4.buld指令建立的附加包中新增startXXX函数用于初始设定
|
||||
|
||||
|
||||
Formal V 0.0.3
|
||||
2021 6 29
|
||||
1.新增save、load指令支持工程文件存取
|
||||
2.新增default指令存储默认设置
|
||||
3.输入exit指令退出时不会保存为默认设置
|
||||
4.新增delog指令在Windows系统下删除日志文件
|
||||
|
||||
|
||||
Formal V 0.0.4 ~ 0.0.4.2
|
||||
2021 6 30
|
||||
1.支持midi解析,能够通过midi文件解析音符,且仅支持打击乐器,即音长为0的声音,不能解析音的长度,解析仅包含note_on消息而不包含note_off消息,且暂时不能解析音乐附带的其他信息
|
||||
2.新增彩蛋指令TAFTCPC(the Anniversary of the Founding of The Communist Party of China) -(0.0.4.1)
|
||||
3.修复读取文件时读取内容不正确的问题 -(0.0.4.2)
|
||||
|
||||
|
||||
Formal V0.0.4.3
|
||||
2021 7 1
|
||||
1.内部代码优化,更加模块化,便于以后窗口化调用
|
||||
|
||||
|
||||
Formal V0.0.5 ~ 0.0.5.2
|
||||
2021 7 3 ~ 2021 7 4
|
||||
1.支持同时编辑、生成多个音乐函数
|
||||
2.支持一个项目中保存多个文件
|
||||
3.支持同一函数中出现不同的乐器 -(0.0.5.1)
|
||||
4.读取midi文件时支持音长的自动解析读取,并支持选择音轨 -(0.0.5.2)
|
||||
5.修复了编辑不同乐器时出现闪退的问题 -(0.0.5.2)
|
||||
|
||||
|
||||
Formal V0.0.5.3
|
||||
2021 7 5
|
||||
1.修复了存储工程文件时的崩溃问题
|
||||
2.读取midi时支持通过音轨自动生成不同的函数文件
|
||||
3.修复了生成函数文件中计分板为浮点数的问题
|
||||
4.修复文件路径不正确的问题
|
||||
5.新增应用bat脚本(仅Windows):可以快速启动、可以清除日志
|
||||
6.新增开发bat脚本(仅Windows):可以快速编译文件并启动测试、可以快速编译文件、可以快速启动测试
|
||||
|
||||
|
||||
Formal V0.0.6
|
||||
2021 7 8 - 2021 7 9
|
||||
1.停止对非Windows系统环境的支持
|
||||
2.支持预听生成的函数,即音乐试听
|
||||
3.乐曲修改设置:单个乐曲可包含多个文件序列(多个乐器),歌曲可以有自己单独的曲名、执行实体、执行计分板等独立设置;同时,每个歌曲可包含不同的乐器序列等等
|
||||
4.读取的音频格式更新:音符、我的世界音调、频率(Hz),仍是字典:'str' : [ float , float ]
|
||||
5.单个项目内不包含多首歌曲,但是做了预制功能:可以编辑多个项目(现在暂时不行)
|
||||
6.不可单独编辑单个音符的乐器
|
||||
7.放弃对语言文件的读取的支持
|
||||
8.停止支持对已读取的音轨的编辑(即删除edit指令)
|
||||
9.停止支持全局设置的修改,以及其相关支持(即删除当前的set、reset、default指令)
|
||||
10.预制支持对于单个音轨设置的修改以及音乐主设置的修改(现在暂时不行)
|
||||
11.存储的项目结构变为json文件结构,则无需zipfile库
|
||||
12.生成的文件包含:支持函数(1个、循环执行)、音乐函数(多个、循环执行)、启动函数(1个、执行一次)
|
||||
13.发现并修改错误:遇到休止符0时,播放会报错并停止
|
||||
14.新增彩蛋指令:RYOUN,生成团队队歌文件及项目
|
||||
15.项目更名为“我的世界函数音乐构建”
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TO-DO
|
||||
1.支持从midi文件的元信息中收取音符信息并自动生成
|
||||
2.Windows平台下支持窗口化
|
||||
3.支持使用WebSocket接口自动播放已编辑的音乐
|
||||
4.可以编辑多个项目
|
||||
5.能够自动将一个长串的音乐分成多个函数文件
|
||||
6.对于单个音轨设置的修改以及音乐主设置的修改
|
||||
7.支持汇报崩溃记录(通过邮件附件的方式)
|
@ -1,72 +0,0 @@
|
||||
从此日志开始,我的世界函数音乐构建更名为 函数音创 NoteFunCreater(谐音NotFun[狗头]),版本号更为0.1.0开始
|
||||
|
||||
注意,运行此文件需要第三方库:
|
||||
1. mido 用于对midi文件的解码
|
||||
2. py7zr 用于对7z压缩包的压缩与解压等(需pycparser, cffi, texttable, pyzstd, pyppmd, pycryptodomex, multivolumefile, brotli, bcj-cffi支持) -(从0.1.3开始不需要)
|
||||
3. zipfile 用于自动生成函数包的压缩
|
||||
4. pystray 用于支持窗口任务栏
|
||||
5. pillow (相当于Python2的PIL)用于绘图
|
||||
|
||||
|
||||
0.1.0
|
||||
2021 7 10 - 2021 7 12
|
||||
1.程序窗口化
|
||||
2.仅支持基本的菜单操作
|
||||
3.程序文件皆储存至其相应目录下
|
||||
4.程序./bin/目录下文件将会自动防修改
|
||||
5.删除了彩蛋
|
||||
|
||||
|
||||
0.1.1
|
||||
2021 7 14
|
||||
1.新增版本辨别的提示
|
||||
2.窗口中显示歌曲信息
|
||||
|
||||
|
||||
0.1.2
|
||||
2021 7 14 - 2021 7 15
|
||||
1.在没运行过的机器上会自动安装库
|
||||
2.从midi导入时不会删除其他音轨
|
||||
3.改进UI样式
|
||||
4.支持对于单个音轨设置的修改以及音乐主设置的修改
|
||||
5.当未保存便退出时,会询问存储
|
||||
6.新增加载进度提示
|
||||
|
||||
|
||||
0.1.3
|
||||
2021 7 15 - 2021 7 19
|
||||
1.不再从文件中读取音符及乐器信息(所以包更小了)
|
||||
2.改进UI
|
||||
3.修复了修改玩家选择器时变更了音乐标题的bug
|
||||
4.新增删除当前选定音轨按钮
|
||||
5.新增重置设置按钮(将音乐总设置设置为开始时的设置)
|
||||
6.运用多线程加载函数与文件等,程序运行效率更高
|
||||
7.修复变量作用域混淆问题
|
||||
|
||||
|
||||
0.1.3.1
|
||||
2021 7 19
|
||||
1.修复了菜单中无法退出程序的问题
|
||||
|
||||
|
||||
0.1.4
|
||||
2021 7 22
|
||||
1.支持显示指令于列表中
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TO-DO
|
||||
1.支持从midi文件的元信息中收取音符信息并自动生成
|
||||
2.支持生成zip函数包
|
||||
3.支持使用WebSocket接口自动播放已编辑的音乐
|
||||
4.可以编辑多个项目
|
||||
5.能够自动将一个长串的音乐分成多个函数文件
|
||||
6.支持用户导入自己的乐器
|
||||
7.支持汇报崩溃记录(通过邮件附件的方式)
|
||||
8.支持播放字幕
|
||||
9.支持任务栏角标与通知
|
||||
10.将控制台版本的彩蛋移植到此版本,开启了任务栏
|
||||
11.可编辑音符
|
@ -1,36 +0,0 @@
|
||||
世界音创(NoteMapCreater)是金羿开发的一款用于生成我的世界中各类有关音乐的物件的软件
|
||||
软件禁止商用,源代码始终公开,如使用未经授权的音乐经过此软件生成的任何物件侵犯了他人权利与本软件及其作者无关
|
||||
|
||||
Copyright © W-YI 2021
|
||||
|
||||
开头,特别感谢:
|
||||
KCINE:提供Cinemusicedit函数包(虽然函数包没怎么用过)
|
||||
Charlie_Ping:提供MusiCreaterBot(音乐地图生成QQ机器人)源码核心以及时不时的催更(虽然源码没有抄)
|
||||
金羿(作者本人):提供NoteFunCreater(函数音创)的制作经验以及时不时的摸鱼(虽然不是很支持函数音创)
|
||||
广大群友:高效的催更作业让我以蜗牛的速度前进
|
||||
|
||||
Alpha 0.0.0
|
||||
2021 8 1 - 2021 8 10
|
||||
1.确定了大概的功能
|
||||
2.不支持无参数传入
|
||||
3.可以查看帮助,但是帮助大多功能没实现
|
||||
4.可以从格式文本、midi文件、钢琴声音MP3导入音轨
|
||||
5.可以生成一些方块到世界里,但是没有播放器(半支持bw开关)
|
||||
5.提供了修改文件地址的方法,但是不能修改
|
||||
|
||||
Alpha 0.0.1
|
||||
2021 8 10
|
||||
1.可以从函数音创的工程文件读取音轨
|
||||
2.可以新建一个空白世界来生成
|
||||
3.支持修改输出文件地址
|
||||
4.支持修改输出方块起始位置
|
||||
5.支持指定播放乐器,执行实体,执行积分板,播放玩家选择器
|
||||
6.可以生成指令音乐地图(完全支持-w开关)
|
||||
|
||||
Beta 0.0.0
|
||||
2021 8 X?
|
||||
1.除了-nw 和 -f 开关不支持以外都支持了
|
||||
|
||||
Beta 0.0.1
|
||||
2021 8 19
|
||||
1.修复了大量bug
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
312
nmcsup/const.py
312
nmcsup/const.py
@ -1,312 +0,0 @@
|
||||
"""音创系列的音符对照表 以及一系列常数"""
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:0个;语法(一级)错误:109个
|
||||
|
||||
|
||||
notes = {
|
||||
'....A': [0.074, 27.5, 'wood', 8],
|
||||
'....A#': [0.0787, 29.135, 'wood', 9],
|
||||
'....B': [0.083, 30.868, 'wood', 10],
|
||||
'...C': [0.088, 32.703, 'wood', 11],
|
||||
'...C#': [0.094, 34.648, 'wood', 12],
|
||||
'...D': [0.1, 36.708, 'wood', 13],
|
||||
'...D#': [0.105, 38.891, 'log', 0],
|
||||
'...E': [0.11, 41.203, 'log', 1],
|
||||
'...F': [0.12, 43.654, 'log', 2],
|
||||
'...F#': [0.125, 46.249, 'wood', 0],
|
||||
'...G': [0.13, 48.999, 'wood', 1],
|
||||
'...G#': [0.14, 51.913, 'wood', 2],
|
||||
'...A': [0.15, 55.0, 'wood', 3],
|
||||
'...A#': [0.16, 58.27, 'wood', 4],
|
||||
'...B': [0.17, 61.735, 'wood', 5],
|
||||
'..C': [0.18, 65.406, 'wool', 0],
|
||||
'..C#': [0.19, 69.296, 'wool', 1],
|
||||
'..D': [0.2, 73.416, 'wool', 2],
|
||||
'..D#': [0.21, 77.782, 'wool', 3],
|
||||
'..E': [0.22, 82.407, 'wool', 4],
|
||||
'..F': [0.235, 87.307, 'wool', 5],
|
||||
'..F#': [0.25, 92.499, 'concretepowder', 0],
|
||||
'..G': [0.26, 97.999, 'concretepowder', 1],
|
||||
'..G#': [0.28, 103.826, 'concretepowder', 2],
|
||||
'..A': [0.3, 110.0, 'concretepowder', 3],
|
||||
'..A#': [0.31, 116.541, 'concretepowder', 4],
|
||||
'..B': [0.33, 123.471, 'concretepowder', 5],
|
||||
'.C': [0.35, 130.813, 'concretepowder', 6],
|
||||
'.C#': [0.37, 138.591, 'concretepowder', 7],
|
||||
'.D': [0.4, 146.832, 'concretepowder', 8],
|
||||
'.D#': [0.42, 155.563, 'concretepowder', 9],
|
||||
'.E': [0.44, 164.814, 'concretepowder', 10],
|
||||
'.F': [0.47, 174.614, 'concretepowder', 11],
|
||||
'.F#': [0.5, 184.997, 'concretepowder', 12],
|
||||
'.G': [0.53, 195.998, 'concretepowder', 13],
|
||||
'.G#': [0.56, 207.652, 'concretepowder', 14],
|
||||
'.A': [0.6, 220.0, 'concretepowder', 15],
|
||||
'.A#': [0.63, 233.082, 'concrete', 0],
|
||||
'.B': [0.67, 246.942, 'concrete', 1],
|
||||
'C': [0.7, 261.626, 'concrete', 2],
|
||||
'C#': [0.75, 277.183, 'concrete', 3],
|
||||
'D': [0.8, 293.665, 'concrete', 4],
|
||||
'D#': [0.84, 311.127, 'concrete', 5],
|
||||
'E': [0.9, 329.628, 'concrete', 6],
|
||||
'F': [0.94, 349.228, 'concrete', 7],
|
||||
'F#': [1.0, 369.994, 'concrete', 8],
|
||||
'G': [1.05, 391.995, 'concrete', 9],
|
||||
'G#': [1.12, 415.305, 'concrete', 10],
|
||||
'A': [1.2, 440.0, 'concrete', 11],
|
||||
'A#': [1.25, 466.164, 'concrete', 12],
|
||||
'B': [1.33, 493.883, 'concrete', 13],
|
||||
'`C': [1.4, 523.251, 'concrete', 14],
|
||||
'`C#': [1.5, 554.365, 'concrete', 15],
|
||||
'`D': [1.6, 587.33, 'stained_hardened_clay', 0],
|
||||
'`D#': [1.7, 622.254, 'stained_hardened_clay', 1],
|
||||
'`E': [1.8, 659.255, 'stained_hardened_clay', 2],
|
||||
'`F': [1.9, 698.456, 'stained_hardened_clay', 3],
|
||||
'`F#': [2.0, 739.989, 'stained_hardened_clay', 4],
|
||||
'`G': [2.1, 783.991, 'stained_hardened_clay', 5],
|
||||
'`G#': [2.24, 830.609, 'stained_hardened_clay', 6],
|
||||
'`A': [2.4, 880.0, 'stained_hardened_clay', 7],
|
||||
'`A#': [2.5, 932.328, 'stained_hardened_clay', 8],
|
||||
'`B': [2.67, 987.767, 'stained_hardened_clay', 9],
|
||||
'``C': [2.83, 1046.502, 'stained_hardened_clay', 10],
|
||||
'``C#': [3.0, 1108.731, 'stained_hardened_clay', 11],
|
||||
'``D': [3.17, 1174.659, 'stained_hardened_clay', 12],
|
||||
'``D#': [3.36, 1244.508, 'stained_hardened_clay', 13],
|
||||
'``E': [3.56, 1318.51, 'stained_hardened_clay', 14],
|
||||
'``F': [3.78, 1396.913, 'stained_hardened_clay', 15],
|
||||
'``F#': [4.0, 1479.978, 'white_glazed_terracotta', 0],
|
||||
'``G': [4.24, 1567.982, 'orange_glazed_terracotta', 0],
|
||||
'``G#': [4.5, 1661.219, 'magenta_glazed_terracotta', 0],
|
||||
'``A': [4.76, 1760.0, 'light_blue_glazed_terracotta', 0],
|
||||
'``A#': [5.04, 1864.655, 'yellow_glazed_terracotta', 0],
|
||||
'``B': [5.34, 1975.533, 'lime_glazed_terracotta', 0],
|
||||
'```C': [5.66, 2093.005, 'pink_glazed_terracotta', 0],
|
||||
'```C#': [6.0, 2217.461, 'gray_glazed_terracotta', 0],
|
||||
'```D': [6.35, 2349.318, 'silver_glazed_terracotta', 0],
|
||||
'```D#': [6.73, 2489.016, 'cyan_glazed_terracotta', 0],
|
||||
'```E': [7.13, 2637.02, 'purple_glazed_terracotta', 0],
|
||||
'```F': [7.55, 2793.826, 'blue_glazed_terracotta', 0],
|
||||
'```F#': [8.0, 2959.955, 'brown_glazed_terracotta', 0],
|
||||
'```G': [8.47, 3135.963, 'green_glazed_terracotta', 0],
|
||||
'```G#': [8.98, 3322.438, 'red_glazed_terracotta', 0],
|
||||
'```A': [9.51, 3520.0, 'black_glazed_terracotta', 0],
|
||||
'```A#': [10.08, 3729.31, 'stained_glass', 0],
|
||||
'```B': [10.68, 3951.066, 'stained_glass', 1],
|
||||
'````C': [11.31, 4186.009, 'stained_glass', 2],
|
||||
'0': [0.0, 0.0, 'glass', 0]
|
||||
}
|
||||
'''音符对照表\n
|
||||
音符:[MC音调, 声音频率, 方块名称, 数据值]'''
|
||||
|
||||
# 方块
|
||||
'''
|
||||
blocks = {
|
||||
0.074 : ['stained_glass', 3],
|
||||
0.0787 : ['stained_glass', 4],
|
||||
0.083 : ['stained_glass', 5],
|
||||
0.088 : ['stained_glass', 6],
|
||||
0.094 : ['stained_glass', 7],
|
||||
0.1 : ['stained_glass', 8],
|
||||
0.105 : ['stained_glass', 9],
|
||||
0.11 : ['stained_glass', 10],
|
||||
0.12 : ['stained_glass', 11],
|
||||
0.125 : ['stained_glass', 12],
|
||||
0.13 : ['stained_glass', 13],
|
||||
0.14 : ['stained_glass', 14],
|
||||
0.15 : ['stained_glass', 15],
|
||||
0.16 : ['wool', 0],
|
||||
0.17 : ['wool', 1],
|
||||
0.18 : ['wool', 2],
|
||||
0.19 : ['wool', 3],
|
||||
0.2 : ['wool', 4],
|
||||
0.21 : ['wool', 5],
|
||||
0.22 : ['wool', 6],
|
||||
0.235 : ['wool', 7],
|
||||
0.25 : ['concretepowder', 0],
|
||||
0.26 : ['concretepowder', 1],
|
||||
0.28 : ['concretepowder', 2],
|
||||
0.3 : ['concretepowder', 3],
|
||||
0.31 : ['concretepowder', 4],
|
||||
0.33 : ['concretepowder', 5],
|
||||
0.35 : ['concretepowder', 6],
|
||||
0.37 : ['concretepowder', 7],
|
||||
0.4 : ['concretepowder', 8],
|
||||
0.42 : ['concretepowder', 9],
|
||||
0.44 : ['concretepowder', 10],
|
||||
0.47 : ['concretepowder', 11],
|
||||
0.5 : ['concretepowder', 12],
|
||||
0.53 : ['concretepowder', 13],
|
||||
0.56 : ['concretepowder', 14],
|
||||
0.6 : ['concretepowder', 15],
|
||||
0.63 : ['concrete', 0],
|
||||
0.67 : ['concrete', 1],
|
||||
0.7 : ['concrete', 2],
|
||||
0.75 : ['concrete', 3],
|
||||
0.8 : ['concrete', 4],
|
||||
0.84 : ['concrete', 5],
|
||||
0.9 : ['concrete', 6],
|
||||
0.94 : ['concrete', 7],
|
||||
1.0 : ['concrete', 8],
|
||||
1.05 : ['concrete', 9],
|
||||
1.12 : ['concrete', 10],
|
||||
1.2 : ['concrete', 11],
|
||||
1.25 : ['concrete', 12],
|
||||
1.33 : ['concrete', 13],
|
||||
1.4 : ['concrete', 14],
|
||||
1.5 : ['concrete', 15],
|
||||
1.6 : ['stained_hardened_clay', 0],
|
||||
1.7 : ['stained_hardened_clay', 1],
|
||||
1.8 : ['stained_hardened_clay', 2],
|
||||
1.9 : ['stained_hardened_clay', 3],
|
||||
2.0 : ['stained_hardened_clay', 4],
|
||||
2.1 : ['stained_hardened_clay', 5],
|
||||
2.24 : ['stained_hardened_clay', 6],
|
||||
2.4 : ['stained_hardened_clay', 7],
|
||||
2.5 : ['stained_hardened_clay', 8],
|
||||
2.67 : ['stained_hardened_clay', 9],
|
||||
2.83 : ['stained_hardened_clay', 10],
|
||||
3.0 : ['stained_hardened_clay', 11],
|
||||
3.17 : ['stained_hardened_clay', 12],
|
||||
3.36 : ['stained_hardened_clay', 13],
|
||||
3.56 : ['stained_hardened_clay', 14],
|
||||
3.78 : ['stained_hardened_clay', 15],
|
||||
4.0 : ['stained_glass_pane', 0],
|
||||
4.24 : ['stained_glass_pane', 1],
|
||||
4.5 : ['stained_glass_pane', 2],
|
||||
4.76 : ['stained_glass_pane', 3],
|
||||
5.04 : ['stained_glass_pane', 4],
|
||||
5.34 : ['stained_glass_pane', 5],
|
||||
5.66 : ['stained_glass_pane', 6],
|
||||
6.0 : ['stained_glass_pane', 7],
|
||||
6.35 : ['stained_glass_pane', 8],
|
||||
6.73 : ['stained_glass_pane', 9],
|
||||
7.13 : ['stained_glass_pane', 10],
|
||||
7.55 : ['stained_glass_pane', 11],
|
||||
8.0 : ['stained_glass_pane', 12],
|
||||
8.47 : ['stained_glass_pane', 13],
|
||||
8.98 : ['stained_glass_pane', 14],
|
||||
9.51 : ['stained_glass_pane', 15],
|
||||
10.08 : ['stained_glass', 0],
|
||||
10.68 : ['stained_glass', 1],
|
||||
11.31 : ['stained_glass', 2],
|
||||
0.0 : ['glass', 0]
|
||||
}
|
||||
#向查理平致敬!!!!!
|
||||
'''
|
||||
|
||||
Blocks = {
|
||||
0.074: 'barrel',
|
||||
0.0787: 'beacon',
|
||||
0.083: 'bedrock',
|
||||
0.088: 'black_glazed_terracotta',
|
||||
0.094: 'blast_furnace',
|
||||
0.1: 'blue_glazed_terracotta',
|
||||
0.105: 'blue_ice',
|
||||
0.11: 'bone_block',
|
||||
0.12: 'bookshelf',
|
||||
0.125: 'brick_block',
|
||||
0.13: 'brown_glazed_terracotta',
|
||||
0.14: 'cartography_table',
|
||||
0.15: 'carved_pumpkin',
|
||||
0.16: 'clay',
|
||||
0.17: 'coal_block',
|
||||
0.18: 'coal_ore',
|
||||
0.19: 'cobblestone',
|
||||
0.2: 'concrete',
|
||||
0.21: 'crafting_table',
|
||||
0.22: 'cyan_glazed_terracotta',
|
||||
0.235: 'diamond_block',
|
||||
0.25: 'diamond_ore',
|
||||
0.26: 'white_glazed_terracotta',
|
||||
0.28: 'dispenser',
|
||||
0.3: 'dried_kelp_block',
|
||||
0.31: 'dropper',
|
||||
0.33: 'emerald_block',
|
||||
0.35: 'emerald_ore',
|
||||
0.37: 'end_bricks',
|
||||
0.4: 'end_stone',
|
||||
0.42: 'fletching_table',
|
||||
0.44: 'furnace',
|
||||
0.47: 'glass',
|
||||
0.5: 'glowingobsidian',
|
||||
0.53: 'glowstone',
|
||||
0.56: 'gold_block',
|
||||
0.6: 'gold_ore',
|
||||
0.63: 'grass',
|
||||
0.67: 'gray_glazed_terracotta',
|
||||
0.7: 'green_glazed_terracotta',
|
||||
0.75: 'hardened_clay',
|
||||
0.8: 'hay_block',
|
||||
0.84: 'iron_block',
|
||||
0.9: 'iron_ore',
|
||||
0.94: 'jukebox',
|
||||
1.0: 'lapis_block',
|
||||
1.05: 'lapis_ore',
|
||||
1.12: 'light_blue_glazed_terracotta',
|
||||
1.2: 'lime_glazed_terracotta',
|
||||
1.25: 'lit_pumpkin',
|
||||
1.33: 'log',
|
||||
1.4: 'loom',
|
||||
1.5: 'magenta_glazed_terracotta',
|
||||
1.6: 'magma',
|
||||
1.7: 'melon_block',
|
||||
1.8: 'web',
|
||||
1.9: 'mossy_cobblestone',
|
||||
2.0: 'nether_brick',
|
||||
2.1: 'nether_wart_block',
|
||||
2.24: 'netherrack',
|
||||
2.4: 'noteblock',
|
||||
2.5: 'observer',
|
||||
2.67: 'obsidian',
|
||||
2.83: 'orange_glazed_terracotta',
|
||||
3.0: 'pink_glazed_terracotta',
|
||||
3.17: 'piston',
|
||||
3.36: 'planks',
|
||||
3.56: 'prismarine',
|
||||
3.78: 'pumpkin',
|
||||
4.0: 'purple_glazed_terracotta',
|
||||
4.24: 'purpur_block',
|
||||
4.5: 'quartz_block',
|
||||
4.76: 'quartz_ore',
|
||||
5.04: 'red_glazed_terracotta',
|
||||
5.34: 'red_nether_brick',
|
||||
5.66: 'red_sandstone',
|
||||
6.0: 'redstone_block',
|
||||
6.35: 'yellow_glazed_terracotta',
|
||||
6.73: 'sandstone',
|
||||
7.13: 'stonebrick',
|
||||
7.55: 'silver_glazed_terracotta',
|
||||
8.0: 'slime',
|
||||
8.47: 'smithing_table',
|
||||
8.98: 'smoker',
|
||||
9.51: 'smooth_stone',
|
||||
10.08: 'snow',
|
||||
10.68: 'soul_sand',
|
||||
11.31: 'sponge',
|
||||
0.0: 'stone'
|
||||
}
|
||||
'''频率对照表\n
|
||||
MC音调:方块名称'''
|
||||
|
||||
# 乐器
|
||||
Instuments = {
|
||||
'note.banjo': '班卓',
|
||||
'note.bass': '低音',
|
||||
'note.bassattack': '贝斯',
|
||||
'note.bd': '鼓声',
|
||||
'note.bell': '铃声',
|
||||
'note.bit': '比特',
|
||||
'note.cow_bell': '牛铃',
|
||||
'note.didgeridoo': '迪吉',
|
||||
'note.flute': '长笛',
|
||||
'note.guitar': '吉他',
|
||||
'note.harp': '竖琴',
|
||||
'note.hat': '架鼓',
|
||||
'note.chime': '钟声',
|
||||
'note.iron_xylophone': '铁琴',
|
||||
'note.pling': '叮叮',
|
||||
'note.snare': '响弦',
|
||||
'note.xylophone': '木琴'
|
||||
}
|
||||
'''乐器对照表\n
|
||||
乐器英文:中文
|
||||
翻译:雪莹工坊Fun-Fer'''
|
@ -1,71 +0,0 @@
|
||||
"""提供对于音创系列的日志"""
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:0个;语法(一级)错误:9个
|
||||
|
||||
import logging
|
||||
import os
|
||||
import datetime
|
||||
|
||||
StrStartTime = str(datetime.datetime.now()).replace(':', '_')[:-7]
|
||||
time = StrStartTime
|
||||
|
||||
main_path = './log/'
|
||||
|
||||
position = main_path + time
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(level=logging.INFO)
|
||||
|
||||
if not os.path.exists('./log/'):
|
||||
os.makedirs('./log/')
|
||||
|
||||
# try:
|
||||
# handler = logging.FileHandler(position + ".logger")
|
||||
# except FileNotFoundError:
|
||||
# os.makedirs('./log/')
|
||||
handler = logging.FileHandler(position + ".logger")
|
||||
print(position + ".logger")
|
||||
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.INFO)
|
||||
|
||||
logger.addHandler(handler)
|
||||
logger.addHandler(console)
|
||||
|
||||
# import logger
|
||||
|
||||
# 载入日志功能
|
||||
StrStartTime = str(datetime.datetime.now()).replace(':', '_')[:-7]
|
||||
# logger.setting(StrStartTime)
|
||||
"""字符串型的程序开始时间"""
|
||||
|
||||
|
||||
def log(info: str = '', isWrite: bool = True, isPrinted: bool = False, isLoggerLibRecord: bool = True):
|
||||
"""
|
||||
info: 信息
|
||||
isPrinted: 是否print(仅限金羿log,python官方的logging照常输出)
|
||||
isLoggerLibRecord: 是否同时在logger库中记录
|
||||
isWrite: 是否write(仅限金羿log,python官方的logging照常输出)
|
||||
"""
|
||||
"""将信息连同当前时间载入日志"""
|
||||
# 致后来的开发者:请让金羿的log存在吧,不然他自己都看不懂你们写了什么了
|
||||
# 我指的是程序内部
|
||||
# ——金羿
|
||||
if not os.path.exists('./log/'):
|
||||
os.makedirs('./log/')
|
||||
if isWrite:
|
||||
with open('./log/' + StrStartTime + '.msct.log', 'a', encoding='UTF-8') as f:
|
||||
f.write(str(datetime.datetime.now())[11:19] + ' ' + info + '\n')
|
||||
if isPrinted:
|
||||
print(str(datetime.datetime.now())[11:19] + ' ' + info)
|
||||
if isLoggerLibRecord:
|
||||
logger.info(info)
|
||||
|
||||
|
||||
def end():
|
||||
logging.disable(logging.INFO)
|
||||
logging.shutdown()
|
@ -1,128 +0,0 @@
|
||||
"""音创系列的文件读取功能"""
|
||||
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:3个;语法(一级)错误:22个
|
||||
|
||||
|
||||
from nmcsup.log import log
|
||||
from nmcsup.const import notes
|
||||
|
||||
|
||||
|
||||
# 从格式文本文件读入一个音轨并存入一个列表
|
||||
def ReadFile(fn: str): # -> list
|
||||
from nmcsup.trans import note2list
|
||||
log('打开' + fn + "并读取音符")
|
||||
try:
|
||||
nat = open(fn, 'r', encoding='UTF-8').read().split(" ")
|
||||
del fn
|
||||
except FileNotFoundError:
|
||||
log("找不到读取目标文件")
|
||||
return False
|
||||
Notes = []
|
||||
log(str(nat) + "已读取")
|
||||
for i in range(int(len(nat) / 2)):
|
||||
Notes.append([nat[i * 2], float(nat[i * 2 + 1])])
|
||||
Notes = note2list(Notes)
|
||||
log('音符数据更新' + str(Notes))
|
||||
return [Notes, ]
|
||||
|
||||
|
||||
# 从midi读入多个音轨,返回多个音轨列表
|
||||
def ReadMidi(midfile: str): # -> list
|
||||
import mido
|
||||
from msctspt.threadOpera import NewThread
|
||||
Notes = []
|
||||
try:
|
||||
mid = mido.MidiFile(midfile)
|
||||
except FileNotFoundError:
|
||||
log("找不到文件或无法读取文件" + midfile)
|
||||
return False
|
||||
# 解析
|
||||
ks = list(notes.values())
|
||||
|
||||
def loadMidi(track1):
|
||||
datas = []
|
||||
for i in track1:
|
||||
if i.is_meta:
|
||||
log('元信息' + str(i))
|
||||
pass # 不处理元信息
|
||||
elif 'note_on' in str(i):
|
||||
msg = str(i).replace("note=", '').replace("time=", '').split(" ")
|
||||
log('音符on消息,处理后:' + str(msg))
|
||||
if msg[4] == '0':
|
||||
datas.append([ks[int(msg[2]) - 20][0], 1.0])
|
||||
log('延续时间0tick--:添加音符' + str([ks[int(msg[2]) - 20][0], 1.0]))
|
||||
else:
|
||||
datas.append([ks[int(msg[2]) - 20][0], float(msg[4]) / 480])
|
||||
log('延续时间' + msg[4] + 'tick--:添加音符' + str([ks[int(msg[2]) - 20][0], float(msg[4]) / 480]))
|
||||
del msg
|
||||
log('音符增加' + str(datas))
|
||||
return datas
|
||||
|
||||
for j, track in enumerate(mid.tracks):
|
||||
th = NewThread(loadMidi, (track,))
|
||||
th.start()
|
||||
Notes.append(th.getResult())
|
||||
del ks
|
||||
return Notes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def ReadOldProject(fn: str): # -> list
|
||||
import json
|
||||
from nmcsup.trans import note2list
|
||||
log("读取文件:" + fn)
|
||||
try:
|
||||
with open(fn, 'r', encoding='UTF-8') as c:
|
||||
dataset = json.load(c)
|
||||
except FileNotFoundError:
|
||||
print('找不到文件:' + fn + ",请查看您是否输入正确")
|
||||
log("丢失" + fn)
|
||||
return False
|
||||
for i in range(len(dataset['musics'])):
|
||||
dataset['musics'][i]['notes'] = note2list(dataset['musics'][i]['notes'])
|
||||
# 返回 音轨列表 选择器
|
||||
return dataset
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# a = midi_conversion("L:\\0WorldMusicCreater-MFMS new edition\\框架\\v0.3.2\\Musicreater\\测试用\\同道殊途标准.mid")
|
||||
# midi_conversion("L:\\0WorldMusicCreater-MFMS new edition\\框架\\v0.3.2\\Musicreater\\测试用\\"
|
||||
# "Illusionary_Daytime_--------幻昼.mid")
|
||||
# a = midi_conversion(r"C:\Users\lc\Documents\MuseScore3\乐谱\架子鼓.mid")
|
||||
from bgArrayLib.reader import midi_conversion
|
||||
a = midi_conversion(r"C:\Users\lc\Documents\MuseScore3\乐谱\stay2.mid")
|
||||
# print(a)
|
246
nmcsup/trans.py
246
nmcsup/trans.py
@ -1,246 +0,0 @@
|
||||
"""音创系列的转换功能"""
|
||||
# 诸葛亮与八卦阵帮忙修改语法 日期:---2022年1月19日
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:2个;语法(一级)错误:192个
|
||||
|
||||
|
||||
from nmcsup.log import log
|
||||
|
||||
import amulet
|
||||
import amulet_nbt
|
||||
from amulet.api.block import Block
|
||||
from amulet.api.block_entity import BlockEntity
|
||||
from amulet.utils.world_utils import block_coords_to_chunk_coords
|
||||
from amulet_nbt import TAG_String, TAG_Compound, TAG_Byte
|
||||
|
||||
|
||||
# 输入一个列表 [ [str, float ], [], ... ] 音符str 值为持续时间float
|
||||
def note2list(Notes: list) -> list:
|
||||
from nmcsup.const import notes
|
||||
|
||||
def change(base):
|
||||
enwo = {
|
||||
'a': 'A',
|
||||
'b': 'B',
|
||||
'c': 'C',
|
||||
'd': "D",
|
||||
"e": "E",
|
||||
'f': 'F',
|
||||
'g': "G"
|
||||
}
|
||||
nuwo = {
|
||||
'6': 'A',
|
||||
'7': 'B',
|
||||
'1': 'C',
|
||||
'2': "D",
|
||||
"3": "E",
|
||||
'4': 'F',
|
||||
'5': "G"
|
||||
}
|
||||
for k, v in enwo.items():
|
||||
if k in base:
|
||||
base = base.replace(k, v)
|
||||
for k, v in nuwo.items():
|
||||
if k in base:
|
||||
base = base.replace(k, v)
|
||||
return base
|
||||
|
||||
res = []
|
||||
log(" === 音符列表=>音调列表")
|
||||
for i in Notes:
|
||||
s2 = change(i[0])
|
||||
log(' === 正在操作音符' + i[0] + '->' + s2)
|
||||
if s2 in notes.keys():
|
||||
log(" === 找到此音符,加入:" + str(notes[s2][0]))
|
||||
res.append([notes[s2][0], float(i[1])])
|
||||
else:
|
||||
log(' === ' + s2 + '不在音符表内,此处自动替换为 休止符0 ')
|
||||
res.append(['0', float(i[1])])
|
||||
log(' === 最终反回' + str(res))
|
||||
return res
|
||||
|
||||
|
||||
def mcnote2freq(Notes):
|
||||
from nmcsup.const import notes
|
||||
mcnback = {}
|
||||
for i, j in notes.items():
|
||||
mcnback[j[0]] = i
|
||||
res = []
|
||||
log(" === 我的世界音调表=>频率列表")
|
||||
for i in Notes:
|
||||
log(' === 正在操作音符' + i[0] + '->' + mcnback[i[0]])
|
||||
res.append([notes[mcnback[i[0]]][1], float(i[1])])
|
||||
log(' === 最终反回' + str(res))
|
||||
return res
|
||||
|
||||
|
||||
# MP3文件转midi文件
|
||||
def Mp32Mid(mp3File, midFile):
|
||||
from piano_transcription_inference import PianoTranscription, sample_rate, load_audio
|
||||
# 加载
|
||||
(audio, _) = load_audio(mp3File, sr=sample_rate) # , mono=True
|
||||
# 实例化并转换
|
||||
PianoTranscription(device="cpu").transcribe(audio, midFile)
|
||||
|
||||
|
||||
# 传入一个音符列表转为指令列表
|
||||
def Note2Cmd(Notes: list, ScoreboardName: str, Instrument: str, PlayerSelect: str = '',
|
||||
isProsess: bool = False) -> list:
|
||||
commands = []
|
||||
a = 0.0
|
||||
length = len(Notes)
|
||||
j = 1
|
||||
for i in range(len(Notes)):
|
||||
commands.append("execute @a" + PlayerSelect + " ~ ~ ~ execute @s[scores={" + ScoreboardName + "=" + str(
|
||||
int((a + 2) * 5 + int(Notes[i][1] * 5))) + "}] ~ ~ ~ playsound " + Instrument + " @s ~ ~ ~ 1000 " + str(
|
||||
Notes[i][0]) + " 1000\n")
|
||||
a += Notes[i][1]
|
||||
if isProsess:
|
||||
commands.append("execute @a" + PlayerSelect + " ~ ~ ~ execute @s[scores={" + ScoreboardName + "=" + str(
|
||||
int((a + 2) * 5 + int(Notes[i][1] * 5))) + "}] ~ ~ ~ title @s actionbar §e▶ 播放中: §a" + str(
|
||||
j) + "/" + str(length) + " || " + str(int(j / length * 1000) / 10) + "\n")
|
||||
j += 1
|
||||
commands.append("\n\n# 凌云我的世界开发团队 x 凌云软件开发团队 : W-YI(金羿)\n")
|
||||
return commands
|
||||
|
||||
|
||||
# def newDataStructureCounterChange():
|
||||
|
||||
|
||||
# 简单载入方块
|
||||
# level.set_version_block(posx,posy,posz,"minecraft:overworld",("bedrock", (1, 16, 20)),Block(namespace, name))
|
||||
|
||||
|
||||
# 转入指令列表与位置信息转至世界
|
||||
def Cmd2World(cmd: list, world: str, dire: list):
|
||||
"""将指令以命令链的形式载入世界\n
|
||||
cmd指令列表位为一个序列,中包含指令字符串\n
|
||||
world为地图所在位置,需要指向文件夹,dire为指令方块生成之位置"""
|
||||
level = amulet.load_level(world)
|
||||
cdl = []
|
||||
for i in cmd:
|
||||
# e = True
|
||||
try:
|
||||
if (i[:i.index('#')].replace(' ', '') != '\n') and (i[:i.index('#')].replace(' ', '') != ''):
|
||||
cdl.append(i[:i.index('#')])
|
||||
# e = False
|
||||
except:
|
||||
cdl.append(i)
|
||||
# finally:
|
||||
# if e is True:
|
||||
# cdl.append(i)
|
||||
i = 0
|
||||
# 第一个是特殊
|
||||
universal_block = Block('universal_minecraft', 'command_block',
|
||||
{'conditional': TAG_String("false"), 'facing': TAG_String('up'),
|
||||
'mode': TAG_String("repeating")})
|
||||
cx, cz = block_coords_to_chunk_coords(dire[0], dire[2])
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = dire[0] - 16 * cx, dire[2] - 16 * cz
|
||||
universal_block_entity = BlockEntity('universal_minecraft', 'command_block', dire[0], dire[1], dire[2],
|
||||
amulet_nbt.NBTFile(TAG_Compound({'utags': TAG_Compound(
|
||||
{'auto': TAG_Byte(0), 'Command': TAG_String(cdl.pop(0))})})))
|
||||
chunk.blocks[offset_x, dire[1], offset_z] = level.block_palette.get_add_block(universal_block)
|
||||
chunk.block_entities[(dire[0], dire[1], dire[2])] = universal_block_entity
|
||||
chunk.changed = True
|
||||
# 集体上移
|
||||
dire[1] += 1
|
||||
# 真正开始
|
||||
down = False
|
||||
for j in cdl:
|
||||
if dire[1] + i >= 255:
|
||||
dire[0] += 1
|
||||
i = 0
|
||||
down = not down
|
||||
# 定义此方块
|
||||
if dire[1] + i == 254:
|
||||
universal_block = Block('universal_minecraft', 'command_block',
|
||||
{'conditional': TAG_String("false"), 'facing': TAG_String('east'),
|
||||
'mode': TAG_String("chain")})
|
||||
else:
|
||||
if down:
|
||||
universal_block = Block('universal_minecraft', 'command_block',
|
||||
{'conditional': TAG_String("false"), 'facing': TAG_String('down'),
|
||||
'mode': TAG_String("chain")})
|
||||
else:
|
||||
universal_block = Block('universal_minecraft', 'command_block',
|
||||
{'conditional': TAG_String("false"), 'facing': TAG_String('up'),
|
||||
'mode': TAG_String("chain")})
|
||||
cx, cz = block_coords_to_chunk_coords(dire[0], dire[2])
|
||||
# 获取区块
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = dire[0] - 16 * cx, dire[2] - 16 * cz
|
||||
if down:
|
||||
# 定义方块实体
|
||||
universal_block_entity = BlockEntity('universal_minecraft', 'command_block', dire[0], 254 - i, dire[2],
|
||||
amulet_nbt.NBTFile(TAG_Compound({'utags': TAG_Compound(
|
||||
{'auto': TAG_Byte(1), 'Command': TAG_String(j)})})))
|
||||
|
||||
# 将方块加入世界
|
||||
chunk.blocks[offset_x, 254 - i, offset_z] = level.block_palette.get_add_block(universal_block)
|
||||
chunk.block_entities[(dire[0], 254 - i, dire[2])] = universal_block_entity
|
||||
else:
|
||||
# 定义方块实体
|
||||
universal_block_entity = BlockEntity('universal_minecraft', 'command_block', dire[0], dire[1] + i, dire[2],
|
||||
amulet_nbt.NBTFile(TAG_Compound({'utags': TAG_Compound(
|
||||
{'auto': TAG_Byte(1), 'Command': TAG_String(j)})})))
|
||||
|
||||
# 将方块加入世界
|
||||
chunk.blocks[offset_x, dire[1] + i, offset_z] = level.block_palette.get_add_block(universal_block)
|
||||
chunk.block_entities[(dire[0], dire[1] + i, dire[2])] = universal_block_entity
|
||||
# 设置为已更新区块
|
||||
chunk.changed = True
|
||||
i += 1
|
||||
del i, cdl
|
||||
# 保存世界并退出
|
||||
level.save()
|
||||
level.close()
|
||||
|
||||
|
||||
# 音符转成方块再加载到世界里头
|
||||
def Blocks2World(world: str, dire: list, Datas: list):
|
||||
from nmcsup.const import Blocks
|
||||
level = amulet.load_level(world)
|
||||
i = 0
|
||||
|
||||
def setblock(block: str, pos: list):
|
||||
"""pos : list[int,int,int]"""
|
||||
cx, cz = block_coords_to_chunk_coords(pos[0], pos[2])
|
||||
chunk = level.get_chunk(cx, cz, "minecraft:overworld")
|
||||
offset_x, offset_z = pos[0] - 16 * cx, pos[2] - 16 * cz
|
||||
chunk.blocks[offset_x, pos[1], offset_z] = level.block_palette.get_add_block(Block("minecraft", block))
|
||||
chunk.changed = True
|
||||
|
||||
for j in Datas:
|
||||
if dire[1] + 1 >= 255:
|
||||
i = 0
|
||||
dire[0] += 1
|
||||
setblock(Blocks[j[0]], [dire[0], dire[1] + i, dire[2]])
|
||||
i = int(i + j[1] + 0.5) # 四舍五入
|
||||
level.save()
|
||||
level.close()
|
||||
|
||||
|
||||
# 传入音符列表制作播放器指令
|
||||
def Notes2Player(Note, dire: list, CmdData: dict):
|
||||
"""传入音符列表、坐标、指令数据,生成播放器指令"""
|
||||
Notes = {}
|
||||
for i in Note:
|
||||
Notes[i[0]] = ''
|
||||
Notes = list(Notes.keys())
|
||||
from nmcsup.const import Blocks
|
||||
Cmds = []
|
||||
for j in Notes:
|
||||
Cmds.append('execute @e[x=' + str(dire[0]) + ',y=' + str(dire[1]) + ',z=' + str(dire[2]) + ',dy=' + str(
|
||||
255 - dire[1]) + ',name=' + CmdData['Ent'] + '] ~ ~ ~ detect ~ ~ ~ ' + Blocks[j] + ' 0 execute @a ' +
|
||||
CmdData['Pls'] + ' ~ ~ ~ playsound ' + CmdData['Ins'] + ' @s ~ ~ ~ 1000 ' + str(j) + ' 1000\n')
|
||||
Cmds += ['#本函数由 金羿 音·创 生成\n', 'execute @e[y=' + str(dire[1]) + ',dy=' + str(255 - dire[1]) + ',name=' + CmdData[
|
||||
'Ent'] + '] ~ ~ ~ tp ~ ~1 ~\n',
|
||||
'execute @e[y=255,dy=100,name=' + CmdData['Ent'] + '] ~ ~ ~ tp ~1 ' + str(dire[1]) + ' ~\n',
|
||||
'#音·创 开发交流群 861684859']
|
||||
return Cmds
|
||||
|
||||
|
||||
# 传入音符列表生成方块至世界
|
||||
def Datas2BlkWorld(NoteData, world: str, dire: list):
|
||||
for i in range(len(NoteData)):
|
||||
Blocks2World(world, [dire[0], dire[1], dire[2] + i], NoteData[i])
|
@ -1,86 +0,0 @@
|
||||
"""音创系列版本号和版本操作函数"""
|
||||
# 统计:致命(三级)错误:0个;警告(二级)错误:0个;语法(一级)错误:24个
|
||||
|
||||
|
||||
from msctspt.bugReporter import version
|
||||
import os
|
||||
|
||||
# 以下下两个值请在 msctspt/bugReporter 的version类中修改
|
||||
VER = version.version
|
||||
"""当前版本"""
|
||||
|
||||
LIBS = version.libraries
|
||||
"""当前所需库"""
|
||||
|
||||
|
||||
# 判断版本、临时文件与补全库
|
||||
def compver(ver1, ver2):
|
||||
"""
|
||||
传入不带英文的版本号,特殊情况:"10.12.2.6.5">"10.12.2.6"
|
||||
:param ver1: 版本号1
|
||||
:param ver2: 版本号2
|
||||
:return: ver1< = >ver2返回-1/0/1
|
||||
"""
|
||||
list1 = str(ver1).split(".")
|
||||
list2 = str(ver2).split(".")
|
||||
# 循环次数为短的列表的len
|
||||
for i in range(len(list1)) if len(list1) < len(list2) else range(len(list2)):
|
||||
if int(list1[i]) == int(list2[i]):
|
||||
pass
|
||||
elif int(list1[i]) < int(list2[i]):
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
# 循环结束,哪个列表长哪个版本号高
|
||||
if len(list1) == len(list2):
|
||||
return 0
|
||||
elif len(list1) < len(list2):
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
#
|
||||
# ————————————————
|
||||
# 版权声明:上面的函数compver为CSDN博主「基友死得早」的原创文章中的函数,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
|
||||
# 原文链接:https://blog.csdn.net/tinyjm/article/details/93514261
|
||||
# ————————————————
|
||||
#
|
||||
|
||||
|
||||
def InstallLibs(now, LIBS1):
|
||||
"""比对库信息并安装库"""
|
||||
from os import system as run
|
||||
for i in LIBS1:
|
||||
if i not in now:
|
||||
print("安装库:" + i)
|
||||
run("python -m pip install " + i + " -i https://pypi.tuna.tsinghua.edu.cn/simple")
|
||||
|
||||
|
||||
def chkver(ver=VER, libs=LIBS):
|
||||
"""通过文件比对版本信息并安装库"""
|
||||
if not os.path.exists(os.getenv('APPDATA') + '\\Musicreater\\msct.ActiveDatas.msct'):
|
||||
print("新安装库")
|
||||
os.makedirs(os.getenv('APPDATA') + '\\Musicreater\\')
|
||||
with open(os.getenv('APPDATA') + '\\Musicreater\\msct.ActiveDatas.msct', 'w') as f:
|
||||
f.write(ver[0] + '\n')
|
||||
for i in libs:
|
||||
f.write(i + '\n')
|
||||
InstallLibs([], libs)
|
||||
else:
|
||||
with open(os.getenv('APPDATA') + '\\Musicreater\\msct.ActiveDatas.msct', 'r') as f:
|
||||
v = f.readlines()
|
||||
cp = compver(ver[0], v[0])
|
||||
if cp != 0:
|
||||
InstallLibs(v[1:], libs)
|
||||
with open(os.getenv('APPDATA') + '\\Musicreater\\msct.ActiveDatas.msct', 'w') as f:
|
||||
f.write(ver[0] + '\n')
|
||||
for i in libs:
|
||||
f.write(i + '\n')
|
||||
del cp
|
||||
|
||||
|
||||
def resetver():
|
||||
"""重置版本信息"""
|
||||
import shutil
|
||||
shutil.rmtree(os.getenv('APPDATA') + '\\Musicreater\\')
|
Loading…
Reference in New Issue
Block a user