🐛 修复多bot连接时深渊统计猜语音可能报错的问题

This commit is contained in:
CMHopeSunshine 2023-02-17 22:36:31 +08:00
parent 9f88e385c5
commit 4c3b1e5631
5 changed files with 477 additions and 187 deletions

View File

@ -2,7 +2,13 @@ import random
from typing import Union from typing import Union
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.onebot.v11 import Message, MessageEvent, GroupMessageEvent, PrivateMessageEvent from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
PrivateMessageEvent,
)
from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
@ -12,7 +18,14 @@ from LittlePaimon.config import config
from LittlePaimon.database import GenshinVoice from LittlePaimon.database import GenshinVoice
from LittlePaimon.utils.alias import get_match_alias from LittlePaimon.utils.alias import get_match_alias
from LittlePaimon.utils.message import CommandCharacter, CommandLang, MessageBuild from LittlePaimon.utils.message import CommandCharacter, CommandLang, MessageBuild
from .handler import GuessVoice, get_character_voice, get_rank, get_voice_list, get_record
from .handler import (
GuessVoice,
get_character_voice,
get_rank,
get_record,
get_voice_list,
)
from .resources import update_voice_resources from .resources import update_voice_resources
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
@ -23,44 +36,67 @@ __plugin_meta__ = PluginMetadata(
'author': '惜月', 'author': '惜月',
'version': '3.0', 'version': '3.0',
'priority': 6, 'priority': 6,
} },
) )
guess_voice = on_command('原神猜语音', priority=12, block=True, state={ guess_voice = on_command(
'原神猜语音',
priority=12,
block=True,
state={
'pm_name': '原神猜语音', 'pm_name': '原神猜语音',
'pm_description': '原神猜语音小游戏', 'pm_description': '原神猜语音小游戏',
'pm_usage': '原神猜语音[语言][排行榜]', 'pm_usage': '原神猜语音[语言][排行榜]',
'pm_priority': 1 'pm_priority': 1,
}) },
get_voice = on_command('原神语音', priority=12, block=True, state={ )
get_voice = on_command(
'原神语音',
priority=12,
block=True,
state={
'pm_name': '原神语音', 'pm_name': '原神语音',
'pm_description': '获取指定角色的指定语音', 'pm_description': '获取指定角色的指定语音',
'pm_usage': '原神语音<名|序号>[语言]', 'pm_usage': '原神语音<名|序号>[语言]',
'pm_priority': 3 'pm_priority': 3,
}) },
voice_list = on_command('原神语音列表', priority=12, block=True, state={ )
voice_list = on_command(
'原神语音列表',
priority=12,
block=True,
state={
'pm_name': '原神语音列表', 'pm_name': '原神语音列表',
'pm_description': '查看角色的语音列表', 'pm_description': '查看角色的语音列表',
'pm_usage': '原神语音列表<名><语言>', 'pm_usage': '原神语音列表<名><语言>',
'pm_priority': 2 'pm_priority': 2,
}) },
update_voice = on_command('更新原神语音资源', priority=12, permission=SUPERUSER, block=True, state={ )
update_voice = on_command(
'更新原神语音资源',
priority=12,
permission=SUPERUSER,
block=True,
state={
'pm_name': '更新原神语音资源', 'pm_name': '更新原神语音资源',
'pm_description': '更新原神语音资源', 'pm_description': '更新原神语音资源',
'pm_usage': '更新原神语音资源', 'pm_usage': '更新原神语音资源',
'pm_show': False, 'pm_show': False,
'pm_priority': 4 'pm_priority': 4,
}) },
)
@guess_voice.handle() @guess_voice.handle()
async def _(event: GroupMessageEvent, msg: Message = CommandArg(), lang=CommandLang()): async def _(
bot: Bot, event: GroupMessageEvent, msg: Message = CommandArg(), lang=CommandLang()
):
msg = msg.extract_plain_text().strip() msg = msg.extract_plain_text().strip()
if 'rank' in msg or '排行' in msg: if 'rank' in msg or '排行' in msg:
result = await get_rank(event.group_id) result = await get_rank(event.group_id)
await guess_voice.finish(result) await guess_voice.finish(result)
else: else:
game = GuessVoice(event.group_id, config.guess_voice_time, lang) game = GuessVoice(event.group_id, bot, config.guess_voice_time, lang)
result = await game.start() result = await game.start()
await guess_voice.send(f'即将发送一段语音,将在{config.guess_voice_time}秒后公布答案') await guess_voice.send(f'即将发送一段语音,将在{config.guess_voice_time}秒后公布答案')
try: try:
@ -71,11 +107,19 @@ async def _(event: GroupMessageEvent, msg: Message = CommandArg(), lang=CommandL
@get_voice.handle() @get_voice.handle()
async def _(event: Union[GroupMessageEvent, PrivateMessageEvent], lang=CommandLang(), msg: Message = CommandArg()): async def _(
event: Union[GroupMessageEvent, PrivateMessageEvent],
lang=CommandLang(),
msg: Message = CommandArg(),
):
msg = msg.extract_plain_text().strip().split(' ')[0] msg = msg.extract_plain_text().strip().split(' ')[0]
if msg.isdigit(): if msg.isdigit():
voice = await GenshinVoice.get_or_none(id=int(msg)) voice = await GenshinVoice.get_or_none(id=int(msg))
await get_voice.finish(await get_record(voice.voice_url) if voice else MessageBuild.Text(f'没有{msg}号原神语音')) await get_voice.finish(
await get_record(voice.voice_url)
if voice
else MessageBuild.Text(f'没有{msg}号原神语音')
)
else: else:
if chara := get_match_alias(msg, ['角色'], True): if chara := get_match_alias(msg, ['角色'], True):
chara = chara[0] chara = chara[0]
@ -85,11 +129,17 @@ async def _(event: Union[GroupMessageEvent, PrivateMessageEvent], lang=CommandLa
if voices: if voices:
await get_voice.finish(await get_record(random.choice(voices).voice_url)) await get_voice.finish(await get_record(random.choice(voices).voice_url))
else: else:
await get_voice.finish(MessageBuild.Text(f'暂无{chara}{lang}文语音资源,让超级用户[更新原神语音资源]吧!')) await get_voice.finish(
MessageBuild.Text(f'暂无{chara}{lang}文语音资源,让超级用户[更新原神语音资源]吧!')
)
@voice_list.handle() @voice_list.handle()
async def _(event: Union[GroupMessageEvent, PrivateMessageEvent], character=CommandCharacter(1), lang=CommandLang()): async def _(
event: Union[GroupMessageEvent, PrivateMessageEvent],
character=CommandCharacter(1),
lang=CommandLang(),
):
result = await get_voice_list(character[0], lang) result = await get_voice_list(character[0], lang)
await get_voice.finish(result) await get_voice.finish(result)

View File

@ -1,14 +1,15 @@
import datetime import datetime
import random import random
from nonebot import get_bot, on_regex from nonebot import on_regex
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageSegment from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageSegment
from nonebot.rule import Rule from nonebot.rule import Rule
from LittlePaimon.database import GenshinVoice, GuessVoiceRank from LittlePaimon.database import GenshinVoice, GuessVoiceRank
from LittlePaimon.utils import scheduler, logger from LittlePaimon.utils import logger, scheduler
from LittlePaimon.utils.alias import get_alias_by_name from LittlePaimon.utils.alias import get_alias_by_name
from LittlePaimon.utils.requests import aiorequests from LittlePaimon.utils.requests import aiorequests
from .draw import draw_voice_list from .draw import draw_voice_list
gaming = {} gaming = {}
@ -19,10 +20,13 @@ class GuessVoice:
group_id: int group_id: int
language: str language: str
def __init__(self, group_id: int, game_time: int = 30, language: str = ''): def __init__(
self, group_id: int, bot: Bot, game_time: int = 30, language: str = ''
):
self.group_id = group_id self.group_id = group_id
self.game_time = game_time self.game_time = game_time
self.language = language self.language = language
self.bot = bot
@property @property
def is_gaming(self): def is_gaming(self):
@ -39,10 +43,14 @@ class GuessVoice:
create_guess_matcher(self.group_id, voice.character, self.game_time) create_guess_matcher(self.group_id, voice.character, self.game_time)
if scheduler.get_job(f'Guess_voice_{self.group_id}'): if scheduler.get_job(f'Guess_voice_{self.group_id}'):
scheduler.remove_job(f'Guess_voice_{self.group_id}') scheduler.remove_job(f'Guess_voice_{self.group_id}')
scheduler.add_job(self.end, 'date', scheduler.add_job(
run_date=datetime.datetime.now() + datetime.timedelta(seconds=self.game_time), self.end,
'date',
run_date=datetime.datetime.now()
+ datetime.timedelta(seconds=self.game_time),
id=f'Guess_voice_{self.group_id}', id=f'Guess_voice_{self.group_id}',
misfire_grace_time=10) misfire_grace_time=10,
)
return await get_record(voice.voice_url) return await get_record(voice.voice_url)
async def end(self, exception: bool = False): async def end(self, exception: bool = False):
@ -51,18 +59,22 @@ class GuessVoice:
del gaming[self.group_id] del gaming[self.group_id]
msg = f'还没有人猜中呢,正确答案是:{answer}' msg = f'还没有人猜中呢,正确答案是:{answer}'
try: try:
await get_bot().send_group_msg(group_id=self.group_id, message=msg) await self.bot.send_group_msg(group_id=self.group_id, message=msg)
except Exception as e: except Exception as e:
logger.warning('原神猜语音', '➤发送结果时出错', str(e)) logger.warning('原神猜语音', '➤发送结果时出错', str(e))
logger.info('原神猜语音', f'➤群<m>{self.group_id}</m>猜语音游戏结束,答案为<m>{answer}</m>,没有人猜对') logger.info(
'原神猜语音', f'➤群<m>{self.group_id}</m>猜语音游戏结束,答案为<m>{answer}</m>,没有人猜对'
)
elif exception: elif exception:
logger.warning('原神猜语音', f'➤群<m>{self.group_id}</m>猜语音游戏发送语音出错, 异常结束') logger.warning('原神猜语音', f'➤群<m>{self.group_id}</m>猜语音游戏发送语音出错, 异常结束')
del gaming[self.group_id] del gaming[self.group_id]
async def get_rank(group_id: int): async def get_rank(group_id: int):
records = await GuessVoiceRank.filter(group_id=group_id, records = await GuessVoiceRank.filter(
guess_time__gte=datetime.datetime.now() - datetime.timedelta(days=7)) group_id=group_id,
guess_time__gte=datetime.datetime.now() - datetime.timedelta(days=7),
)
if not records: if not records:
return '本群本周暂无排行榜数据哦!' return '本群本周暂无排行榜数据哦!'
rank = {} rank = {}
@ -72,7 +84,9 @@ async def get_rank(group_id: int):
else: else:
rank[record.user_id] = 1 rank[record.user_id] = 1
msg = '本周猜语音排行榜\n' msg = '本周猜语音排行榜\n'
for i, (user_id, count) in enumerate(sorted(rank.items(), key=lambda x: x[1], reverse=True), start=1): for i, (user_id, count) in enumerate(
sorted(rank.items(), key=lambda x: x[1], reverse=True), start=1
):
msg += f'{i}.{user_id}: {count}\n' msg += f'{i}.{user_id}: {count}\n'
return msg return msg
@ -87,24 +101,39 @@ def create_guess_matcher(group_id, role_name, game_time):
def check_group(event: GroupMessageEvent): def check_group(event: GroupMessageEvent):
return event.group_id == group_id return event.group_id == group_id
if '旅行者' in role_name: if '旅行者' in role_name:
role_name = role_name.replace('旅行者(', '').replace('', '') role_name = role_name.replace('旅行者(', '').replace('', '')
alias_list = get_alias_by_name(role_name) alias_list = get_alias_by_name(role_name)
re_str = '|'.join(alias_list) re_str = '|'.join(alias_list)
guess_matcher = on_regex(f'^{re_str}$', temp=True, rule=Rule(check_group), guess_matcher = on_regex(
expire_time=datetime.timedelta(seconds=game_time)) f'^{re_str}$',
temp=True,
rule=Rule(check_group),
expire_time=datetime.timedelta(seconds=game_time),
)
guess_matcher.plugin_name = "Genshin_Voice" guess_matcher.plugin_name = "Genshin_Voice"
@guess_matcher.handle() @guess_matcher.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
await GuessVoiceRank.create(user_id=event.user_id, group_id=event.group_id, answer=role_name, await GuessVoiceRank.create(
guess_time=datetime.datetime.now()) user_id=event.user_id,
group_id=event.group_id,
answer=role_name,
guess_time=datetime.datetime.now(),
)
del gaming[event.group_id] del gaming[event.group_id]
if scheduler.get_job(f'Guess_voice_{event.group_id}'): if scheduler.get_job(f'Guess_voice_{event.group_id}'):
scheduler.remove_job(f'Guess_voice_{event.group_id}') scheduler.remove_job(f'Guess_voice_{event.group_id}')
logger.info('原神猜语音', f'➤群<m>{event.group_id}</m>猜语音游戏结束,答案为<m>{role_name}</m>,由<m>{event.sender.card}</m>猜对') logger.info(
msg = Message(MessageSegment.text('恭喜') + MessageSegment.at(event.user_id) + MessageSegment.text( '原神猜语音',
f'猜对了!\n正确答案是:{role_name}')) f'➤群<m>{event.group_id}</m>猜语音游戏结束,答案为<m>{role_name}</m>,由<m>{event.sender.card}</m>猜对',
)
msg = Message(
MessageSegment.text('恭喜')
+ MessageSegment.at(event.user_id)
+ MessageSegment.text(f'猜对了!\n正确答案是:{role_name}')
)
await guess_matcher.finish(msg) await guess_matcher.finish(msg)
@ -118,7 +147,11 @@ async def get_character_voice(character: str, language: str = '中'):
async def get_voice_list(character: str, language: str = ''): async def get_voice_list(character: str, language: str = ''):
voice_list = await GenshinVoice.filter(character=character, language=language).all() voice_list = await GenshinVoice.filter(character=character, language=language).all()
return await draw_voice_list(voice_list) if voice_list else MessageSegment.text(f'暂无{character}{language}语音资源,让超级用户[更新原神语音资源]吧!') return (
await draw_voice_list(voice_list)
if voice_list
else MessageSegment.text(f'暂无{character}{language}语音资源,让超级用户[更新原神语音资源]吧!')
)
async def get_record(url: str) -> MessageSegment.record: async def get_record(url: str) -> MessageSegment.record:

View File

@ -1,11 +1,12 @@
from nonebot import on_command from nonebot import on_command
from nonebot.adapters.onebot.v11 import Message, MessageEvent, GroupMessageEvent from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from LittlePaimon.utils import logger from LittlePaimon.utils import logger
from LittlePaimon.utils.genshin import GenshinInfoManager from LittlePaimon.utils.genshin import GenshinInfoManager
from LittlePaimon.utils.message import CommandPlayer from LittlePaimon.utils.message import CommandPlayer
from .abyss_statistics import get_statistics from .abyss_statistics import get_statistics
from .draw_abyss import draw_abyss_card from .draw_abyss import draw_abyss_card
from .youchuang import draw_team from .youchuang import draw_team
@ -18,27 +19,45 @@ __plugin_meta__ = PluginMetadata(
'author': '惜月', 'author': '惜月',
'version': '3.0', 'version': '3.0',
'priority': 2, 'priority': 2,
} },
) )
sy = on_command('sy', aliases={'深渊战报', '深渊信息'}, priority=10, block=True, state={ sy = on_command(
'sy',
aliases={'深渊战报', '深渊信息'},
priority=10,
block=True,
state={
'pm_name': 'sy', 'pm_name': 'sy',
'pm_description': '查看本期|上期的深渊战报', 'pm_description': '查看本期|上期的深渊战报',
'pm_usage': 'sy(uid)(本期|上期)', 'pm_usage': 'sy(uid)(本期|上期)',
'pm_priority': 1 'pm_priority': 1,
}) },
abyss_stat = on_command('深渊统计', aliases={'深渊群数据', '深渊群排行'}, priority=10, block=True, state={ )
abyss_stat = on_command(
'深渊统计',
aliases={'深渊群数据', '深渊群排行'},
priority=10,
block=True,
state={
'pm_name': '深渊统计', 'pm_name': '深渊统计',
'pm_description': '查看本群深渊统计,仅群可用', 'pm_description': '查看本群深渊统计,仅群可用',
'pm_usage': '深渊统计', 'pm_usage': '深渊统计',
'pm_priority': 2 'pm_priority': 2,
}) },
abyss_team = on_command('深渊配队', aliases={'配队推荐', '深渊阵容'}, priority=10, block=True, state={ )
abyss_team = on_command(
'深渊配队',
aliases={'配队推荐', '深渊阵容'},
priority=10,
block=True,
state={
'pm_name': '深渊配队', 'pm_name': '深渊配队',
'pm_description': '查看深渊配队推荐,数据来源于游创工坊', 'pm_description': '查看深渊配队推荐,数据来源于游创工坊',
'pm_usage': '深渊配队', 'pm_usage': '深渊配队',
'pm_priority': 3 'pm_priority': 3,
}) },
)
@sy.handle() @sy.handle()
@ -66,9 +85,9 @@ async def _(event: MessageEvent, players=CommandPlayer(), msg: Message = Command
@abyss_stat.handle() @abyss_stat.handle()
async def _(event: GroupMessageEvent): async def _(bot: Bot, event: GroupMessageEvent):
try: try:
result = await get_statistics(event.group_id) result = await get_statistics(event.group_id, bot)
except Exception as e: except Exception as e:
result = f'制作深渊统计时出错:{e}' result = f'制作深渊统计时出错:{e}'
await abyss_stat.finish(result) await abyss_stat.finish(result)

View File

@ -1,12 +1,14 @@
import datetime import datetime
from collections import Counter from collections import Counter
from typing import Dict, Any, Tuple from typing import Any, Dict, Tuple
import pytz import pytz
from nonebot import get_bot from nonebot.adapters.onebot.v11 import Bot
from LittlePaimon.database import AbyssInfo from LittlePaimon.database import AbyssInfo
from LittlePaimon.utils.image import PMImage, font_manager as fm, get_qq_avatar, load_image from LittlePaimon.utils.image import PMImage
from LittlePaimon.utils.image import font_manager as fm
from LittlePaimon.utils.image import get_qq_avatar, load_image
from LittlePaimon.utils.message import MessageBuild from LittlePaimon.utils.message import MessageBuild
from LittlePaimon.utils.path import RESOURCE_BASE_PATH from LittlePaimon.utils.path import RESOURCE_BASE_PATH
from LittlePaimon.utils.requests import aiorequests from LittlePaimon.utils.requests import aiorequests
@ -24,7 +26,9 @@ async def get_user_avatar(user_id: str, size: Tuple[int, int] = (60, 60)):
async def get_group_avatar(group_id: str): async def get_group_avatar(group_id: str):
try: try:
img = await aiorequests.get_img(f'https://p.qlogo.cn/gh/{group_id}/{group_id}/100', size=(110, 110)) img = await aiorequests.get_img(
f'https://p.qlogo.cn/gh/{group_id}/{group_id}/100', size=(110, 110)
)
img = PMImage(img) img = PMImage(img)
await img.to_circle('circle') await img.to_circle('circle')
return img return img
@ -32,20 +36,26 @@ async def get_group_avatar(group_id: str):
return PMImage(size=(110, 110), color=(255, 255, 255, 255)) return PMImage(size=(110, 110), color=(255, 255, 255, 255))
async def get_statistics(group_id: int): async def get_statistics(group_id: int, bot: Bot):
if not (info_list := await AbyssInfo.all()): now = datetime.datetime.now()
abyss_info_list = await AbyssInfo.filter(
total_battle__not=None,
total_star__not=None,
max_damage__not=None,
max_take_damage__not=None,
start_time__lte=now,
end_time__gte=now,
)
if not abyss_info_list:
return '本群还没有深渊战斗数据哦!' return '本群还没有深渊战斗数据哦!'
member_list = await get_bot().get_group_member_list(group_id=group_id) member_list = await bot.get_group_member_list(group_id=group_id)
member_id_list = [str(member['user_id']) for member in member_list] member_id_list = [str(member['user_id']) for member in member_list]
info_list = [info for info in info_list if info_list = [info for info in abyss_info_list if info.user_id in member_id_list]
info.user_id in member_id_list and info.total_battle and info.total_star and info.max_damage and info.max_take_damage] if not abyss_info_list:
now = datetime.datetime.now().replace(tzinfo=pytz.timezone('Asia/Shanghai'))
info_list = [info for info in info_list if info.start_time <= now <= info.end_time]
if not info_list:
return '本群还没有深渊战斗数据哦!' return '本群还没有深渊战斗数据哦!'
elif len(info_list) < 3: elif len(abyss_info_list) < 3:
return '本群深渊有效战斗数据不足3人无法生成统计图' return '本群深渊有效战斗数据不足3人无法生成统计图'
for info in info_list: for info in abyss_info_list:
if info.nickname is None: if info.nickname is None:
for member in member_list: for member in member_list:
if info.user_id == str(member['user_id']): if info.user_id == str(member['user_id']):
@ -53,7 +63,7 @@ async def get_statistics(group_id: int):
break break
data = { data = {
'群号': str(group_id), '群号': str(group_id),
'群名称': (await get_bot().get_group_info(group_id=group_id))['group_name'], '群名称': (await bot.get_group_info(group_id=group_id))['group_name'],
} }
# 数据数 # 数据数
info_num = len(info_list) info_num = len(info_list)
@ -65,7 +75,9 @@ async def get_statistics(group_id: int):
average_star = round(sum(info.total_star for info in info_list) / info_num, 1) average_star = round(sum(info.total_star for info in info_list) / info_num, 1)
data['平均星数'] = average_star data['平均星数'] = average_star
# 平均战斗次数 # 平均战斗次数
average_battle_num = round(sum(info.total_battle for info in info_list) / info_num, 1) average_battle_num = round(
sum(info.total_battle for info in info_list) / info_num, 1
)
data['平均战斗次数'] = average_battle_num data['平均战斗次数'] = average_battle_num
# 最高伤害角色 # 最高伤害角色
# max_damage = max(info_list, key=lambda x: x.max_damage.value) # max_damage = max(info_list, key=lambda x: x.max_damage.value)
@ -80,10 +92,13 @@ async def get_statistics(group_id: int):
'用户名': info.nickname, '用户名': info.nickname,
'qq号': info.user_id, 'qq号': info.user_id,
'uid': info.uid, 'uid': info.uid,
} for info in max_damage[:3] }
for info in max_damage[:3]
] ]
# 最多承伤角色 # 最多承伤角色
max_take_damage = sorted(info_list, key=lambda x: x.max_take_damage.value, reverse=True) max_take_damage = sorted(
info_list, key=lambda x: x.max_take_damage.value, reverse=True
)
data['最高承受伤害'] = [ data['最高承受伤害'] = [
{ {
'图标': info.max_take_damage.icon, '图标': info.max_take_damage.icon,
@ -94,7 +109,8 @@ async def get_statistics(group_id: int):
'用户名': info.nickname, '用户名': info.nickname,
'qq号': info.user_id, 'qq号': info.user_id,
'uid': info.uid, 'uid': info.uid,
} for info in max_take_damage[:3] }
for info in max_take_damage[:3]
] ]
# 11、12层阵容 # 11、12层阵容
battle_characters_up11 = Counter() battle_characters_up11 = Counter()
@ -108,14 +124,18 @@ async def get_statistics(group_id: int):
battle_characters_up11[f'{character.icon}-{character.rarity}'] += 1 battle_characters_up11[f'{character.icon}-{character.rarity}'] += 1
for battles in floor11.battles_down: for battles in floor11.battles_down:
for character in battles.characters: for character in battles.characters:
battle_characters_down11[f'{character.icon}-{character.rarity}'] += 1 battle_characters_down11[
f'{character.icon}-{character.rarity}'
] += 1
if floor12 := info.floors.get(12): if floor12 := info.floors.get(12):
for battles in floor12.battles_up: for battles in floor12.battles_up:
for character in battles.characters: for character in battles.characters:
battle_characters_up12[f'{character.icon}-{character.rarity}'] += 1 battle_characters_up12[f'{character.icon}-{character.rarity}'] += 1
for battles in floor12.battles_down: for battles in floor12.battles_down:
for character in battles.characters: for character in battles.characters:
battle_characters_down12[f'{character.icon}-{character.rarity}'] += 1 battle_characters_down12[
f'{character.icon}-{character.rarity}'
] += 1
data['11层上半'] = battle_characters_up11.most_common(4) data['11层上半'] = battle_characters_up11.most_common(4)
data['11层下半'] = battle_characters_down11.most_common(4) data['11层下半'] = battle_characters_down11.most_common(4)
data['12层上半'] = battle_characters_up12.most_common(4) data['12层上半'] = battle_characters_up12.most_common(4)
@ -130,53 +150,129 @@ async def draw_statistics_img(data: Dict[str, Any]):
'4small': await load_image(RESOURCE_BASE_PATH / 'abyss' / '4smallbox.png'), '4small': await load_image(RESOURCE_BASE_PATH / 'abyss' / '4smallbox.png'),
'5big': await load_image(RESOURCE_BASE_PATH / 'abyss' / '5bigbox.png'), '5big': await load_image(RESOURCE_BASE_PATH / 'abyss' / '5bigbox.png'),
'5small': await load_image(RESOURCE_BASE_PATH / 'abyss' / '5smallbox.png'), '5small': await load_image(RESOURCE_BASE_PATH / 'abyss' / '5smallbox.png'),
'4bg': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star4_no_line.png', size=(95, 95)), '4bg': await load_image(
'5bg': await load_image(RESOURCE_BASE_PATH / 'icon' / 'star5_no_line.png', size=(95, 95)) RESOURCE_BASE_PATH / 'icon' / 'star4_no_line.png', size=(95, 95)
),
'5bg': await load_image(
RESOURCE_BASE_PATH / 'icon' / 'star5_no_line.png', size=(95, 95)
),
} }
avatar = await get_group_avatar(data['群号']) avatar = await get_group_avatar(data['群号'])
await img.paste(avatar, (38, 47)) await img.paste(avatar, (38, 47))
await img.text(data['群名称'], 162, 58, fm.get('hywh', 48), '#040404') await img.text(data['群名称'], 162, 58, fm.get('hywh', 48), '#040404')
await img.text(data['群号'], 165, 116, fm.get('hywh', 36), '#040404') await img.text(data['群号'], 165, 116, fm.get('hywh', 36), '#040404')
await img.text(f'CREATED BY LITTLEPAIMON AT {datetime.datetime.now().strftime("%m-%d %H:%M")}', await img.text(
1033, 195, fm.get('bahnschrift_regular.ttf', 30), '#8c4c2e', 'right') f'CREATED BY LITTLEPAIMON AT {datetime.datetime.now().strftime("%m-%d %H:%M")}',
await img.text(str(data['总人数']), (233, 352), 296, fm.get('bahnschrift_regular.ttf', 48), '#040404', 'center') 1033,
await img.text(str(data['平均星数']), (492, 586), 296, fm.get('bahnschrift_regular.ttf', 48), '#040404', 'center') 195,
await img.text(str(data['平均战斗次数']), (698, 840), 296, fm.get('bahnschrift_regular.ttf', 48), '#040404', fm.get('bahnschrift_regular.ttf', 30),
'center') '#8c4c2e',
'right',
)
await img.text(
str(data['总人数']),
(233, 352),
296,
fm.get('bahnschrift_regular.ttf', 48),
'#040404',
'center',
)
await img.text(
str(data['平均星数']),
(492, 586),
296,
fm.get('bahnschrift_regular.ttf', 48),
'#040404',
'center',
)
await img.text(
str(data['平均战斗次数']),
(698, 840),
296,
fm.get('bahnschrift_regular.ttf', 48),
'#040404',
'center',
)
# 满星人数 # 满星人数
full_num = [data['满星人数'] / data['总人数'], 1 - data['满星人数'] / data['总人数']] full_num = [data['满星人数'] / data['总人数'], 1 - data['满星人数'] / data['总人数']]
now_used_width = 36 now_used_width = 36
if full_num[0] > 0.03: if full_num[0] > 0.03:
await img.draw_rectangle((now_used_width, 402, now_used_width + int(1007 * full_num[0]), 449), '#b6d6f2') await img.draw_rectangle(
await img.text(str(data['满星人数']), now_used_width + 18, 413, fm.get('bahnschrift_regular.ttf', 30), (now_used_width, 402, now_used_width + int(1007 * full_num[0]), 449),
'#3d6e99') '#b6d6f2',
)
await img.text(
str(data['满星人数']),
now_used_width + 18,
413,
fm.get('bahnschrift_regular.ttf', 30),
'#3d6e99',
)
now_used_width += int(1007 * full_num[0]) now_used_width += int(1007 * full_num[0])
if full_num[1] > 0.03: if full_num[1] > 0.03:
await img.draw_rectangle((now_used_width, 402, now_used_width + int(1007 * full_num[1]), 449), '#c8b6f2') await img.draw_rectangle(
await img.text(str(data['总人数'] - data['满星人数']), now_used_width + 18, 413, (now_used_width, 402, now_used_width + int(1007 * full_num[1]), 449),
fm.get('bahnschrift_regular.ttf', 30), '#593d99') '#c8b6f2',
)
await img.text(
str(data['总人数'] - data['满星人数']),
now_used_width + 18,
413,
fm.get('bahnschrift_regular.ttf', 30),
'#593d99',
)
# 最高伤害 # 最高伤害
await img.paste(box[f'{data["最高伤害"][0]["稀有度"]}big'], (39, 512)) await img.paste(box[f'{data["最高伤害"][0]["稀有度"]}big'], (39, 512))
await img.paste(box[f'{data["最高伤害"][1]["稀有度"]}small'], (39, 664)) await img.paste(box[f'{data["最高伤害"][1]["稀有度"]}small'], (39, 664))
await img.paste(box[f'{data["最高伤害"][2]["稀有度"]}small'], (296, 664)) await img.paste(box[f'{data["最高伤害"][2]["稀有度"]}small'], (296, 664))
await img.paste( await img.paste(
await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][0]["图标"]}.png', size=(124, 124)), await load_image(
(44, 525)) RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][0]["图标"]}.png',
size=(124, 124),
),
(44, 525),
)
await img.paste( await img.paste(
await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][1]["图标"]}.png', size=(82, 82)), await load_image(
(45, 673)) RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][1]["图标"]}.png',
size=(82, 82),
),
(45, 673),
)
await img.paste( await img.paste(
await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][2]["图标"]}.png', size=(82, 82)), await load_image(
(300, 673)) RESOURCE_BASE_PATH / 'avatar' / f'{data["最高伤害"][2]["图标"]}.png',
size=(82, 82),
),
(300, 673),
)
await img.paste(await get_user_avatar(data['最高伤害'][0]['qq号']), (112, 588)) await img.paste(await get_user_avatar(data['最高伤害'][0]['qq号']), (112, 588))
await img.paste(await get_user_avatar(data['最高伤害'][1]['qq号'], (42, 42)), (87, 713)) await img.paste(await get_user_avatar(data['最高伤害'][1]['qq号'], (42, 42)), (87, 713))
await img.paste(await get_user_avatar(data['最高伤害'][2]['qq号'], (42, 42)), (344, 713)) await img.paste(await get_user_avatar(data['最高伤害'][2]['qq号'], (42, 42)), (344, 713))
await img.text('最强一击', 180, 515, fm.get('hywh', 30), '#040404') await img.text('最强一击', 180, 515, fm.get('hywh', 30), '#040404')
await img.text('第二名', 139, 668, fm.get('hywh', 22), '#040404') await img.text('第二名', 139, 668, fm.get('hywh', 22), '#040404')
await img.text('第三名', 397, 668, fm.get('hywh', 22), '#040404') await img.text('第三名', 397, 668, fm.get('hywh', 22), '#040404')
await img.text(str(data['最高伤害'][0]['数值']), 180, 547, fm.get('bahnschrift_regular.ttf', 68), '#040404') await img.text(
await img.text(str(data['最高伤害'][1]['数值']), 137, 693, fm.get('bahnschrift_regular.ttf', 38), '#040404') str(data['最高伤害'][0]['数值']),
await img.text(str(data['最高伤害'][2]['数值']), 395, 693, fm.get('bahnschrift_regular.ttf', 38), '#040404') 180,
547,
fm.get('bahnschrift_regular.ttf', 68),
'#040404',
)
await img.text(
str(data['最高伤害'][1]['数值']),
137,
693,
fm.get('bahnschrift_regular.ttf', 38),
'#040404',
)
await img.text(
str(data['最高伤害'][2]['数值']),
395,
693,
fm.get('bahnschrift_regular.ttf', 38),
'#040404',
)
await img.text(data['最高伤害'][0]['用户名'][:11], 180, 610, fm.get('hywh', 30), '#040404') await img.text(data['最高伤害'][0]['用户名'][:11], 180, 610, fm.get('hywh', 30), '#040404')
await img.text(data['最高伤害'][1]['用户名'][:6], 137, 726, fm.get('hywh', 22), '#040404') await img.text(data['最高伤害'][1]['用户名'][:6], 137, 726, fm.get('hywh', 22), '#040404')
await img.text(data['最高伤害'][2]['用户名'][:6], 395, 726, fm.get('hywh', 22), '#040404') await img.text(data['最高伤害'][2]['用户名'][:6], 395, 726, fm.get('hywh', 22), '#040404')
@ -186,66 +282,158 @@ async def draw_statistics_img(data: Dict[str, Any]):
await img.paste(box[f'{data["最高承受伤害"][1]["稀有度"]}small'], (552, 664)) await img.paste(box[f'{data["最高承受伤害"][1]["稀有度"]}small'], (552, 664))
await img.paste(box[f'{data["最高承受伤害"][2]["稀有度"]}small'], (808, 664)) await img.paste(box[f'{data["最高承受伤害"][2]["稀有度"]}small'], (808, 664))
await img.paste( await img.paste(
await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][0]["图标"]}.png', size=(124, 124)), await load_image(
(560, 525)) RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][0]["图标"]}.png',
size=(124, 124),
),
(560, 525),
)
await img.paste( await img.paste(
await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][1]["图标"]}.png', size=(82, 82)), await load_image(
(557, 673)) RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][1]["图标"]}.png',
size=(82, 82),
),
(557, 673),
)
await img.paste( await img.paste(
await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][2]["图标"]}.png', size=(82, 82)), await load_image(
(815, 673)) RESOURCE_BASE_PATH / 'avatar' / f'{data["最高承受伤害"][2]["图标"]}.png',
size=(82, 82),
),
(815, 673),
)
await img.paste(await get_user_avatar(data['最高承受伤害'][0]['qq号']), (623, 588)) await img.paste(await get_user_avatar(data['最高承受伤害'][0]['qq号']), (623, 588))
await img.paste(await get_user_avatar(data['最高承受伤害'][1]['qq号'], (42, 42)), (600, 713)) await img.paste(
await img.paste(await get_user_avatar(data['最高承受伤害'][2]['qq号'], (42, 42)), (857, 713)) await get_user_avatar(data['最高承受伤害'][1]['qq号'], (42, 42)), (600, 713)
)
await img.paste(
await get_user_avatar(data['最高承受伤害'][2]['qq号'], (42, 42)), (857, 713)
)
await img.text('最多承伤', 693, 515, fm.get('hywh', 30), '#040404') await img.text('最多承伤', 693, 515, fm.get('hywh', 30), '#040404')
await img.text('第二名', 652, 668, fm.get('hywh', 22), '#040404') await img.text('第二名', 652, 668, fm.get('hywh', 22), '#040404')
await img.text('第三名', 910, 668, fm.get('hywh', 22), '#040404') await img.text('第三名', 910, 668, fm.get('hywh', 22), '#040404')
await img.text(str(data['最高承受伤害'][0]['数值']), 693, 547, fm.get('bahnschrift_regular.ttf', 68), '#040404') await img.text(
await img.text(str(data['最高承受伤害'][1]['数值']), 650, 693, fm.get('bahnschrift_regular.ttf', 38), '#040404') str(data['最高承受伤害'][0]['数值']),
await img.text(str(data['最高承受伤害'][2]['数值']), 908, 693, fm.get('bahnschrift_regular.ttf', 38), '#040404') 693,
await img.text(data['最高承受伤害'][0]['用户名'][:11], 693, 610, fm.get('hywh', 30), '#040404') 547,
await img.text(data['最高承受伤害'][1]['用户名'][:6], 650, 726, fm.get('hywh', 22), '#040404') fm.get('bahnschrift_regular.ttf', 68),
await img.text(data['最高承受伤害'][2]['用户名'][:6], 908, 726, fm.get('hywh', 22), '#040404') '#040404',
)
await img.text(
str(data['最高承受伤害'][1]['数值']),
650,
693,
fm.get('bahnschrift_regular.ttf', 38),
'#040404',
)
await img.text(
str(data['最高承受伤害'][2]['数值']),
908,
693,
fm.get('bahnschrift_regular.ttf', 38),
'#040404',
)
await img.text(
data['最高承受伤害'][0]['用户名'][:11], 693, 610, fm.get('hywh', 30), '#040404'
)
await img.text(
data['最高承受伤害'][1]['用户名'][:6], 650, 726, fm.get('hywh', 22), '#040404'
)
await img.text(
data['最高承受伤害'][2]['用户名'][:6], 908, 726, fm.get('hywh', 22), '#040404'
)
tag = await load_image(RESOURCE_BASE_PATH / 'general' / 'tag.png') tag = await load_image(RESOURCE_BASE_PATH / 'general' / 'tag.png')
# 角色出场率 # 角色出场率
for i in range(4): for i in range(4):
try: try:
icon, rarity, count = data['11层上半'][i][0].split('-')[0], data['11层上半'][i][0].split('-')[1], \ icon, rarity, count = (
data['11层上半'][i][1] data['11层上半'][i][0].split('-')[0],
data['11层上半'][i][0].split('-')[1],
data['11层上半'][i][1],
)
await img.paste(box[f'{rarity}bg'], (182 + i * 101, 867)) await img.paste(box[f'{rarity}bg'], (182 + i * 101, 867))
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), await img.paste(
(182 + i * 101, 867)) await load_image(
RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)
),
(182 + i * 101, 867),
)
await img.paste(tag, (236 + i * 101, 942)) await img.paste(tag, (236 + i * 101, 942))
await img.text(str(count), (236 + i * 101, 277 + i * 101), 943, fm.get('bahnschrift_regular.ttf', 19), await img.text(
'white', 'center') str(count),
(236 + i * 101, 277 + i * 101),
943,
fm.get('bahnschrift_regular.ttf', 19),
'white',
'center',
)
icon, rarity, count = data['11层下半'][i][0].split('-')[0], data['11层下半'][i][0].split('-')[1], \ icon, rarity, count = (
data['11层下半'][i][1] data['11层下半'][i][0].split('-')[0],
data['11层下半'][i][0].split('-')[1],
data['11层下半'][i][1],
)
await img.paste(box[f'{rarity}bg'], (642 + i * 101, 867)) await img.paste(box[f'{rarity}bg'], (642 + i * 101, 867))
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), await img.paste(
(642 + i * 101, 867)) await load_image(
RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)
),
(642 + i * 101, 867),
)
await img.paste(tag, (696 + i * 101, 942)) await img.paste(tag, (696 + i * 101, 942))
await img.text(str(count), (696 + i * 101, 737 + i * 101), 943, fm.get('bahnschrift_regular.ttf', 19), await img.text(
'white', 'center') str(count),
(696 + i * 101, 737 + i * 101),
943,
fm.get('bahnschrift_regular.ttf', 19),
'white',
'center',
)
icon, rarity, count = data['12层上半'][i][0].split('-')[0], data['12层上半'][i][0].split('-')[1], \ icon, rarity, count = (
data['12层上半'][i][1] data['12层上半'][i][0].split('-')[0],
data['12层上半'][i][0].split('-')[1],
data['12层上半'][i][1],
)
await img.paste(box[f'{rarity}bg'], (182 + i * 101, 983)) await img.paste(box[f'{rarity}bg'], (182 + i * 101, 983))
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), await img.paste(
(182 + i * 101, 983)) await load_image(
RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)
),
(182 + i * 101, 983),
)
await img.paste(tag, (236 + i * 101, 1058)) await img.paste(tag, (236 + i * 101, 1058))
await img.text(str(count), (236 + i * 101, 278 + i * 101), 1059, fm.get('bahnschrift_regular.ttf', 19), await img.text(
'white', 'center') str(count),
(236 + i * 101, 278 + i * 101),
1059,
fm.get('bahnschrift_regular.ttf', 19),
'white',
'center',
)
icon, rarity, count = data['12层下半'][i][0].split('-')[0], data['12层下半'][i][0].split('-')[1], \ icon, rarity, count = (
data['12层下半'][i][1] data['12层下半'][i][0].split('-')[0],
data['12层下半'][i][0].split('-')[1],
data['12层下半'][i][1],
)
await img.paste(box[f'{rarity}bg'], (642 + i * 101, 983)) await img.paste(box[f'{rarity}bg'], (642 + i * 101, 983))
await img.paste(await load_image(RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)), await img.paste(
(642 + i * 101, 983)) await load_image(
RESOURCE_BASE_PATH / 'avatar' / f'{icon}.png', size=(95, 95)
),
(642 + i * 101, 983),
)
await img.paste(tag, (696 + i * 101, 1058)) await img.paste(tag, (696 + i * 101, 1058))
await img.text(str(count), (696 + i * 101, 737 + i * 101), 1059, fm.get('bahnschrift_regular.ttf', 19), await img.text(
'white', 'center') str(count),
(696 + i * 101, 737 + i * 101),
1059,
fm.get('bahnschrift_regular.ttf', 19),
'white',
'center',
)
i += 1 i += 1
except IndexError: except IndexError:
pass pass

View File

@ -1,26 +1,27 @@
import os
import asyncio import asyncio
import contextlib import contextlib
import os
import random import random
import sys import sys
from pathlib import Path from pathlib import Path
from nonebot import on_command, get_bot, get_app
from nonebot import get_app, get_bot, on_command
from nonebot.adapters.onebot.v11 import (
ActionFailed,
Bot,
GroupMessageEvent,
Message,
MessageEvent,
)
from nonebot.params import Arg, ArgPlainText, CommandArg
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.plugin import PluginMetadata from nonebot.plugin import PluginMetadata
from nonebot.rule import to_me from nonebot.rule import to_me
from nonebot.params import CommandArg, ArgPlainText, Arg
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import (
Bot,
Message,
MessageEvent,
GroupMessageEvent,
ActionFailed,
)
from LittlePaimon.config import config from LittlePaimon.config import config
from LittlePaimon.utils import NICKNAME, DRIVER, __version__ from LittlePaimon.utils import DRIVER, NICKNAME, __version__
from LittlePaimon.utils.files import save_json, load_json from LittlePaimon.utils.files import load_json, save_json
from LittlePaimon.utils.update import check_update, update from LittlePaimon.utils.update import check_update, update
__plugin_meta__ = PluginMetadata( __plugin_meta__ = PluginMetadata(
@ -209,11 +210,11 @@ async def _(
@DRIVER.on_bot_connect @DRIVER.on_bot_connect
async def _(): async def _(bot: Bot):
if not (reboot_file := (Path() / 'rebooting.json')).exists(): if not (reboot_file := (Path() / 'rebooting.json')).exists():
return return
bot = get_bot()
reboot_data = load_json(reboot_file) reboot_data = load_json(reboot_file)
reboot_file.unlink()
if reboot_data['session_type'] == 'group': if reboot_data['session_type'] == 'group':
await bot.send_group_msg( await bot.send_group_msg(
group_id=reboot_data['session_id'], group_id=reboot_data['session_id'],
@ -230,4 +231,3 @@ async def _():
group_id=int(group_id), user_id=int(bot.self_id), card=card_info group_id=int(group_id), user_id=int(bot.self_id), card=card_info
) )
await asyncio.sleep(0.25) await asyncio.sleep(0.25)
reboot_file.unlink()