diff --git a/LittlePaimon/__init__.py b/LittlePaimon/__init__.py index eb4c111..0c13ca9 100644 --- a/LittlePaimon/__init__.py +++ b/LittlePaimon/__init__.py @@ -7,7 +7,7 @@ from LittlePaimon.utils.migration import migrate_database from LittlePaimon.utils.tool import check_resource DRIVER = get_driver() -__version__ = '3.0.0beta6' +__version__ = '3.0.0beta7' try: SUPERUSERS: List[int] = [int(s) for s in DRIVER.config.superusers] diff --git a/LittlePaimon/manager/plugin_manager/draw_help.py b/LittlePaimon/manager/plugin_manager/draw_help.py index 72d43d8..981a931 100644 --- a/LittlePaimon/manager/plugin_manager/draw_help.py +++ b/LittlePaimon/manager/plugin_manager/draw_help.py @@ -63,7 +63,7 @@ async def draw_help(plugin_list: List[PluginInfo]): await img.paste(matcher_card, (40 + 336 * matcher_group.index(matcher), height_now)) await img.text(matcher.pm_usage, 40 + 336 * matcher_group.index(matcher) + 15, height_now + 10, fm.get('SourceHanSansCN-Bold.otf', 24), 'black') if matcher.pm_description: - await img.text_box(matcher.pm_description, (40 + 336 * matcher_group.index(matcher) + 10, 40 + 336 * matcher_group.index(matcher) + matcher_card.width - 22), + await img.text_box(matcher.pm_description.replace('\n', '^'), (40 + 336 * matcher_group.index(matcher) + 10, 40 + 336 * matcher_group.index(matcher) + matcher_card.width - 22), (height_now + 44, height_now + max_height - 10), fm.get('SourceHanSansCN-Bold.otf', 18), '#40342d') height_now += max_height + 10 + 6 elif plugin.usage: diff --git a/LittlePaimon/plugins/Paimon_Wiki/__init__.py b/LittlePaimon/plugins/Paimon_Wiki/__init__.py index 5dd62d1..dde46b0 100644 --- a/LittlePaimon/plugins/Paimon_Wiki/__init__.py +++ b/LittlePaimon/plugins/Paimon_Wiki/__init__.py @@ -1,19 +1,20 @@ import time from nonebot import on_regex, on_command -from nonebot.adapters.onebot.v11 import MessageEvent, Message, MessageSegment +from nonebot.adapters.onebot.v11 import MessageEvent, Message, MessageSegment, GroupMessageEvent from nonebot.adapters.onebot.v11.helpers import HandleCancellation from nonebot.adapters.onebot.v11.exception import ActionFailed -from nonebot.params import RegexDict, ArgPlainText, CommandArg +from nonebot.params import RegexDict, ArgPlainText, CommandArg, Arg from nonebot.plugin import PluginMetadata from nonebot.typing import T_State from LittlePaimon import NICKNAME, DRIVER from LittlePaimon.utils.alias import get_match_alias +from LittlePaimon.utils.tool import freq_limiter from LittlePaimon.utils.message import MessageBuild from LittlePaimon.database.models import PlayerAlias from LittlePaimon.config import RESOURCE_BASE_PATH -from .draw_map import init_map, draw_map +from .draw_map import init_map, draw_map, get_full_map # from .abyss_rate_draw import draw_rate_rank, draw_teams_rate @@ -54,6 +55,12 @@ material_map = on_command('材料图鉴', priority=11, block=True, state={ 'pm_usage': '材料图鉴<材料名>[地图]', 'pm_priority': 9 }) +material_map_full = on_command('材料地图', priority=11, block=True, state={ + 'pm_name': '材料地图', + 'pm_description': '查看多个材料大地图采集点。\n示例:材料地图 鸣草 鬼兜虫 提瓦特', + 'pm_usage': '材料地图<材料名列表>[地图]', + 'pm_priority': 10 +}) # abyss_rate = on_command('syrate', aliases={'深渊登场率', '深境螺旋登场率', '深渊登场率排行', '深渊排行'}, priority=11, block=True, state={ @@ -101,16 +108,20 @@ async def _(event: MessageEvent, regex_dict: dict = RegexDict()): @material_map.handle() async def _(event: MessageEvent, state: T_State, msg: Message = CommandArg()): - if params := msg.extract_plain_text().strip().split(' '): + if params := msg.extract_plain_text().strip(): + params = params.split(' ') state['name'] = Message(params[0]) if len(params) > 1: if params[1] in {'提瓦特', '层岩巨渊', '渊下宫'}: state['map'] = params[1] else: state['map'] = Message('提瓦特') + else: + state['map'] = Message('提瓦特') -@material_map.got('map', prompt='地图名称有误,请在【提瓦特、层岩巨渊、渊下宫】中选择') +@material_map.got('map', prompt='地图名称有误,请在【提瓦特、层岩巨渊、渊下宫】中选择,或回答【取消】退出', + parameterless=[HandleCancellation(f'好吧,有需要再找{NICKNAME}')]) async def _(event: MessageEvent, state: T_State, map_: str = ArgPlainText('map')): if map_ not in {'提瓦特', '层岩巨渊', '渊下宫'}: await material_map.reject('地图名称有误,请在【提瓦特、层岩巨渊、渊下宫】中选择') @@ -128,21 +139,34 @@ async def _(event: MessageEvent, map_: str = ArgPlainText('map'), name: str = Ar await material_map.finish(result, at_sender=True) +@material_map_full.handle() +async def _(event: MessageEvent, state: T_State, msg: Message = CommandArg()): + state['map'] = '提瓦特' + if params := msg.extract_plain_text().strip(): + params = params.split(' ') + for p in params.copy(): + if p in {'提瓦特', '层岩巨渊', '渊下宫'}: + params.remove(p) + state['map'] = p + state['names'] = params + + +@material_map_full.got('names', prompt='请输入要查询的材料名称,或回答【取消】退出', + parameterless=[HandleCancellation(f'好吧,有需要再找{NICKNAME}')]) +async def _(event: MessageEvent, map_: str = Arg('map'), names=Arg('names')): + if isinstance(names, Message): + names = names.extract_plain_text().split(' ') + if not freq_limiter.check(f'材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}'): + await material_map_full.finish(f'材料地图查询冷却中,剩余{freq_limiter.left(f"材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}")}秒', at_sender=True) + freq_limiter.start(f'材料地图_{event.group_id if isinstance(event, GroupMessageEvent) else event.user_id}', 15) + await material_map_full.send(MessageBuild.Text(f'开始查找{"、".join(names)}的资源点,请稍候...')) + result = await get_full_map(names, map_) + await material_map_full.finish(result, at_sender=True) + + DRIVER.on_bot_connect(init_map) -# @abyss_rate.handle() -# async def abyss_rate_handler(event: MessageEvent): -# abyss_img = await draw_rate_rank() -# await abyss_rate.finish(abyss_img) - - -# @abyss_team.handle() -# async def abyss_team_handler(event: MessageEvent, reGroup=RegexDict()): -# abyss_img = await draw_teams_rate(reGroup['floor']) -# await abyss_team.finish(abyss_img) - - def create_wiki_matcher(pattern: str, help_fun: str, help_name: str): maps = on_regex(pattern, priority=11, block=True, state={ 'pm_name': help_fun, @@ -187,7 +211,7 @@ def create_wiki_matcher(pattern: str, help_fun: str, help_name: str): if isinstance(name, Message): name = name.extract_plain_text().strip() if state['type'] == '角色' and ( - match_alias := await PlayerAlias.get_or_none(user_id=str(event.user_id), alias=name)): + match_alias := await PlayerAlias.get_or_none(user_id=str(event.user_id), alias=name)): try: await maps.finish(MessageSegment.image(state['img_url'].format(match_alias.character))) except ActionFailed: diff --git a/LittlePaimon/plugins/Paimon_Wiki/draw_map.py b/LittlePaimon/plugins/Paimon_Wiki/draw_map.py index 853da86..b0f2fba 100644 --- a/LittlePaimon/plugins/Paimon_Wiki/draw_map.py +++ b/LittlePaimon/plugins/Paimon_Wiki/draw_map.py @@ -1,11 +1,12 @@ import math +from typing import List from LittlePaimon.config import RESOURCE_BASE_PATH from LittlePaimon.utils import logger, aiorequests from LittlePaimon.utils.files import load_image from LittlePaimon.utils.image import PMImage, font_manager as fm from LittlePaimon.utils.message import MessageBuild -from .genshinmap import utils, models, request, img +from .genshinmap import utils, models, request, img, XYPoint from PIL import Image, ImageFile, ImageOps ImageFile.LOAD_TRUNCATED_IMAGES = True @@ -64,7 +65,7 @@ async def draw_map(name: str, map_: str): return MessageBuild.Text(f'未查找到材料{name}') points = await request.get_points(map_id) if not (points := utils.convert_pos(utils.get_points_by_id(resource.id, points), maps.detail.origin)): - return MessageBuild.Text(f'在{map_}上未查找到材料{name},请尝试其他地图') + return MessageBuild.Text(f'{map_}未查找到材料{name},请尝试其他地图') point_icon = await load_image(RESOURCE_BASE_PATH / 'genshin_map' / 'point_icon.png') if len(points) >= 3: group_point = img.k_means_points(points, 700) @@ -110,5 +111,63 @@ async def draw_map(name: str, map_: str): return MessageBuild.Image(total_img, mode='RGB', quality=85) +async def get_full_map(names: List[str], map_: str): + map_id = models.MapID[map_name_reverse[map_]] + maps = await request.get_maps(map_id) + labels = await request.get_labels(map_id) + resources = [] + resources_not = [] + resources_points = [] + childs = [child for label in labels for child in label.children] + for name in names: + if res_filter := list(filter(lambda x: x.name == name, childs)): + resources.append(res_filter[0]) + else: + resources_not.append(name) + if not resources: + return MessageBuild.Text(f'未查找到材料{"、".join(names)}') + points = await request.get_points(map_id) + for resource in resources: + if points_ := utils.convert_pos(utils.get_points_by_id(resource.id, points), maps.detail.origin): + resources_points.append(points_) + else: + resources_not.append(resource.name) + if not resources_points: + return MessageBuild.Text(f'{map_}未查找到材料{"、".join(names)},请尝试其他地图') + map_img = await load_image(RESOURCE_BASE_PATH / 'genshin_map' / 'results' / f'{map_id.name}.png') + box_icon = await load_image(RESOURCE_BASE_PATH / 'genshin_map' / 'point_box.png') + i = 0 + max_point = XYPoint(x=0, y=0) + min_point = XYPoint(x=16384, y=12288) + for points in resources_points: + resource_icon = box_icon.copy() + resource_icon.alpha_composite(await aiorequests.get_img(resources[i].icon, size=(90, 90)), (28, 15)) + resource_icon = resource_icon.resize((48, 48), Image.ANTIALIAS) + if len(points) >= 3: + group_point = img.k_means_points(points, 16000) + else: + x1_temp = int(points[0].x) - 16000 + x2_temp = int(points[0].x) + 16000 + y1_temp = int(points[0].y) - 16000 + y2_temp = int(points[0].y) + 16000 + group_point = [( + models.XYPoint(x1_temp, y1_temp), + models.XYPoint(x2_temp, y2_temp), + points)] + lt_point = group_point[0][0] + rb_point = group_point[0][1] + min_point = XYPoint(x=min(min_point.x, lt_point.x), y=min(min_point.y, lt_point.y)) + max_point = XYPoint(x=max(max_point.x, rb_point.x), y=max(max_point.y, rb_point.y)) + for point in group_point[0][2]: + point_trans = (int(point.x), int(point.y)) + map_img.paste(resource_icon, (point_trans[0] - 24, point_trans[1] - 48), resource_icon) + i += 1 + map_img = map_img.crop((int(min_point.x) - 50, int(min_point.y) - 50, int(max_point.x) + 50, int(max_point.y) + 50)) + if resources_not: + return MessageBuild.Text(f'{map_}未找到材料{"、".join(resources_not)},请尝试其他地图\n') + MessageBuild.Image(map_img) + else: + return MessageBuild.Image(map_img) + +