1
0
forked from bot/app

添加对zip格式的资源包的支持,对function的支持

This commit is contained in:
2024-05-31 19:17:25 +08:00
parent c66d470166
commit e15aafd781
10 changed files with 285 additions and 90 deletions

View File

@ -0,0 +1,111 @@
"""
liteyuki function是一种类似于mcfunction的函数用于在liteyuki中实现一些功能例如自定义指令等也可与Python函数绑定
使用 /function function_name *args **kwargs来调用
例如 /function test/hello user_id=123456
可以用于一些轻量级插件的编写无需Python代码
SnowyKami
"""
import functools
# cmd *args **kwargs
# api api_name **kwargs
import os
from typing import Any, Awaitable, Callable, Coroutine
from nonebot import Bot
from nonebot.adapters.satori import bot
ly_function_extensions = (
"lyf",
"lyfunction",
"mcfunction"
)
loaded_functions = dict()
class LiteyukiFunction:
def __init__(self, name: str, path: str):
self.name = name
self.path = path
self.functions = list()
self.bot: Bot = None
self.var_data = dict()
self.macro_data = dict()
def __call__(self, *args, **kwargs):
for _callable in self.functions:
if _callable is not None:
_callable(*args, **kwargs)
def __str__(self):
return f"LiteyukiFunction({self.name}, {self.path})"
def __repr__(self):
return self.__str__()
async def execute_line(self, line: str) -> Callable[[tuple, dict], Coroutine[Any, Any, Any] | Any] | None:
"""
解析一行轻雪函数
Args:
line:
Returns:
"""
args: list[str] = line.split(" ")
head = args.pop(0)
if head.startswith("#"):
# 注释
return None
elif head == "var":
# 变量定义
for arg in args:
self.var_data[arg.split("=", 1)[0]] = eval(arg.split("=", 1)[1])
elif head == "cmd":
# 在当前计算机上执行命令
os.system(line.split(" ", 1)[1])
elif head == "api":
# 调用Bot API 需要Bot实例
await self.bot.call_api(line.split(" ", 1)[1])
elif head == "function":
# 调用轻雪函数
return functools.partial(get_function, line.split(" ", 1)[1])
def get_function(name: str) -> LiteyukiFunction | None:
"""
获取一个轻雪函数
Args:
name: 函数名
Returns:
"""
return loaded_functions.get(name)
def load_from_dir(path: str):
"""
从目录中加载轻雪函数类似mcfunction
Args:
path: 目录路径
"""
for f in os.listdir(path):
f = os.path.join(path, f)
if os.path.isfile(f):
if f.endswith(ly_function_extensions):
load_from_file(f)
def load_from_file(path: str):
"""
从文件中加载轻雪函数
Args:
path:
Returns:
"""
pass

View File

@ -1,6 +1,7 @@
import json
import os
import shutil
import zipfile
from typing import Any
import nonebot
@ -11,6 +12,7 @@ from .language import Language, get_default_lang_code
_loaded_resource_packs: list["ResourceMetadata"] = [] # 按照加载顺序排序
temp_resource_root = "data/liteyuki/resources"
temp_extract_root = "data/liteyuki/temp"
lang = Language(get_default_lang_code())
@ -32,6 +34,15 @@ def load_resource_from_dir(path: str):
if os.path.exists(os.path.join(path, "metadata.yml")):
with open(os.path.join(path, "metadata.yml"), "r", encoding="utf-8") as f:
metadata = yaml.safe_load(f)
elif os.path.isfile(path) and path.endswith(".zip"):
# zip文件
# 临时解压并读取metadata.yml
with zipfile.ZipFile(path, "r") as zip_ref:
# 解压至临时目录 data/liteyuki/temp/{pack_name}.zip
zip_ref.extractall(os.path.join(temp_extract_root, os.path.basename(path)))
with zip_ref.open("metadata.yml") as f:
metadata = yaml.safe_load(f)
path = os.path.join(temp_extract_root, os.path.basename(path))
else:
# 没有metadata.yml文件不是一个资源包
return
@ -41,13 +52,21 @@ def load_resource_from_dir(path: str):
copy_file(os.path.join(root, file), os.path.join(temp_resource_root, relative_path))
metadata["path"] = path
metadata["folder"] = os.path.basename(path)
if os.path.exists(os.path.join(path, "lang")):
# 加载语言
from liteyuki.utils.base.language import load_from_dir
load_from_dir(os.path.join(path, "lang"))
if os.path.exists(os.path.join(path, "functions")):
# 加载功能
from liteyuki.utils.base.ly_function import load_from_dir
load_from_dir(os.path.join(path, "functions"))
_loaded_resource_packs.insert(0, ResourceMetadata(**metadata))
def get_path(path: str, abs_path: bool = True, default: Any = None, debug: bool=False) -> str | Any:
def get_path(path: str, abs_path: bool = True, default: Any = None, debug: bool = False) -> str | Any:
"""
获取资源包中的文件
Args:
@ -125,7 +144,7 @@ def load_resources():
json.dump([], open("resources/index.json", "w", encoding="utf-8"))
resource_index: list[str] = json.load(open("resources/index.json", "r", encoding="utf-8"))
resource_index.reverse() # 优先级高的后加载,但是排在前面
resource_index.reverse() # 优先级高的后加载,但是排在前面
for resource in resource_index:
load_resource_from_dir(os.path.join("resources", resource))
@ -147,7 +166,8 @@ def check_exist(name: str) -> bool:
name: 资源包名称,文件夹名
Returns: 是否存在
"""
return os.path.exists(os.path.join("resources", name, "metadata.yml"))
path = os.path.join("resources", name)
return os.path.exists(os.path.join(path, "metadata.yml")) or (os.path.isfile(path) and name.endswith(".zip"))
def add_resource_pack(name: str) -> bool: