forked from shenjack/ica-plugins
ruaaaa
This commit is contained in:
commit
12d4e24a41
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
#config/*
|
||||
|
||||
*__pycache__*
|
||||
*.pyc
|
0
config/your_config_here
Normal file
0
config/your_config_here
Normal file
BIN
plugins/SMILEYSANS-OBLIQUE.TTF
Normal file
BIN
plugins/SMILEYSANS-OBLIQUE.TTF
Normal file
Binary file not shown.
82
plugins/base.py
Normal file
82
plugins/base.py
Normal file
@ -0,0 +1,82 @@
|
||||
import io
|
||||
import psutil
|
||||
import platform
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
from PIL import (Image, ImageDraw, ImageFont)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ica_typing import IcaNewMessage, IcaClient
|
||||
from ica_typing import TailchatReciveMessage, TailchatClient
|
||||
else:
|
||||
IcaNewMessage = TypeVar("NewMessage")
|
||||
IcaClient = TypeVar("IcaClient")
|
||||
TailchatReciveMessage = TypeVar("TailchatReciveMessage")
|
||||
TailchatClient = TypeVar("TailchatClient")
|
||||
|
||||
|
||||
# 生成一张本地信息图
|
||||
def local_env_info() -> str:
|
||||
cache = io.StringIO()
|
||||
# 参考 DR 的 (crash report)
|
||||
cache.write(f"系统: {platform.platform()}\n")
|
||||
# 处理器
|
||||
try:
|
||||
cache.write("|".join([f"{x}%" for x in psutil.cpu_percent(interval=1, percpu=True)]))
|
||||
cache.write("\n")
|
||||
except OSError:
|
||||
cache.write("CPU: 未知\n")
|
||||
# Python 版本信息
|
||||
cache.write(f"{platform.python_implementation()}: {platform.python_version()}-{platform.python_branch()}({platform.python_compiler()})\n")
|
||||
# 内存信息
|
||||
try:
|
||||
memory = psutil.virtual_memory()
|
||||
cache.write(f"内存: {memory.free / 1024 / 1024 / 1024:.3f}GB/{memory.total / 1024 / 1024 / 1024:.3f}GB\n")
|
||||
except OSError:
|
||||
cache.write("内存: 未知\n")
|
||||
return cache.getvalue()
|
||||
|
||||
def local_env_image() -> bytes:
|
||||
img = Image.new("RGB", (800, 140), (255, 255, 255))
|
||||
# 往图片上写入一些信息
|
||||
draw = ImageDraw.Draw(img)
|
||||
font = ImageFont.truetype("./SMILEYSANS-OBLIQUE.TTF", size=25)
|
||||
draw.text((10, 10), local_env_info(), fill=(0, 0, 0), font=font)
|
||||
img_cache = io.BytesIO()
|
||||
img.save(img_cache, format="PNG")
|
||||
raw_img = img_cache.getvalue()
|
||||
img_cache.close()
|
||||
return raw_img
|
||||
|
||||
def on_ica_message(msg: IcaNewMessage, client: IcaClient) -> None:
|
||||
if not (msg.is_from_self or msg.is_reply):
|
||||
if msg.content == "/bot":
|
||||
reply = msg.reply_with(f"ica-async-rs({client.version})-sync-py {client.ica_version}")
|
||||
client.send_message(reply)
|
||||
elif msg.content == "/bot-sys":
|
||||
datas = local_env_info()
|
||||
reply = msg.reply_with(datas)
|
||||
reply.set_img(local_env_image(), "image/png", False)
|
||||
client.send_message(reply)
|
||||
elif msg.content == "/bot-uptime":
|
||||
uptime = client.startup_time
|
||||
up_delta = datetime.now(timezone.utc) - uptime
|
||||
reply = msg.reply_with(f"Bot 运行时间: {up_delta}")
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
def on_tailchat_message(msg: TailchatReciveMessage, client: TailchatClient) -> None:
|
||||
if not (msg.is_reply or msg.is_from_self):
|
||||
if msg.content == "/bot":
|
||||
reply = msg.reply_with(f"tailchat-async-rs({client.version})-sync-py {client.tailchat_version}")
|
||||
client.send_message(reply)
|
||||
elif msg.content == "/bot-sys":
|
||||
datas = local_env_info()
|
||||
reply = msg.reply_with(datas)
|
||||
reply.set_img(local_env_image(), "just_img.png")
|
||||
client.send_message(reply)
|
||||
elif msg.content == "/bot-uptime":
|
||||
uptime = client.startup_time
|
||||
up_delta = datetime.now(timezone.utc) - uptime
|
||||
reply = msg.reply_with(f"Bot 运行时间: {up_delta}")
|
||||
client.send_message(reply)
|
378
plugins/bmcl.py
Normal file
378
plugins/bmcl.py
Normal file
@ -0,0 +1,378 @@
|
||||
import io
|
||||
import time
|
||||
import requests
|
||||
import traceback
|
||||
import urllib.parse
|
||||
|
||||
# import PIL
|
||||
|
||||
from typing import TYPE_CHECKING, TypeVar, Optional, Tuple, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ica_typing import IcaNewMessage, IcaClient, ConfigData
|
||||
CONFIG_DATA: ConfigData
|
||||
else:
|
||||
CONFIG_DATA = None # type: ignore
|
||||
IcaNewMessage = TypeVar("NewMessage")
|
||||
IcaClient = TypeVar("IcaClient")
|
||||
|
||||
_version_ = "2.8.0-rs"
|
||||
backend_version = "unknown"
|
||||
|
||||
def format_data_size(data_bytes: float) -> str:
|
||||
data_lens = ["B", "KB", "MB", "GB", "TB"]
|
||||
data_len = "0B"
|
||||
for i in range(5):
|
||||
if data_bytes < 1024:
|
||||
data_bytes = round(data_bytes, 5)
|
||||
data_len = f"{data_bytes}{data_lens[i]}"
|
||||
break
|
||||
else:
|
||||
data_bytes /= 1024
|
||||
return data_len
|
||||
|
||||
|
||||
def format_hit_count(count: int) -> str:
|
||||
"""数据分段, 四位一个下划线
|
||||
|
||||
Args:
|
||||
count (int): 数据
|
||||
|
||||
Returns:
|
||||
str: 格式化后的数据
|
||||
1 -> 1
|
||||
1000 -> 1000
|
||||
10000 -> 1_0000
|
||||
100000 -> 10_0000
|
||||
1000000 -> 100_0000
|
||||
"""
|
||||
count_str = str(count)
|
||||
count_len = len(count_str)
|
||||
if count_len <= 4:
|
||||
return count_str
|
||||
else:
|
||||
# 先倒序
|
||||
# 再插入
|
||||
# 最后再倒序
|
||||
count_str = count_str[::-1]
|
||||
count_str = "_".join([count_str[i:i+4] for i in range(0, count_len, 4)])
|
||||
count_str = count_str[::-1]
|
||||
return count_str
|
||||
|
||||
|
||||
def wrap_request(url: str, msg: IcaNewMessage, client: IcaClient) -> Optional[dict]:
|
||||
try:
|
||||
cookie = CONFIG_DATA["cookie"] # type: ignore
|
||||
if cookie == "填写你的 cookie" or cookie is None:
|
||||
response = requests.get(url)
|
||||
else:
|
||||
response = requests.get(url, cookies={"openbmclapi-jwt": cookie})
|
||||
except requests.exceptions.RequestException:
|
||||
warn_msg = f"数据请求失败, 请检查网络\n{traceback.format_exc()}"
|
||||
reply = msg.reply_with(warn_msg)
|
||||
client.send_and_warn(reply)
|
||||
return None
|
||||
except Exception as _:
|
||||
warn_msg = f"数据请求中发生未知错误, 请呼叫 shenjack\n{traceback.format_exc()}"
|
||||
reply = msg.reply_with(warn_msg)
|
||||
client.send_and_warn(reply)
|
||||
return None
|
||||
if not response.status_code == 200 or response.reason != "OK":
|
||||
warn_msg = f"请求失败, 请检查网络\n{response.status_code} {response.reason}"
|
||||
reply = msg.reply_with(warn_msg)
|
||||
client.send_and_warn(reply)
|
||||
return None
|
||||
return response.json()
|
||||
|
||||
|
||||
def bmcl_dashboard(msg: IcaNewMessage, client: IcaClient) -> None:
|
||||
req_time = time.time()
|
||||
# 记录请求时间
|
||||
data = wrap_request("https://bd.bangbang93.com/openbmclapi/metric/dashboard", msg, client)
|
||||
dashboard_status = wrap_request("https://bd.bangbang93.com/openbmclapi/metric/version", msg, client)
|
||||
if data is None or dashboard_status is None:
|
||||
return
|
||||
global backend_version
|
||||
backend_version = dashboard_status["version"]
|
||||
backend_commit = dashboard_status["_resolved"].split("#")[1][:7]
|
||||
data_bytes: float = data["bytes"]
|
||||
data_hits: int = data["hits"]
|
||||
data_bandwidth: float = data["currentBandwidth"]
|
||||
load_str: float = data["load"] * 100
|
||||
online_node: int = data["currentNodes"]
|
||||
online_bandwidth: int = data["bandwidth"]
|
||||
data_len = format_data_size(data_bytes)
|
||||
hits_count = format_hit_count(data_hits)
|
||||
|
||||
report_msg = (
|
||||
f"OpenBMCLAPI 面板v{_version_}-状态\n"
|
||||
f"api版本 {backend_version} commit:{backend_commit}\n"
|
||||
f"实时信息: {online_node} 带宽: {online_bandwidth}Mbps\n"
|
||||
f"负载: {load_str:.2f}% 带宽: {data_bandwidth:.2f}Mbps\n"
|
||||
f"当日请求: {hits_count} 数据量: {data_len}\n"
|
||||
f"请求时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(req_time))}\n"
|
||||
"数据源: https://bd.bangbang93.com/pages/dashboard"
|
||||
)
|
||||
client.debug(report_msg)
|
||||
reply = msg.reply_with(report_msg)
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
def check_is_full_data(data: list) -> bool:
|
||||
return 'user' in data[0]
|
||||
|
||||
|
||||
def display_rank_min(ranks: list, req_time) -> str:
|
||||
cache = io.StringIO()
|
||||
cache.write(f"bmclapi v{_version_}-排名({len(ranks)})")
|
||||
if check_is_full_data(ranks):
|
||||
cache.write("完整\n")
|
||||
for rank in ranks:
|
||||
cache.write('✅' if rank['isEnabled'] else '❌')
|
||||
if 'fullSize' in rank:
|
||||
cache.write('🌕' if rank['fullSize'] else '🌘')
|
||||
if 'version' in rank:
|
||||
cache.write('🟢' if rank['version'] == backend_version else '🟠')
|
||||
cache.write(f"-{rank['index']+1:3}")
|
||||
cache.write(f"|{rank['name']}\n")
|
||||
else:
|
||||
cache.write("无cookie\n")
|
||||
for rank in ranks:
|
||||
cache.write('✅' if rank['isEnabled'] else '❌')
|
||||
cache.write(f"-{rank['index']+1:3}")
|
||||
cache.write(f"|{rank['name']}\n")
|
||||
cache.write(f"请求时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(req_time))}")
|
||||
return cache.getvalue()
|
||||
|
||||
|
||||
def display_rank_full(ranks: list, req_time) -> str:
|
||||
cache = io.StringIO()
|
||||
cache.write(f"bmclapi v{_version_}-排名({len(ranks)})")
|
||||
if check_is_full_data(ranks):
|
||||
cache.write("完整\n")
|
||||
for rank in ranks:
|
||||
# 基本信息
|
||||
cache.write('✅' if rank['isEnabled'] else '❌')
|
||||
if 'fullSize' in rank:
|
||||
cache.write('🌕' if rank['fullSize'] else '🌘')
|
||||
cache.write(f"|{rank['index']+1:3}|")
|
||||
cache.write(f"{rank['name']}")
|
||||
if 'version' in rank:
|
||||
cache.write(f"|{rank['version']}")
|
||||
cache.write('🟢' if rank['version'] == backend_version else '🟠')
|
||||
cache.write('\n')
|
||||
# 用户/赞助信息
|
||||
if ('user' in rank) and (rank['user'] is not None):
|
||||
cache.write(f"所有者:{rank['user']['name']}")
|
||||
if 'sponsor' in rank:
|
||||
cache.write(f"|赞助者:{rank['sponsor']['name']}")
|
||||
if 'sponsor' in rank or ('user' in rank and rank['user'] is not None):
|
||||
cache.write('\n')
|
||||
# 数据信息
|
||||
if 'metric' in rank:
|
||||
hits = format_hit_count(rank['metric']['hits'])
|
||||
data = format_data_size(rank['metric']['bytes'])
|
||||
cache.write(f"hit/data|{hits}|{data}")
|
||||
cache.write('\n')
|
||||
else:
|
||||
cache.write("无cookie\n")
|
||||
for rank in ranks:
|
||||
cache.write('✅' if rank['isEnabled'] else '❌')
|
||||
cache.write(f"-{rank['index']+1:3}")
|
||||
cache.write(f"|{rank['name']}|\n")
|
||||
if 'sponsor' in rank:
|
||||
cache.write(f"赞助者: {rank['sponsor']['name']}|")
|
||||
if 'metric' in rank:
|
||||
cache.write(f"hit/data|{format_hit_count(rank['metric']['hits'])}|{format_data_size(rank['metric']['bytes'])}\n")
|
||||
cache.write(f"请求时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(req_time))}")
|
||||
return cache.getvalue()
|
||||
|
||||
|
||||
def bmcl_rank_general(msg, client):
|
||||
req_time = time.time()
|
||||
# 记录请求时间
|
||||
rank_data = wrap_request("https://bd.bangbang93.com/openbmclapi/metric/rank", msg, client)
|
||||
if rank_data is None:
|
||||
return
|
||||
# 预处理数据
|
||||
for i, r in enumerate(rank_data):
|
||||
r['index'] = i
|
||||
# 显示前3名
|
||||
ranks = rank_data[:3]
|
||||
# ranks = rank_data
|
||||
|
||||
# image = PIL.Image.new("RGB", (100, 100), (255, 255, 255))
|
||||
# img_cache = io.BytesIO()
|
||||
# image.save(img_cache, format="JPEG")
|
||||
# raw_img = img_cache.getvalue()
|
||||
# img_cache.close()
|
||||
|
||||
report_msg = display_rank_full(ranks, req_time)
|
||||
client.debug(report_msg)
|
||||
reply = msg.reply_with(display_rank_full(ranks, req_time))
|
||||
# reply.set_img(raw_img, "image/jpeg", False)
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
def bmcl_rank(msg: IcaNewMessage, client: IcaClient, name: str) -> None:
|
||||
req_time = time.time()
|
||||
# 记录请求时间
|
||||
rank_data = wrap_request("https://bd.bangbang93.com/openbmclapi/metric/rank", msg, client)
|
||||
if rank_data is None:
|
||||
return
|
||||
# 预处理数据
|
||||
for i, r in enumerate(rank_data):
|
||||
r['index'] = i
|
||||
# 搜索是否有这个名字的节点
|
||||
names: List[str] = [r["name"].lower() for r in rank_data]
|
||||
# try:
|
||||
# import regexrs
|
||||
# pattern = regexrs.compile(name)
|
||||
# finds = [pattern.match(n) for n in names]
|
||||
# except Exception as e:
|
||||
finds = [name.lower() in n for n in names]
|
||||
if not any(finds):
|
||||
reply = msg.reply_with(f"未找到名为{name}的节点")
|
||||
client.send_message(reply)
|
||||
return
|
||||
# 如果找到 > 3 个节点, 则提示 不显示
|
||||
counts = [f for f in finds if f]
|
||||
ranks = [rank_data[i] for i, f in enumerate(finds) if f]
|
||||
if len(counts) > 3:
|
||||
if len(counts) > 10:
|
||||
reply = msg.reply_with(f"搜索|{name}|到{len(counts)}个节点, 请用更精确的名字")
|
||||
else:
|
||||
# 4~10 个节点 只显示名称和次序
|
||||
report_msg = display_rank_min(ranks, req_time)
|
||||
reply = msg.reply_with(report_msg)
|
||||
client.send_message(reply)
|
||||
return
|
||||
# 如果找到 <= 3 个节点, 则显示全部信息
|
||||
report_msg = display_rank_full(ranks, req_time)
|
||||
client.debug(report_msg)
|
||||
reply = msg.reply_with(report_msg)
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
def bangbang_img(msg: IcaNewMessage, client: IcaClient) -> None:
|
||||
data = requests.get("https://api.bangbang93.top/api/link")
|
||||
if data.status_code != 200:
|
||||
reply = msg.reply_with(f"请求失败 {data.status_code} {data.reason}")
|
||||
client.send_message(reply)
|
||||
return
|
||||
raw_name = data.url.split("/")[-1]
|
||||
img_suffix = raw_name.split(".")[-1]
|
||||
# mine 映射一下
|
||||
if img_suffix.lower() in ("jpeg", "jpg"):
|
||||
img_suffix = "jpeg"
|
||||
img_name = raw_name[:-len(img_suffix) - 1]
|
||||
img_name = urllib.parse.unquote(img_name)
|
||||
mime_format = f"image/{img_suffix}"
|
||||
client.info(f"获取到随机怪图: {img_name} {img_suffix}")
|
||||
reply = msg.reply_with(img_name)
|
||||
reply.set_img(data.content, mime_format, True)
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
help = """/bmcl -> dashboard
|
||||
/bmcl rank -> all rank
|
||||
/bmcl rank <name> -> rank of <name>
|
||||
/bm93 -> 随机怪图
|
||||
/brrs <name> -> rank of <name>
|
||||
搜索限制:
|
||||
1- 3 显示全部信息
|
||||
4-10 显示状态、名称
|
||||
11+ 不显示
|
||||
"""
|
||||
|
||||
|
||||
def on_ica_message(msg: IcaNewMessage, client: IcaClient) -> None:
|
||||
if not (msg.is_from_self or msg.is_reply):
|
||||
if '\n' in msg.content:
|
||||
return
|
||||
try:
|
||||
if not msg.content.startswith("/b"):
|
||||
return
|
||||
global backend_version
|
||||
if backend_version == "unknown":
|
||||
dashboard_status = wrap_request("https://bd.bangbang93.com/openbmclapi/metric/version", msg, client)
|
||||
if dashboard_status is None:
|
||||
return
|
||||
backend_version = dashboard_status["version"]
|
||||
if msg.content.startswith("/bmcl"):
|
||||
if msg.content == "/bmcl":
|
||||
bmcl_dashboard(msg, client)
|
||||
elif msg.content == "/bmcl rank":
|
||||
bmcl_rank_general(msg, client)
|
||||
elif msg.content.startswith("/bmcl rank") and len(msg.content) > 11:
|
||||
name = msg.content[11:]
|
||||
bmcl_rank(msg, client, name)
|
||||
else:
|
||||
reply = msg.reply_with(help)
|
||||
client.send_message(reply)
|
||||
elif msg.content.startswith("/brrs"):
|
||||
if msg.content == "/brrs":
|
||||
reply = msg.reply_with(help)
|
||||
client.send_message(reply)
|
||||
else:
|
||||
name = msg.content.split(" ")
|
||||
if len(name) > 1:
|
||||
name = name[1]
|
||||
bmcl_rank(msg, client, name)
|
||||
elif msg.content == "/bm93":
|
||||
bangbang_img(msg, client)
|
||||
except: # noqa
|
||||
report_msg = f"bmcl插件发生错误,请呼叫shenjack\n{traceback.format_exc()}"
|
||||
if len(report_msg) > 200:
|
||||
report_msg = report_msg[:200] + "..." # 防止消息过长
|
||||
reply = msg.reply_with(report_msg)
|
||||
client.send_and_warn(reply)
|
||||
|
||||
|
||||
def on_tailchat_message(msg, client) -> None:
|
||||
if not msg.is_reply:
|
||||
if '\n' in msg.content:
|
||||
return
|
||||
try:
|
||||
if not msg.content.startswith("/b"):
|
||||
return
|
||||
global backend_version
|
||||
if backend_version == "unknown":
|
||||
dashboard_status = wrap_request("https://bd.bangbang93.com/openbmclapi/metric/version", msg, client)
|
||||
if dashboard_status is None:
|
||||
return
|
||||
backend_version = dashboard_status["version"]
|
||||
if msg.content.startswith("/bmcl"):
|
||||
if msg.content == "/bmcl":
|
||||
bmcl_dashboard(msg, client)
|
||||
elif msg.content == "/bmcl rank":
|
||||
bmcl_rank_general(msg, client)
|
||||
elif msg.content.startswith("/bmcl rank") and len(msg.content) > 11:
|
||||
name = msg.content[11:]
|
||||
bmcl_rank(msg, client, name)
|
||||
else:
|
||||
reply = msg.reply_with(help)
|
||||
client.send_message(reply)
|
||||
elif msg.content.startswith("/brrs"):
|
||||
if msg.content == "/brrs":
|
||||
reply = msg.reply_with(help)
|
||||
client.send_message(reply)
|
||||
else:
|
||||
name = msg.content.split(" ")
|
||||
if len(name) > 1:
|
||||
name = name[1]
|
||||
bmcl_rank(msg, client, name)
|
||||
elif msg.content == "/bm93":
|
||||
bangbang_img(msg, client)
|
||||
except: # noqa
|
||||
report_msg = f"bmcl插件发生错误,请呼叫shenjack\n{traceback.format_exc()}"
|
||||
if len(report_msg) > 200:
|
||||
report_msg = report_msg[:200] + "..." # 防止消息过长
|
||||
reply = msg.reply_with(report_msg)
|
||||
client.send_and_warn(reply)
|
||||
|
||||
def on_config() -> Tuple[str, str]:
|
||||
return (
|
||||
"bmcl.toml",
|
||||
"""cookie = \"填写你的 cookie\""""
|
||||
)
|
4
plugins/md5/.gitignore
vendored
Normal file
4
plugins/md5/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
input.txt
|
||||
node_modules
|
||||
package.json
|
||||
package-lock.json
|
1
plugins/md5/assets/gAd.md
Normal file
1
plugins/md5/assets/gAd.md
Normal file
@ -0,0 +1 @@
|
||||
@@ABMECIGUB@OK@CHBAA@FCMFNBEABCICEG@DJDGBGHMDALBAHHEDIEFB@AACFLCFDC@ABIC@DBLIABFPCFDCTD@B@@ID@@EHDI@GDGFDAH@ABBAGBBF@PKALADHG@AAOC@EJ@@FCHC@MLKBAHBGDAKDGA\C@A@FHE@TTHWCGHJBBAFBSGCAAF@I@D@A@AC@AGIFXHBAEU@@@AMTGFF@AAIBJGAKAAAE@BJIMH@CAAHAABC@DD@L@AABEDFECBCT@BGED@GDF@CFDDGH@ACDBDH@DAFOBBIKD@ICJGCAH@GBADBDGDH@@DIY@BFDEOEAS@G@DIN@GABNHECOCBEAHPBC@AIBDAFBDWB@GCAB@EACD@DE@@FFDB@JBFAENJ@L@JMM@R@JD@@DBCFCDAB@@@EBABCEA@PAEBKB@@@DXBCACFABCDFBIAFDBAEAFCY@LB@EHH@B@BIIDFGDOCH@EB@LFCCCDCE@BF@DG@LNDQKKCC@FACDFCGBCSC@CLI@CHLBHELHA@BCA@AABSBBBNBFI@MBCMB@UB@PNA@DEJ_GOD@DKDBIMC@BMBBADFVEB@DCBA@AG@HE@FDCE@AC@EBBL]@AF@@A@FBHBECJAFDAMBA@EBEICGFDCEBADMC@LC@FH@D@@EEBAFPAHIAAACBBD@BBBCCDCB@GDHCMHAGAGA@HVBFCRCDHCJBERJBBEBEIGOAD@WBDCDKAACK@BAMAOADFE@@EUFAF@NKICDFBFWLAIICBABBKWBGLLZAGHBA@AB@A@DEBG@HER@CDAO@@FCDA@EOFB@DBOJRAAAABCAFFDBAAKDB@ACD@FC@I@@EB@HHCBGCCLCB@BDBA@BFBBHNIA@DDQA@@@EAO@EHIGBOAFSAZCGJRCN@CMJL@CACE@HCIDTBGSFAA@AA@DFBA@J@DJDGEBEFBBHIJ@GCFGDLBA@@DBBD@FA@TBCAIHAJ@CCLHDA@DHFF@HJCF@DEAJE@JGI@ABFJEDKD@DGEICHECPMDBIELA@D[F@HDGDABBND@CAKHBCCDOAJACEE@CIDFVALABQAC@P@HBBBKBA@AM@@RCAC@PKD@HC@@IABD@PCFFA@NQD@DBJFJCAAA@HACFFBAAJ@AM@GDBECBADD@D@@CNK@@FPEJGDATACFJQANKADFA@LKVGEAJQAAB@@KDA@C@DCAEBAADBNHCCE@@@AACGED@JBBFBHANAFMAASHDC@DBIJJHDECAD@FDAFECDGC@GHQB@@BBCEFEXABBA@@EIIJF@@DEC@AAQCA@A@CIBGNACK@CHLEFBCBD@BOIB@BJDEGFD@AL@INECCAUAXHBBEDWBBA@BBLDADD@BHB@D@HHFB@GGAKABAAEGCKFJHJC@@@HECDDVBL@BCLB@DEEE@BDFN[@DPA@DF@AAFF@B@EGEDG@ABBBFCAAA@FPAJBBACBBFGA@@@D@LOOBBQDGDOJRACGABCUCAHGBF@BBKDAA@FCCO[AAIALA@SKHKB@ABRLDDBC@CAEAFBGFCLA@DBFFB@A@EG]DEGEBQWKMB@NBBMEADKI^@@@KHED@P@CC@FACZNADAM@IADC@V@@@A@IO@CKEEKCBLIBCBG@AEBCANA@BJAFBAVCLDGHCKPDEDLIFHBL@@FF@DH@ABDGFDF@HLDIBAEBCF@@BLFBA@AAFBCDBBFA@FBL@AA@AABBCFEEAFCJUICDI@@@I@AA@FBBDFE@C@AKAEBBBC@EGAEKACA@@B@AGHMHHD@ACGABHBEFVCT@FGADC@DADGDADLPNGBAAAEACF@D@PAH@PELHAEJ@CCKEICAAG@DNDE@CDBF@AEJK@O@DEC@FCICLDNHHDBCANBCE@AGLCDGCHCBCCCA@PECE@K@AJJ@QBNBO@@DODCEBNLFBACBEBFABJCFBOBPKRBB@EAFACGGIC@CGG^DDAFVACFHBBACAJDP@GDM@ABB@GG@@@B@K@EBFFAFB@DGB@FANBH@BQDE@FEBBGJ@FBGBAOAI@DQEJA@KE@ATC@JUG@QADH@@HAB@DDA@JCFFB@AAOCL@MPBAC@@CAQCCAA@@DIUHG@EBUEAIHSERCJK@@GTAD@N@AHRCMEL@HCA@@AICAB@HI@AF@ABLAEW@GBZ@CFNKDCHN@@BDO@@CFL@NDBN@L@AUBHBAEFEEQGAKHQ@@@CAB@KIOCA@CF@P@MA@DLBABARQBA@KCAIDGIDG@JCCBBFBFKED@ABEFBBAHGDBDBBMBDFBDBDDABABD@DPCF\DB@G@DD@E@G@CV@EBF@O@@CA@BQFDBLAB@BDGHF@@@@BI@DADEBBCDEGCD@A_@EAKACCA@CICDEPKGCEADNABFDCG@DFCBPE@FEDECBAFGBAGCBH@JDAENADAF@CBHACBA@@BCCQCF@FNNBAD@GABKAEBFACGCBFKCGOEBG@DBI@B@GBAJADIOWA@KKLCGFAABAR@TH@BBDAF@DMDA@AHAABREIABAHCED@@EAFHHEBEDSEABNMBAOREEJ@A@ALACIGHFBNPIEDDFDF@@KBHCGBBBOBCAILBFHDMATBDAD@ADFBWHJ@@BACCRC@FJAB@DCFM@IBHCIAF@ED@HAG@@@ECDHBAAHBEKDC@@@BCENC@C@ACDEBDG@A@A@K@BBCNOK@FBCAFIAPFECBBIOEGHDACGBB@@J@ADEECBEG@AACEADD@@JEGACHJ@BDE@JE@IFAQGEBFDDDKUECEEHFD_@CDCG@BJALEB@B@@QEKE@LKBD@ABW@QBNNAL@B@KCADDADA@BD@QBEQ@DQUC@EC@BOGB@AM@DGBAANEIAGFNPEICA@CHEDGDCD@A@LEP@N@CEMFJ@@BIACB@NIBJG@NG^A@EAIMCDHH@BCFEPOJGC@CSNAAAJ@FCGT@FAAOKHXFVFACJHFMAADAA@LA@MHLKTGSZ@HAAJ@AABD@BCBEPDHCJJB@JAABKEBCCEH@D@DBHIAACABAGBBB@EGCACFUDFC@LB@AAFHDBC@G@E@DQD@DKD@CFEBHABANEQ@CCLDAGCAHBA@@@CKC@DAHCGEMJOBGZ@A@CB@AD@ECQ@DAZNN@ACC@@CECDCJAFNJRGBGG@NCBJ@@BI@DBIDCO@B@CCDAAMTGGGCAKDGG@A@ALBA@@FDQ@BA@AB@AVKDJED@@@CDLFC@@C@PCBMCDK@IEHCEAC@CRCOBCAFAGEFUK@@BADGAUFBFIA@H@AI@DDB@BGAAHLVC@KCKBDCBBACHC@A@NI@BEBDIFVF@AGBCIELDIZABAJAFD@AUKS@DJ@@DD@BMHABFBE@IBBDBADAM@GMDBHD@@EAD@BEADGPGGAAFEEABBECKIBAW@BEEQE@DD@FCCAEHJFB@C@E@BMJCB@ALGD@CBC@F@AFJDECAAA@BEO@EBNACDCUH@@K@A@DB@BFECFMAEHDBAEEADFB@EE@CI@ABDBDCAD@A@@B@JCB@FAGJCK@GG@ABFLQ@BHDEHOAB@DBIDSBDBIVA@FD@@ABCAAAA
|
176
plugins/md5/assets/zh.json
Normal file
176
plugins/md5/assets/zh.json
Normal file
@ -0,0 +1,176 @@
|
||||
{
|
||||
"recover": "[1]回复体力[2]点",
|
||||
"sklAbsorb": "[0]发起[吸血攻击]",
|
||||
"sklAccumulate": "[0]开始[聚气]",
|
||||
"sklAccumulated": "[1]攻击力上升",
|
||||
"sklAccumulateCancel": "[1]的[聚气]被打消了",
|
||||
"sklAssassinate1": "[0][潜行]到[1]身后",
|
||||
"sklAssassinate2": "[0]发动[背刺]",
|
||||
"dodge": "[0][回避]了攻击(通用)",
|
||||
"sklAssassinateFailed": "[0]的[潜行]被识破",
|
||||
"sklBerserkEnd": "[1]从[狂暴]中解除",
|
||||
"sklBerserkAttack": "[0]发起[狂暴攻击]",
|
||||
"sklBerserkHit": "[1]进入[狂暴]状态",
|
||||
"sklBerserk": "[0]使用[狂暴术]",
|
||||
"sklCharge": "[0]开始[蓄力]",
|
||||
"sklChargeCancel": "[1]的[蓄力]被中止了",
|
||||
"sklCharmEnd": "[1]从[魅惑]中解除",
|
||||
"sklCharm": "[0]使用[魅惑]",
|
||||
"sklCharmHit": "[1]被[魅惑]了",
|
||||
"sklClone": "[0]使用[分身]",
|
||||
"sklCloned": "出现一个新的[1]",
|
||||
"sklCritical": "[0]发动[会心一击]",
|
||||
"sklCurseDamage": "[诅咒]使伤害加倍",
|
||||
"sklCurseEnd": "[1]从[诅咒]中解除",
|
||||
"sklCurseHit": "[1]被[诅咒]了",
|
||||
"sklCurse": "[0]使用[诅咒]",
|
||||
"sklDisperse": "[0]使用[净化]",
|
||||
"sklExchange": "[0]使用[生命之轮]",
|
||||
"sklExchanged": "[1]的体力值与[0]互换",
|
||||
"sklFire": "[0]使用[火球术]",
|
||||
"sklHalf": "[0]使用[瘟疫]",
|
||||
"sklHalfDamage": "[1]体力减少[2]%",
|
||||
"sklHasteEnd": "[1]从[疾走]中解除",
|
||||
"sklHaste": "[0]使用[加速术]",
|
||||
"sklHasteHit": "[1]进入[疾走]状态",
|
||||
"sklHeal": "[0]使用[治愈魔法]",
|
||||
"sklIceEnd": "[1]从[冰冻]中解除",
|
||||
"sklIceHit": "[1]被[冰冻]了",
|
||||
"sklIce": "[0]使用[冰冻术]",
|
||||
"sklIron": "[0]发动[铁壁]",
|
||||
"sklIrond": "[0]防御力大幅上升",
|
||||
"sklIronCancel": "[1]的[铁壁]被打消了",
|
||||
"sklIronEnd": "[0]从[铁壁]中解除",
|
||||
"sklPoisonDamage": "[1][毒性发作]",
|
||||
"sklPoisonEnd": "[1]从[中毒]中解除",
|
||||
"sklPoisonHit": "[1][中毒]",
|
||||
"sklPoison": "[0][投毒]",
|
||||
"sklQuake": "[0]使用[地裂术]",
|
||||
"SklRapid": "[0]发起攻击",
|
||||
"SklRapidNext": "[0][连击]",
|
||||
"sklRevive": "[0]使用[苏生术]",
|
||||
"sklRevived": "[1][复活]了",
|
||||
"sklPossess": "[0]使用[附体]",
|
||||
"sklShadow": "[0]使用[幻术]",
|
||||
"sklShadowName": "幻影",
|
||||
"sklShadowed": "召唤出[1]",
|
||||
"sklSlowEnd": "[1]从[迟缓]中解除",
|
||||
"sklSlow": "[0]使用[减速术]",
|
||||
"sklSlowHit": "[1]进入[迟缓]状态",
|
||||
"sklExplode": "[0]使用[自爆]",
|
||||
"sklSummon": "[0]使用[血祭]",
|
||||
"sklSummonName": "使魔",
|
||||
"sklSummoned": "召唤出[1]",
|
||||
"sklThunder": "[0]使用[雷击术]",
|
||||
"sklThunderEnd": "[0][回避]了攻击(雷击)",
|
||||
"benchmarking": "实力评估中...[2]%",
|
||||
"benchmarkRatio": "》 胜率: [2]%",
|
||||
"benchmarkScore": "》 实力评分: [2]",
|
||||
"benchmarkSkill": "频率: [2]%",
|
||||
"searchInvalid": "错误,目前最多支持8000人搜索",
|
||||
"searchStart": "搜索开始...",
|
||||
"searchEnd": "搜索结束",
|
||||
"searchFailed": "但是一无所获",
|
||||
"bossName_aokiji": "青雉",
|
||||
"sklAokijiDefend": "[0][吸收]所有冰冻伤害",
|
||||
"sklAokijiIceAge": "[0]使用[冰河时代]",
|
||||
"bossName_conan": "柯南",
|
||||
"sklConanKillUnknown": "[0]在一间密室中发现了一具无名尸体",
|
||||
"sklConanThinking": "[0]正在进行推理",
|
||||
"sklConanThinkingFinish": "[0]推理完毕",
|
||||
"sklConanThinkingFinish2": "真相只有一个",
|
||||
"sklConanThinkingFinish3": "凶手就是你",
|
||||
"sklConanKillLast": "[1]",
|
||||
"sklConanKill": "[0]在一间密室中发现了[1]的尸体",
|
||||
"bossName_covid": "新冠病毒",
|
||||
"sklCovidDamage": "[1][肺炎]发作",
|
||||
"sklCovidICU": "[1]在重症监护室无法行动",
|
||||
"sklCovidStayHome": "[1]在家中自我隔离",
|
||||
"sklCovidInfect": "[0]和[1]近距离接触",
|
||||
"sklCovidPrevent": "但[1]没被感染",
|
||||
"sklAttack": "[0]发起攻击",
|
||||
"sklCovidMutate": "[1]所感染的病毒发生变异",
|
||||
"sklCovidHit": "[1]感染了[新冠病毒]",
|
||||
"bossName_ikaruga": "斑鸠",
|
||||
"sklIkarugaDefend": "[0][吸收]所有奇数伤害",
|
||||
"sklIkarugaAttack": "[0]使用[能量释放]",
|
||||
"bossName_lazy": "懒癌",
|
||||
"sklLazyDamage": "[1][懒癌]发作",
|
||||
"sklLazySkipTurn1": "[0]打开了[Steam]",
|
||||
"sklLazySkipTurn2": "[0]打开了[守望先锋]",
|
||||
"sklLazySkipTurn3": "[0]打开了[文明6]",
|
||||
"sklLazySkipTurn4": "[0]打开了[英雄联盟]",
|
||||
"sklLazySkipTurn5": "[0]打开了[微博]",
|
||||
"sklLazySkipTurn6": "[0]打开了[朋友圈]",
|
||||
"sklLazySkipTurn0": "这回合什么也没做",
|
||||
"sklLazyHit": "[1]感染了[懒癌]",
|
||||
"bossName_mario": "马里奥",
|
||||
"bossMarioGrow10": "[0]得到[蘑菇]",
|
||||
"bossMarioGrow11": "[0]攻击力上升",
|
||||
"bossMarioGrow20": "[0]得到[火焰花]",
|
||||
"bossMarioGrow21": "[0]学会[火球术]",
|
||||
"bossMarioGrow30": "[0]得到[奖命蘑菇]",
|
||||
"bossMarioLife": "[0]还剩[2]条命",
|
||||
"bossMarioRevive": "[0]满血复活",
|
||||
"bossName_mosquito": "蚊",
|
||||
"bossName_saitama": "一拳超人",
|
||||
"saitamaHungry": "[0]觉得有点饿",
|
||||
"saitamaLeave": "[0]离开了战场",
|
||||
"bossName_slime": "史莱姆",
|
||||
"sklSlimeSpawn": "[0][分裂]",
|
||||
"sklSlimeSpawned": "分成了[0] 和 [1]",
|
||||
"bossName_sonic": "索尼克",
|
||||
"bossName_yuri": "尤里",
|
||||
"sklYuriControl": "[0]使用[心灵控制]",
|
||||
"endMessage": "你已经玩了[0]局了",
|
||||
"continueGame": "继续游戏",
|
||||
"navigationLink": "navigation.html",
|
||||
"errorMaxPlayer": "错误,目前最多支持1000人PK",
|
||||
"errorMinPlayer": "错误,请至少输入两行名字",
|
||||
"welcome": "名字竞技场",
|
||||
"welcome2": "(MD5大作战10周年纪念)",
|
||||
"winnerName": "胜者",
|
||||
"score": "得分",
|
||||
"killedCount": "击杀",
|
||||
"killerName": "致命一击",
|
||||
"loserName": "败者",
|
||||
"returnTitle": "返回",
|
||||
"shareTitle": "分享",
|
||||
"helpTitle": "帮助",
|
||||
"HP": "HP",
|
||||
"detail": " 攻 [] 防 [] 速 [] 敏 [] 魔 [] 抗 [] 智 []",
|
||||
"inputTitle": "名字竞技场",
|
||||
"inputPlaceholder": "修改by shenjackyuanjie&超导体元素\n\n版本: latest\n可能会有一些问题, 稳定版请使用根目录下版本",
|
||||
"startFight": "开 始",
|
||||
"closeTitle": "关闭",
|
||||
"fastTitle": "快进",
|
||||
"challengeLabel": "挑战Boss",
|
||||
"selectBossHint": "选择Boss",
|
||||
"win": "[2]获得胜利",
|
||||
"minionDie": "[1]消失了",
|
||||
"damage": "[1]受到[2]点伤害",
|
||||
"die": "[1]被击倒了",
|
||||
"sklMagicAttack": "[0]发起攻击",
|
||||
"sklCounter": "[0]发起[反击]",
|
||||
"defend": "[0][防御]",
|
||||
"sklHide": "[0]发动[隐匿]",
|
||||
"sklMerge": "[0][吞噬]了[1]",
|
||||
"sklMerged": "[0]属性上升",
|
||||
"sklProtect": "[0][守护][1]",
|
||||
"sklReflect": "[0]使用[伤害反弹]",
|
||||
"sklReraise": "[0]使用[护身符]抵挡了一次死亡",
|
||||
"sklUpgrade": "[0]做出[垂死]抗争",
|
||||
"sklUpgraded": "[0]所有属性上升",
|
||||
"sklUpgradeCancel": "[1]的[垂死]属性被打消",
|
||||
"sklZombieName": "丧尸",
|
||||
"sklZombie": "[0][召唤亡灵]",
|
||||
"sklZombied": "[2]变成了[1]",
|
||||
"weaponDeathNoteAtk": "[0]在[死亡笔记]写下[1]的名字",
|
||||
"weaponRModifierUse": "[0]使用[属性修改器]",
|
||||
"weaponS11_0": "[0]在促销日[购买]了武器",
|
||||
"weaponS11_1": "但是并没有什么用",
|
||||
"weaponS11_2": "增加了[2]点",
|
||||
"weaponS11Done1": "[0]信用卡刷爆",
|
||||
"weaponS11Done3": "[0]砍下了自己的左手",
|
||||
"weaponS11Done2": "[0]砍下了自己的右手"
|
||||
}
|
230
plugins/md5/md5-api.js
Normal file
230
plugins/md5/md5-api.js
Normal file
@ -0,0 +1,230 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
var md5_module = require("./md5.js");
|
||||
/**
|
||||
*
|
||||
* @param names 原始的输入框输入
|
||||
* @returns 对战结果
|
||||
*/
|
||||
function fight(names) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
// 检查一下输入是否合法
|
||||
// 比如里面有没有 !test!
|
||||
if (names.indexOf("!test!") !== -1) {
|
||||
throw new Error("你怎么在对战输入里加 !test!(恼)\n${names}");
|
||||
}
|
||||
return [4 /*yield*/, md5_module.fight(names)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 对于胜率/评分的输入检查
|
||||
* @param names
|
||||
* @returns
|
||||
*/
|
||||
function test_check(names) {
|
||||
var have_test = names.trim().startsWith("!test!");
|
||||
return have_test;
|
||||
}
|
||||
/**
|
||||
* 测量胜率
|
||||
* @param names 原始的输入框输入
|
||||
* @param round 战斗的回合数
|
||||
* @returns 胜率结果
|
||||
*/
|
||||
function win_rate(names, round) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
// 检查 round 是否合法
|
||||
if (round <= 0) {
|
||||
throw new Error("round 必须大于 0");
|
||||
}
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在胜率输入里丢了 !test!(恼)\n${names}");
|
||||
}
|
||||
return [4 /*yield*/, md5_module.win_rate(names, round)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param names 原始的输入框输入
|
||||
* @param callback 用于接收胜率的回调函数
|
||||
* @returns 胜率结果
|
||||
*/
|
||||
function win_rate_callback(names, callback) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在胜率输入里丢了 !test!(恼)\n${names}");
|
||||
}
|
||||
return [4 /*yield*/, md5_module.win_rate_callback(names, callback)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function score(names, round) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
// 检查 round 是否合法
|
||||
if (round <= 0) {
|
||||
throw new Error("round 必须大于 0");
|
||||
}
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在分数输入里丢了 !test!(恼)\n${names}");
|
||||
}
|
||||
return [4 /*yield*/, md5_module.score(names, round)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function score_callback(names, callback) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在分数输入里加 !test!(恼)\n${names}");
|
||||
}
|
||||
return [4 /*yield*/, md5_module.score_callback(names, callback)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function run_any(names, round) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0: return [4 /*yield*/, md5_module.run_any(names, round)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
var out_limit = 1000;
|
||||
function wrap_any(names, round) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var result, win_rate_1, win_rate_str, output_str_1, output_datas_1, win_rate_2, output_str_2, output_datas_2;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0: return [4 /*yield*/, run_any(names, round)];
|
||||
case 1:
|
||||
result = _a.sent();
|
||||
if ('message' in result) {
|
||||
// 对战结果
|
||||
return [2 /*return*/, "\u8D62\u5BB6:|".concat(result.source_plr, "|")];
|
||||
}
|
||||
else if ('win_count' in result) {
|
||||
win_rate_1 = result.win_count * 100 / round;
|
||||
win_rate_str = win_rate_1.toFixed(4);
|
||||
output_str_1 = "\u6700\u7EC8\u80DC\u7387:|".concat(win_rate_str, "%|(").concat(round, "\u8F6E)");
|
||||
// 每 500 轮, 输出一次
|
||||
if (round > out_limit) {
|
||||
output_datas_1 = [];
|
||||
result.raw_data.forEach(function (data, index) {
|
||||
if (data.round % out_limit === 0) {
|
||||
output_datas_1.push(data);
|
||||
}
|
||||
});
|
||||
output_datas_1.forEach(function (data, index) {
|
||||
var win_rate = data.win_count * 100 / data.round;
|
||||
output_str_1 += "\n".concat(win_rate.toFixed(2), "%(").concat(data.round, ")");
|
||||
});
|
||||
}
|
||||
return [2 /*return*/, output_str_1];
|
||||
// } else if ('score' in result) {
|
||||
}
|
||||
else {
|
||||
win_rate_2 = (result.score * 10000 / round).toFixed(2);
|
||||
output_str_2 = "\u5206\u6570:|".concat(win_rate_2, "|(").concat(round, "\u8F6E)");
|
||||
if (round > out_limit) {
|
||||
output_datas_2 = [];
|
||||
result.raw_data.forEach(function (data, index) {
|
||||
if (data.round % out_limit === 0) {
|
||||
output_datas_2.push(data);
|
||||
}
|
||||
});
|
||||
output_datas_2.forEach(function (data, index) {
|
||||
var win_rate = (data.score / data.round * 10000).toFixed(2);
|
||||
output_str_2 += "\n".concat(win_rate, "(").concat(data.round, ")");
|
||||
});
|
||||
}
|
||||
return [2 /*return*/, output_str_2];
|
||||
}
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function main() {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var fs, path, names, start_time, result, end_time;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
fs = require("fs");
|
||||
path = require("path");
|
||||
names = fs.readFileSync(path.resolve(__dirname, "input.txt"), "utf-8");
|
||||
start_time = Date.now();
|
||||
return [4 /*yield*/, wrap_any(names, 10000)];
|
||||
case 1:
|
||||
result = _a.sent();
|
||||
end_time = Date.now();
|
||||
console.log(result);
|
||||
console.log("Node.js \u8017\u65F6: ".concat(end_time - start_time, " ms"));
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
main();
|
207
plugins/md5/md5-api.ts
Normal file
207
plugins/md5/md5-api.ts
Normal file
@ -0,0 +1,207 @@
|
||||
const md5_module = require("./md5.js");
|
||||
// import * as md5_module from "./md5.js";
|
||||
|
||||
/**
|
||||
* 对战结果的数据结构
|
||||
* 其实只有 source_plr 是有用的, 是赢家之一
|
||||
*/
|
||||
type FightResult = {
|
||||
message: string;
|
||||
source_plr: string;
|
||||
target_plr: string;
|
||||
affect: string | number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 每一行具体的胜率结果
|
||||
*/
|
||||
type WinRate = {
|
||||
round: number;
|
||||
win_count: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 胜率的数据结构
|
||||
*/
|
||||
type WinRateResult = {
|
||||
win_count: number;
|
||||
raw_data: WinRate[];
|
||||
};
|
||||
|
||||
/**
|
||||
* 用于接收胜率的回调函数
|
||||
* 返回一个 bool, true 表示继续, false 表示停止
|
||||
*/
|
||||
type WinRateCallback = (run_round: number, win_count: number) => boolean;
|
||||
|
||||
/**
|
||||
* 分数的数据结构
|
||||
*/
|
||||
type Score = {
|
||||
round: number;
|
||||
score: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 分数的数据结构
|
||||
*/
|
||||
type ScoreResult = {
|
||||
score: number;
|
||||
raw_data: Score[];
|
||||
};
|
||||
|
||||
/**
|
||||
* 用于接收分数的回调函数
|
||||
* 返回一个 bool, true 表示继续, false 表示停止
|
||||
*/
|
||||
type ScoreCallback = (run_round: number, score: number) => boolean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param names 原始的输入框输入
|
||||
* @returns 对战结果
|
||||
*/
|
||||
async function fight(names: string): Promise<FightResult> {
|
||||
// 检查一下输入是否合法
|
||||
// 比如里面有没有 !test!
|
||||
if (names.indexOf("!test!") !== -1) {
|
||||
throw new Error("你怎么在对战输入里加 !test!(恼)\n${names}");
|
||||
}
|
||||
return await md5_module.fight(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于胜率/评分的输入检查
|
||||
* @param names
|
||||
* @returns
|
||||
*/
|
||||
function test_check(names: string): boolean {
|
||||
const have_test = names.trim().startsWith("!test!");
|
||||
|
||||
return have_test;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测量胜率
|
||||
* @param names 原始的输入框输入
|
||||
* @param round 战斗的回合数
|
||||
* @returns 胜率结果
|
||||
*/
|
||||
async function win_rate(names: string, round: number): Promise<WinRateResult> {
|
||||
// 检查 round 是否合法
|
||||
if (round <= 0) {
|
||||
throw new Error("round 必须大于 0");
|
||||
}
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在胜率输入里丢了 !test!(恼)\n${names}");
|
||||
}
|
||||
return await md5_module.win_rate(names, round);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param names 原始的输入框输入
|
||||
* @param callback 用于接收胜率的回调函数
|
||||
* @returns 胜率结果
|
||||
*/
|
||||
async function win_rate_callback(
|
||||
names: string,
|
||||
callback: WinRateCallback,
|
||||
): Promise<WinRateResult> {
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在胜率输入里丢了 !test!(恼)\n${names}");
|
||||
}
|
||||
return await md5_module.win_rate_callback(names, callback);
|
||||
}
|
||||
|
||||
async function score(names: string, round: number): Promise<ScoreResult> {
|
||||
// 检查 round 是否合法
|
||||
if (round <= 0) {
|
||||
throw new Error("round 必须大于 0");
|
||||
}
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在分数输入里丢了 !test!(恼)\n${names}");
|
||||
}
|
||||
return await md5_module.score(names, round);
|
||||
}
|
||||
|
||||
async function score_callback(
|
||||
names: string,
|
||||
callback: ScoreCallback,
|
||||
): Promise<ScoreResult> {
|
||||
if (!test_check(names)) {
|
||||
throw new Error("你怎么在分数输入里加 !test!(恼)\n${names}");
|
||||
}
|
||||
return await md5_module.score_callback(names, callback);
|
||||
}
|
||||
|
||||
async function run_any(names: string, round: number): Promise<FightResult | WinRateResult | ScoreResult> {
|
||||
return await md5_module.run_any(names, round);
|
||||
}
|
||||
|
||||
const out_limit: number = 1000;
|
||||
|
||||
async function wrap_any(names: string, round: number): Promise<string> {
|
||||
const result = await run_any(names, round);
|
||||
if ('message' in result) {
|
||||
// 对战结果
|
||||
return `赢家:|${result.source_plr}|`;
|
||||
} else if ('win_count' in result) {
|
||||
// 胜率结果
|
||||
const win_rate = result.win_count * 100 / round;
|
||||
let win_rate_str = win_rate.toFixed(4);
|
||||
let output_str = `最终胜率:|${win_rate_str}%|(${round}轮)`;
|
||||
// 每 500 轮, 输出一次
|
||||
if (round > out_limit) {
|
||||
// 把所有要找的数据拿出来
|
||||
let output_datas: WinRate[] = [];
|
||||
result.raw_data.forEach((data, index) => {
|
||||
if (data.round % out_limit === 0) {
|
||||
output_datas.push(data);
|
||||
}
|
||||
});
|
||||
output_datas.forEach((data, index) => {
|
||||
const win_rate = data.win_count * 100 / data.round;
|
||||
output_str += `\n${win_rate.toFixed(2)}%(${data.round})`;
|
||||
});
|
||||
}
|
||||
return output_str;
|
||||
// } else if ('score' in result) {
|
||||
} else {
|
||||
// 分数结果其实还是个胜率, 不过需要 * 100
|
||||
const win_rate = (result.score * 10000 / round).toFixed(2);
|
||||
let output_str = `分数:|${win_rate}|(${round}轮)`;
|
||||
if (round > out_limit) {
|
||||
// 把所有要找的数据拿出来
|
||||
let output_datas: Score[] = [];
|
||||
result.raw_data.forEach((data, index) => {
|
||||
if (data.round % out_limit === 0) {
|
||||
output_datas.push(data);
|
||||
}
|
||||
});
|
||||
output_datas.forEach((data, index) => {
|
||||
const win_rate = (data.score / data.round * 10000).toFixed(2);
|
||||
output_str += `\n${win_rate}(${data.round})`;
|
||||
});
|
||||
}
|
||||
return output_str;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// 从相对位置导入内容
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const names = fs.readFileSync(path.resolve(__dirname, "input.txt"), "utf-8");
|
||||
// const result = await fight(names);
|
||||
// const result = await md5_module.run_any(names, 50000);
|
||||
// console.log(`赢家:|${result.source_plr}|`);
|
||||
const start_time = Date.now();
|
||||
const result = await wrap_any(names, 10000);
|
||||
const end_time = Date.now();
|
||||
console.log(result);
|
||||
console.log(`Node.js 耗时: ${end_time - start_time} ms`);
|
||||
}
|
||||
|
||||
main();
|
21903
plugins/md5/md5.js
Normal file
21903
plugins/md5/md5.js
Normal file
File diff suppressed because one or more lines are too long
208
plugins/name_utils/__init__.py
Normal file
208
plugins/name_utils/__init__.py
Normal file
@ -0,0 +1,208 @@
|
||||
import io
|
||||
|
||||
sklname = [
|
||||
"火球术",
|
||||
"冰冻术",
|
||||
"雷击术",
|
||||
"地裂术",
|
||||
"吸血攻击",
|
||||
"投毒",
|
||||
"连击",
|
||||
"会心一击",
|
||||
"瘟疫",
|
||||
"生命之轮",
|
||||
"狂暴术",
|
||||
"魅惑",
|
||||
"加速术",
|
||||
"减速术",
|
||||
"诅咒",
|
||||
"治愈魔法",
|
||||
"苏生术",
|
||||
"净化",
|
||||
"铁壁",
|
||||
"蓄力",
|
||||
"聚气",
|
||||
"潜行",
|
||||
"血祭",
|
||||
"分身",
|
||||
"幻术",
|
||||
"防御",
|
||||
"守护",
|
||||
"伤害反弹",
|
||||
"护身符",
|
||||
"护盾",
|
||||
"反击",
|
||||
"吞噬",
|
||||
"召唤亡灵",
|
||||
"垂死抗争",
|
||||
"隐匿",
|
||||
"sklvoid1",
|
||||
"sklvoid2",
|
||||
"sklvoid3",
|
||||
"sklvoid4",
|
||||
"sklvoid5",
|
||||
]
|
||||
|
||||
prop_names = [
|
||||
"HP",
|
||||
"攻",
|
||||
"防",
|
||||
"速",
|
||||
"敏",
|
||||
"魔",
|
||||
"抗",
|
||||
"智",
|
||||
"八围",
|
||||
]
|
||||
|
||||
|
||||
class Player:
|
||||
def __init__(self) -> None:
|
||||
self.name = ""
|
||||
self.team = ""
|
||||
self.val = [i for i in range(0, 256)]
|
||||
self.name_base = [0] * 128
|
||||
self.name_str = [0] * 256
|
||||
self.team_str = [0] * 256
|
||||
self.name_len = 0
|
||||
self.team_len = 0
|
||||
self.name_prop = [0] * 8
|
||||
self.skl_id = [i for i in range(0, 40)]
|
||||
self.skl_freq = [0] * 40
|
||||
|
||||
def load(self, raw_name: str):
|
||||
if raw_name == "":
|
||||
print("错误:输入不能为空。")
|
||||
return False
|
||||
if raw_name.count("@") > 1:
|
||||
print("错误:无法分割名字与战队名,请检查输入。")
|
||||
return False
|
||||
name_lst = list(raw_name.rpartition("@"))
|
||||
if len(name_lst[0]) > 256 or len(name_lst[2]) > 256:
|
||||
print("错误:名字或战队名长度过大。")
|
||||
return False
|
||||
if name_lst[1] == "@":
|
||||
if name_lst[2] == "":
|
||||
name_lst[2] = name_lst[0]
|
||||
else:
|
||||
name_lst[0] = name_lst[2]
|
||||
name_bytes = name_lst[0].encode(encoding="utf-8")
|
||||
team_bytes = name_lst[2].encode(encoding="utf-8")
|
||||
self.name = name_lst[0]
|
||||
self.team = name_lst[2]
|
||||
self.name_len = len(name_bytes)
|
||||
self.team_len = len(team_bytes)
|
||||
for i in range(self.name_len):
|
||||
self.name_str[i + 1] = name_bytes[i]
|
||||
for i in range(self.team_len):
|
||||
self.team_str[i + 1] = team_bytes[i]
|
||||
self.name_len += 1
|
||||
self.team_len += 1
|
||||
|
||||
s = 0
|
||||
for i in range(256):
|
||||
s += self.team_str[i % self.team_len] + self.val[i]
|
||||
s %= 256
|
||||
self.val[i], self.val[s] = self.val[s], self.val[i]
|
||||
|
||||
for i in range(2):
|
||||
s = 0
|
||||
for j in range(256):
|
||||
s += self.name_str[j % self.name_len] + self.val[j]
|
||||
s %= 256
|
||||
self.val[j], self.val[s] = self.val[s], self.val[j]
|
||||
s = 0
|
||||
for i in range(256):
|
||||
m = ((self.val[i] * 181) + 160) % 256
|
||||
if m >= 89 and m < 217:
|
||||
self.name_base[s] = m & 63
|
||||
s += 1
|
||||
|
||||
propcnt = 0
|
||||
r = self.name_base[0:32]
|
||||
for i in range(10, 31, 3):
|
||||
r[i : i + 3] = sorted(r[i : i + 3])
|
||||
self.name_prop[propcnt] = r[i + 1]
|
||||
propcnt += 1
|
||||
r[0:10] = sorted(r[0:10])
|
||||
self.name_prop[propcnt] = 154
|
||||
propcnt += 1
|
||||
for i in range(3, 7):
|
||||
self.name_prop[propcnt - 1] += r[i]
|
||||
for i in range(7):
|
||||
self.name_prop[i] += 36
|
||||
|
||||
self.skl_id = list(range(0, 40))
|
||||
self.skl_freq = [0] * 40
|
||||
a = b = 0
|
||||
randbase = []
|
||||
randbase[:] = self.val[:]
|
||||
|
||||
def randgen():
|
||||
def m():
|
||||
nonlocal a, b, randbase
|
||||
a = (a + 1) % 256
|
||||
b = (b + randbase[a]) % 256
|
||||
randbase[a], randbase[b] = randbase[b], randbase[a]
|
||||
return randbase[(randbase[a] + randbase[b]) & 255]
|
||||
|
||||
return ((m() << 8) | m()) % 40
|
||||
|
||||
s = 0
|
||||
for i in range(2):
|
||||
for j in range(40):
|
||||
rand = randgen()
|
||||
s = (s + rand + self.skl_id[j]) % 40
|
||||
self.skl_id[j], self.skl_id[s] = self.skl_id[s], self.skl_id[j]
|
||||
last = -1
|
||||
j = 0
|
||||
for i in range(64, 128, 4):
|
||||
p = (
|
||||
min(
|
||||
self.name_base[i],
|
||||
self.name_base[i + 1],
|
||||
self.name_base[i + 2],
|
||||
self.name_base[i + 3],
|
||||
)
|
||||
% 256
|
||||
)
|
||||
if p > 10 and self.skl_id[j] < 35:
|
||||
self.skl_freq[j] = p - 10
|
||||
if self.skl_id[j] < 25:
|
||||
last = j
|
||||
j += 1
|
||||
if last != -1:
|
||||
self.skl_freq[last] *= 2
|
||||
if self.skl_freq[14] > 0 and last != 14:
|
||||
self.skl_freq[14] += min(
|
||||
self.name_base[60], self.name_base[61], self.skl_freq[14]
|
||||
)
|
||||
if self.skl_freq[15] > 0 and last != 15:
|
||||
self.skl_freq[15] += min(
|
||||
self.name_base[62], self.name_base[63], self.skl_freq[15]
|
||||
)
|
||||
return True
|
||||
|
||||
def display(self) -> str:
|
||||
cache = io.StringIO()
|
||||
cache.write(f"{self.name}@{self.team}|")
|
||||
full = sum(self.name_prop[0:7]) + round(self.name_prop[7] / 3)
|
||||
datas = [self.name_prop[7], *self.name_prop[0:7], full]
|
||||
cache.write(
|
||||
"|".join(
|
||||
[f"{prop_names[index]}:{value}" for index, value in enumerate(datas)]
|
||||
)
|
||||
)
|
||||
cache.write("\n")
|
||||
cache.write(
|
||||
"|".join(
|
||||
[
|
||||
f"{sklname[self.skl_id[index]]}:{self.skl_freq[index]}"
|
||||
for index, value in sorted(
|
||||
enumerate(self.skl_freq), key=lambda x: x[1], reverse=True
|
||||
)
|
||||
if value > 0
|
||||
]
|
||||
)
|
||||
)
|
||||
return cache.getvalue()
|
129
plugins/namerena.py
Normal file
129
plugins/namerena.py
Normal file
@ -0,0 +1,129 @@
|
||||
import io
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import subprocess
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
if str(Path(__file__).parent.absolute()) not in sys.path:
|
||||
sys.path.append(str(Path(__file__).parent.absolute()))
|
||||
|
||||
import name_utils
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ica_typing import (
|
||||
IcaNewMessage,
|
||||
IcaClient,
|
||||
ConfigData,
|
||||
ReciveMessage,
|
||||
TailchatReciveMessage,
|
||||
)
|
||||
|
||||
CONFIG_DATA: ConfigData
|
||||
else:
|
||||
CONFIG_DATA = None # type: ignore
|
||||
IcaNewMessage = TypeVar("NewMessage")
|
||||
IcaClient = TypeVar("IcaClient")
|
||||
ReciveMessage = TypeVar("ReciveMessage")
|
||||
TailchatReciveMessage = TypeVar("TailchatReciveMessage")
|
||||
|
||||
|
||||
_version_ = "0.5.0"
|
||||
|
||||
EVAL_PREFIX = "/namerena"
|
||||
CONVERT_PREFIX = "/namer-peek"
|
||||
|
||||
|
||||
def convert_name(msg: ReciveMessage, client) -> None:
|
||||
# 也是多行
|
||||
if msg.content.find("\n") == -1:
|
||||
client.send_message(
|
||||
msg.reply_with(
|
||||
f"请使用 {CONVERT_PREFIX} 命令,然后换行输入名字,例如:\n{CONVERT_PREFIX}\n张三\n李四\n王五\n"
|
||||
)
|
||||
)
|
||||
return
|
||||
# 去掉 prefix
|
||||
names = msg.content[len(CONVERT_PREFIX) :]
|
||||
# 去掉第一个 \n
|
||||
names = names[names.find("\n") + 1 :]
|
||||
cache = io.StringIO()
|
||||
raw_players = [x for x in names.split("\n") if x != ""]
|
||||
players = [name_utils.Player() for _ in raw_players]
|
||||
for i, player in enumerate(players):
|
||||
if not player.load(raw_players[i]):
|
||||
cache.write(f"{i+1} {raw_players[i]} 无法解析\n")
|
||||
raw_players[i] = ""
|
||||
for i, player in enumerate(players):
|
||||
if raw_players[i] == "":
|
||||
continue
|
||||
cache.write(player.display())
|
||||
cache.write("\n")
|
||||
reply = msg.reply_with(f"{cache.getvalue()}版本:{_version_}")
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
def eval_fight(msg: ReciveMessage, client) -> None:
|
||||
if msg.content.find("\n") == -1:
|
||||
# 在判断一下是不是 /xxx xxxx
|
||||
if msg.content.find(" ") != -1:
|
||||
client.send_message(
|
||||
msg.reply_with(
|
||||
f"请使用 {EVAL_PREFIX} 命令,然后换行输入名字,例如:\n{EVAL_PREFIX}\n张三\n李四\n王五\n"
|
||||
)
|
||||
)
|
||||
return
|
||||
# 去掉 prefix
|
||||
names = msg.content[len(EVAL_PREFIX) :]
|
||||
# 去掉第一个 \n
|
||||
names = names[names.find("\n") + 1 :]
|
||||
|
||||
start_time = time.time()
|
||||
# 开始 try
|
||||
try:
|
||||
# 内容写入到 ./md5/input.txt
|
||||
# 路径是插件文件的相对路径
|
||||
root_path = Path(__file__).parent
|
||||
with open(root_path / "md5" / "input.txt", "w") as f:
|
||||
f.write(names)
|
||||
# 执行 node md5.js
|
||||
runner_path = root_path / "md5" / "md5-api.js"
|
||||
# input_path = root_path / "md5" / "input.txt"
|
||||
result = subprocess.run(
|
||||
["node", runner_path.absolute()],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
# 获取结果
|
||||
out_result = result.stdout.decode("utf-8")
|
||||
err_result = result.stderr.decode("utf-8")
|
||||
# 发送结果
|
||||
end_time = time.time()
|
||||
reply = msg.reply_with(
|
||||
f"{out_result}{err_result}外部耗时:{end_time - start_time:.2f}s\n版本:{_version_}"
|
||||
)
|
||||
client.send_message(reply)
|
||||
except Exception as e:
|
||||
# 发送错误
|
||||
reply = msg.reply_with(f"发生错误:{e}\n{traceback.format_exc()}")
|
||||
client.send_message(reply)
|
||||
|
||||
|
||||
def dispatch_msg(msg: ReciveMessage, client) -> None:
|
||||
if msg.is_reply or msg.is_from_self:
|
||||
return
|
||||
if msg.content.startswith(EVAL_PREFIX):
|
||||
eval_fight(msg, client)
|
||||
elif msg.content.startswith(CONVERT_PREFIX):
|
||||
convert_name(msg, client)
|
||||
|
||||
|
||||
def on_ica_message(msg: IcaNewMessage, client: IcaClient) -> None:
|
||||
dispatch_msg(msg, client) # type: ignore
|
||||
|
||||
|
||||
def on_tailchat_message(msg: TailchatReciveMessage, client) -> None:
|
||||
dispatch_msg(msg, client) # type: ignore
|
80
plugins/save_eval.pyi
Normal file
80
plugins/save_eval.pyi
Normal file
@ -0,0 +1,80 @@
|
||||
import time
|
||||
import random
|
||||
import traceback
|
||||
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ica_typing import IcaNewMessage, IcaClient
|
||||
else:
|
||||
IcaNewMessage = TypeVar("NewMessage")
|
||||
IcaClient = TypeVar("IcaClient")
|
||||
|
||||
def safe_eval(code: str, msg: IcaNewMessage) -> str:
|
||||
try:
|
||||
# code = code.replace('help', '坏东西!\n')
|
||||
# code = code.replace('bytes', '坏东西!\n')
|
||||
# code = code.replace('encode', '坏东西!\n')
|
||||
# code = code.replace('decode', '坏东西!\n')
|
||||
# code = code.replace('compile', '屑的!\n')
|
||||
# code = code.replace('globals', '拿不到!\n')
|
||||
code = code.replace("os", "坏东西!\n")
|
||||
code = code.replace("sys", "坏东西!\n")
|
||||
# code = code.replace('input', '坏东西!\n')
|
||||
# code = code.replace('__', '啊哈!\n')
|
||||
# code = code.replace('import', '很坏!\n')
|
||||
code = code.replace(" kill", "别跑!\n")
|
||||
code = code.replace(" rm ", "别跑!\n")
|
||||
code = code.replace("exit", "好坏!\n")
|
||||
code = code.replace("eval", "啊哈!\n")
|
||||
code = code.replace("exec", "抓住!\n")
|
||||
start_time = time.time()
|
||||
try:
|
||||
import os
|
||||
import math
|
||||
import decimal
|
||||
|
||||
global_val = {
|
||||
"time": time,
|
||||
"math": math,
|
||||
"decimal": decimal,
|
||||
"random": random,
|
||||
"__import__": "<built-in function __import__>",
|
||||
"globals": "<built-in function globals>",
|
||||
"compile": "<built-in function compile>",
|
||||
"open": "<built-in function open>",
|
||||
"help": "<built-in function help>",
|
||||
"exit": "<built-in function exit>",
|
||||
"input": "<built-in function input>",
|
||||
"return": "别惦记你那个 return 了",
|
||||
"getattr": "<built-in function getattr>",
|
||||
"setattr": "<built-in function setattr>",
|
||||
"msg": msg,
|
||||
}
|
||||
os.system = "不许"
|
||||
result = str(eval(code, global_val, {}))
|
||||
limit = 500
|
||||
if len(result) > limit:
|
||||
result = result[:limit]
|
||||
except:
|
||||
result = traceback.format_exc()
|
||||
end_time = time.time()
|
||||
|
||||
if result == "6" or result == 6:
|
||||
result = "他确实等于 6"
|
||||
|
||||
result = f"{code}\neval result:\n{result}\n耗时: {end_time - start_time} s"
|
||||
return result
|
||||
except:
|
||||
error = traceback.format_exc()
|
||||
result = f"error:\n{error}"
|
||||
return result
|
||||
|
||||
|
||||
def on_message(message: IcaNewMessage, client: IcaClient) -> None:
|
||||
if not (message.is_from_self or message.is_reply):
|
||||
if message.content.startswith("/="):
|
||||
code = message.content[2:]
|
||||
result = safe_eval(code, message)
|
||||
reply = message.reply_with(result)
|
||||
client.send_message(reply)
|
Loading…
Reference in New Issue
Block a user