🚧完成sr抽卡记录
@ -5,8 +5,7 @@ from gsuid_core.models import Event
|
||||
from ..utils.convert import get_uid
|
||||
from ..utils.error_reply import UID_HINT
|
||||
from .get_gachalogs import save_gachalogs
|
||||
|
||||
# from .draw_gachalogs import draw_gachalogs_img
|
||||
from .draw_gachalogs import draw_gachalogs_img
|
||||
|
||||
sv_gacha_log = SV('sr抽卡记录')
|
||||
sv_get_gachalog_by_link = SV('sr导入抽卡链接', area='DIRECT')
|
||||
@ -18,8 +17,7 @@ async def send_gacha_log_card_info(bot: Bot, ev: Event):
|
||||
uid, user_id = await get_uid(bot, ev, True)
|
||||
if uid is None:
|
||||
return await bot.send(UID_HINT)
|
||||
# im = await draw_gachalogs_img(uid, user_id)
|
||||
im = '画个饼先,在做了在做了'
|
||||
im = await draw_gachalogs_img(uid, user_id)
|
||||
await bot.send(im)
|
||||
|
||||
|
||||
|
@ -1,426 +1,438 @@
|
||||
# import json
|
||||
# import random
|
||||
# import asyncio
|
||||
# import datetime
|
||||
# from pathlib import Path
|
||||
# from typing import List, Tuple, Union
|
||||
#
|
||||
# from PIL import Image, ImageDraw
|
||||
# from gsuid_core.logger import logger
|
||||
#
|
||||
# from ..utils.image.convert import convert_img
|
||||
# from ..utils.map.name_covert import name_to_avatar_id
|
||||
# from ..utils.resource.RESOURCE_PATH import
|
||||
# CHAR_PATH, PLAYER_PATH, WEAPON_PATH
|
||||
# from ..utils.image.image_tools import (
|
||||
# get_color_bg,
|
||||
# get_qq_avatar,
|
||||
# draw_pic_with_ring,
|
||||
# )
|
||||
# from ..utils.fonts.starrail_fonts import (
|
||||
# sr_font_24,
|
||||
# sr_font_28,
|
||||
# sr_font_36,
|
||||
# sr_font_40,
|
||||
# sr_font_62,
|
||||
# )
|
||||
#
|
||||
# TEXT_PATH = Path(__file__).parent / 'texture2d'
|
||||
#
|
||||
import json
|
||||
import asyncio
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
from gsuid_core.logger import logger
|
||||
|
||||
from ..utils.image.convert import convert_img
|
||||
from ..utils.map.name_covert import name_to_avatar_id
|
||||
from ..utils.resource.RESOURCE_PATH import (
|
||||
PLAYER_PATH,
|
||||
WEAPON_PATH,
|
||||
CHAR_ICON_PATH,
|
||||
)
|
||||
from ..utils.image.image_tools import (
|
||||
get_color_bg,
|
||||
get_qq_avatar,
|
||||
draw_pic_with_ring,
|
||||
)
|
||||
from ..utils.fonts.starrail_fonts import (
|
||||
sr_font_20,
|
||||
sr_font_24,
|
||||
sr_font_28,
|
||||
sr_font_38,
|
||||
sr_font_40,
|
||||
)
|
||||
|
||||
TEXT_PATH = Path(__file__).parent / 'texture2d'
|
||||
EMO_PATH = Path(__file__).parent / 'texture2d' / 'emo'
|
||||
|
||||
# up_tag = Image.open(TEXT_PATH / 'up.png')
|
||||
#
|
||||
# first_color = (29, 29, 29)
|
||||
# brown_color = (41, 25, 0)
|
||||
# red_color = (255, 66, 66)
|
||||
# green_color = (74, 189, 119)
|
||||
#
|
||||
# CHANGE_MAP = {'常驻祈愿': 'normal', '角色祈愿': 'char', '武器祈愿': 'weapon'}
|
||||
# HOMO_TAG = ['非到极致', '运气不好', '平稳保底', '小欧一把', '欧狗在此']
|
||||
# NORMAL_LIST = [
|
||||
# '莫娜',
|
||||
# '迪卢克',
|
||||
# '七七',
|
||||
# '琴',
|
||||
# '阿莫斯之弓',
|
||||
# '天空之翼',
|
||||
# '四风原典',
|
||||
# '天空之卷',
|
||||
# '和璞鸢',
|
||||
# '天空之脊',
|
||||
# '狼的末路',
|
||||
# '天空之傲',
|
||||
# '风鹰剑',
|
||||
# '天空之刃',
|
||||
# ]
|
||||
#
|
||||
# UP_LIST = {
|
||||
# '刻晴': [(2021, 2, 17, 18, 0, 0), (2021, 3, 2, 15, 59, 59)],
|
||||
# '提纳里': [(2022, 8, 24, 11, 0, 0), (2022, 9, 9, 17, 59, 59)],
|
||||
# '迪希雅': [(2023, 3, 1, 11, 0, 0), (2023, 3, 21, 17, 59, 59)],
|
||||
# }
|
||||
#
|
||||
#
|
||||
# async def _draw_card(
|
||||
# img: Image.Image,
|
||||
# xy_point: Tuple[int, int],
|
||||
# name: str,
|
||||
# gacha_num: int,
|
||||
# is_up: bool,
|
||||
# ):
|
||||
# card_img = Image.open(TEXT_PATH / 'item_bg.png')
|
||||
# card_img_draw = ImageDraw.Draw(card_img)
|
||||
# point = (1, 0)
|
||||
# text_point = (55, 124)
|
||||
# if type == '角色':
|
||||
# _id = await name_to_avatar_id(name)
|
||||
# item_pic = (
|
||||
# Image.open(CHAR_PATH / f'{_id}.png')
|
||||
# .convert('RGBA')
|
||||
# .resize((108, 108))
|
||||
# )
|
||||
# else:
|
||||
# item_pic = (
|
||||
# Image.open(WEAPON_PATH / f'{name}.png')
|
||||
# .convert('RGBA')
|
||||
# .resize((108, 108))
|
||||
# )
|
||||
# card_img.paste(item_pic, point, item_pic)
|
||||
# if gacha_num >= 81:
|
||||
# text_color = red_color
|
||||
# elif gacha_num <= 55:
|
||||
# text_color = green_color
|
||||
# else:
|
||||
# text_color = brown_color
|
||||
# card_img_draw.text(
|
||||
# text_point, f'{gacha_num}抽', text_color, gs_font_24, 'mm'
|
||||
# )
|
||||
# if is_up:
|
||||
# card_img.paste(up_tag, (47, -2), up_tag)
|
||||
# img.paste(card_img, xy_point, card_img)
|
||||
#
|
||||
#
|
||||
# async def random_emo_pic(level: int) -> Image.Image:
|
||||
# emo_fold = TEXT_PATH / str(level)
|
||||
# return Image.open(random.choice(list(emo_fold.iterdir())))
|
||||
#
|
||||
#
|
||||
# async def get_level_from_list(ast: int, lst: List) -> int:
|
||||
# if ast == 0:
|
||||
# return 3
|
||||
#
|
||||
# for num_index, num in enumerate(lst):
|
||||
# if ast <= num:
|
||||
# level = 5 - num_index
|
||||
# break
|
||||
# else:
|
||||
# level = 1
|
||||
# return level
|
||||
#
|
||||
#
|
||||
# def check_up(name: str, _time: str) -> bool:
|
||||
# for char in UP_LIST:
|
||||
# if char == name:
|
||||
# time = UP_LIST[char]
|
||||
# s_time = datetime.datetime(*time[0])
|
||||
# e_time = datetime.datetime(*time[1])
|
||||
# gacha_time = datetime.datetime.strptime
|
||||
# (_time, '%Y-%m-%d %H:%M:%S')
|
||||
# if gacha_time < s_time or gacha_time > e_time:
|
||||
# return False
|
||||
# else:
|
||||
# return True
|
||||
# else:
|
||||
# return False
|
||||
#
|
||||
#
|
||||
# async def draw_gachalogs_img(uid: str, user_id: str) -> Union[bytes, str]:
|
||||
# path = PLAYER_PATH / str(uid) / 'gacha_logs.json'
|
||||
# if not path.exists():
|
||||
# return '你还没有祈愿数据噢~\n请添加Stoken后使用命令`刷新抽卡记录`更新祈愿数据~'
|
||||
# with open(path, 'r', encoding='UTF-8') as f:
|
||||
# gacha_data = json.load(f)
|
||||
#
|
||||
# # 数据初始化
|
||||
# total_data = {}
|
||||
# for i in ['群星跃迁', '角色跃迁', '光锥跃迁']:
|
||||
# total_data[i] = {
|
||||
# 'total': 0, # 五星总数
|
||||
# 'avg': 0, # 抽卡平均数
|
||||
# 'avg_up': 0, # up平均数
|
||||
# 'remain': 0, # 已xx抽未出金
|
||||
# 'r_num': [], # 不包含首位的抽卡数量
|
||||
# 'e_num': [], # 包含首位的up抽卡数量
|
||||
# 'up_list': [], # 抽到的UP列表(不包含首位)
|
||||
# 'normal_list': [], # 抽到的五星列表(不包含首位)
|
||||
# 'list': [], # 抽到的五星列表
|
||||
# 'time_range': '', # 抽卡时间
|
||||
# 'all_time': 0, # 抽卡总计秒数
|
||||
# 'type': '一般型', # 抽卡类型: 随缘型, 氪金型, 规划型, 仓鼠型, 佛系型
|
||||
# 'short_gacha_data': {'time': 0, 'num': 0},
|
||||
# 'long_gacha_data': {'time': 0, 'num': 0},
|
||||
# }
|
||||
# # 拿到数据列表
|
||||
# data_list = gacha_data['list'][i]
|
||||
# # 初始化开关
|
||||
# is_not_first = False
|
||||
# # 开始初始化抽卡数
|
||||
# num = 1
|
||||
# # 从后面开始循环
|
||||
# temp_time = datetime.datetime(2023, 4, 26, 8, 0, 0)
|
||||
# for index, data in enumerate(data_list[::-1]):
|
||||
# # 计算抽卡时间跨度
|
||||
# if index == 0:
|
||||
# total_data[i]['time_range'] = data['time']
|
||||
# if index == len(data_list) - 1:
|
||||
# total_data[i]['all_time'] = (
|
||||
# datetime.datetime.strptime(
|
||||
# data['time'], '%Y-%m-%d %H:%M:%S'
|
||||
# )
|
||||
# - datetime.datetime.strptime(
|
||||
# total_data[i]['time_range'], '%Y-%m-%d %H:%M:%S'
|
||||
# )
|
||||
# ).total_seconds()
|
||||
# total_data[i]['time_range'] += '~' + data['time']
|
||||
#
|
||||
# # 计算时间间隔
|
||||
# if index != 0:
|
||||
# now_time = datetime.datetime.strptime(
|
||||
# data['time'], '%Y-%m-%d %H:%M:%S'
|
||||
# )
|
||||
# dis = (now_time - temp_time).total_seconds()
|
||||
# temp_time = now_time
|
||||
# if dis <= 5000:
|
||||
# total_data[i]['short_gacha_data']['num'] += 1
|
||||
# total_data[i]['short_gacha_data']['time'] += dis
|
||||
# elif dis >= 86400:
|
||||
# total_data[i]['long_gacha_data']['num'] += 1
|
||||
# total_data[i]['long_gacha_data']['time'] += dis
|
||||
# else:
|
||||
# temp_time = datetime.datetime.strptime(
|
||||
# data['time'], '%Y-%m-%d %H:%M:%S'
|
||||
# )
|
||||
#
|
||||
# # 如果这是个五星
|
||||
# if data['rank_type'] == '5':
|
||||
# # 抽到这个五星花了多少抽
|
||||
# data['gacha_num'] = num
|
||||
#
|
||||
# # 判断是否是UP
|
||||
# if data['name'] in NORMAL_LIST:
|
||||
# data['is_up'] = False
|
||||
# elif data['name'] in UP_LIST:
|
||||
# data['is_up'] = check_up(data['name'], data['time'])
|
||||
# else:
|
||||
# data['is_up'] = True
|
||||
#
|
||||
# # 往里加东西
|
||||
# if is_not_first:
|
||||
# total_data[i]['r_num'].append(num)
|
||||
# total_data[i]['normal_list'].append(data)
|
||||
# if data['is_up']:
|
||||
# total_data[i]['up_list'].append(data)
|
||||
#
|
||||
# # 把这个数据扔到抽到的五星列表内
|
||||
# total_data[i]['list'].append(data)
|
||||
#
|
||||
# # 判断经过了第一个
|
||||
# if total_data[i]['list']:
|
||||
# is_not_first = True
|
||||
#
|
||||
# num = 1
|
||||
# # 五星总数增加1
|
||||
# total_data[i]['total'] += 1
|
||||
# else:
|
||||
# num += 1
|
||||
#
|
||||
# # 计算已多少抽
|
||||
# total_data[i]['remain'] = num - 1
|
||||
#
|
||||
# # 计算平均抽卡数
|
||||
# if len(total_data[i]['normal_list']) == 0:
|
||||
# total_data[i]['avg'] = 0
|
||||
# else:
|
||||
# total_data[i]['avg'] = float(
|
||||
# '{:.2f}'.format(
|
||||
# sum(total_data[i]['r_num']) / len(total_data[i]['r_num'])
|
||||
# )
|
||||
# )
|
||||
# # 计算平均up数量
|
||||
# if len(total_data[i]['up_list']) == 0:
|
||||
# total_data[i]['avg_up'] = 0
|
||||
# else:
|
||||
# total_data[i]['avg_up'] = float(
|
||||
# '{:.2f}'.format(
|
||||
# sum(total_data[i]['r_num'])
|
||||
# / len(total_data[i]['up_list'])
|
||||
# )
|
||||
# )
|
||||
#
|
||||
# # 计算抽卡类型
|
||||
# # 如果抽卡总数小于40
|
||||
# if gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] <= 40:
|
||||
# total_data[i]['type'] = '佛系型'
|
||||
# # 如果长时抽卡总数占据了总抽卡数的70%
|
||||
# elif (
|
||||
# total_data[i]['long_gacha_data']['num']
|
||||
# / gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||
# >= 0.7
|
||||
# ):
|
||||
# total_data[i]['type'] = '随缘型'
|
||||
# # 如果短时抽卡总数占据了总抽卡数的70%
|
||||
# elif (
|
||||
# total_data[i]['short_gacha_data']['num']
|
||||
# / gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||
# >= 0.7
|
||||
# ):
|
||||
# total_data[i]['type'] = '规划型'
|
||||
# # 如果抽卡数量远远大于标称抽卡数量
|
||||
# elif (
|
||||
# total_data[i]['all_time'] / 30000
|
||||
# <= gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||
# ):
|
||||
# # 如果长时抽卡数量大于短时抽卡数量
|
||||
# if (
|
||||
# total_data[i]['long_gacha_data']['num']
|
||||
# >= total_data[i]['short_gacha_data']['num']
|
||||
# ):
|
||||
# total_data[i]['type'] = '规划型'
|
||||
# else:
|
||||
# total_data[i]['type'] = '氪金型'
|
||||
# # 如果抽卡数量远远小于标称抽卡数量
|
||||
# elif (
|
||||
# total_data[i]['all_time'] / 32000
|
||||
# >= gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] * 2
|
||||
# ):
|
||||
# total_data[i]['type'] = '仓鼠型'
|
||||
#
|
||||
# # 常量偏移数据
|
||||
# single_y = 150
|
||||
#
|
||||
# # 计算图片尺寸
|
||||
# normal_y = (1 + ((total_data['常驻祈愿']['total'] - 1) // 6)) * single_y
|
||||
# char_y = (1 + ((total_data['角色祈愿']['total'] - 1) // 6)) * single_y
|
||||
# weapon_y = (1 + ((total_data['武器祈愿']['total'] - 1) // 6)) * single_y
|
||||
#
|
||||
# # 获取背景图片各项参数
|
||||
# _id = str(user_id)
|
||||
# if _id.startswith('http'):
|
||||
# char_pic = await get_qq_avatar(avatar_url=_id)
|
||||
# else:
|
||||
# char_pic = await get_qq_avatar(qid=user_id)
|
||||
# char_pic = await draw_pic_with_ring(char_pic, 320)
|
||||
#
|
||||
# avatar_title = Image.open(TEXT_PATH / 'avatar_title.png')
|
||||
# img = await get_color_bg(950, 530 + 900 + normal_y + char_y + weapon_y)
|
||||
# img.paste(avatar_title, (0, 0), avatar_title)
|
||||
# img.paste(char_pic, (318, 83), char_pic)
|
||||
# img_draw = ImageDraw.Draw(img)
|
||||
# img_draw.text((475, 454), f'UID {uid}', first_color, gs_font_36, 'mm')
|
||||
#
|
||||
# # 处理title
|
||||
# # {'total': 0, 'avg': 0, 'remain': 0, 'list': []}
|
||||
# type_list = ['常驻祈愿', '角色祈愿', '武器祈愿']
|
||||
# y_extend = 0
|
||||
# level = 3
|
||||
# for index, i in enumerate(type_list):
|
||||
# title = Image.open(TEXT_PATH / 'gahca_title.png')
|
||||
# if i == '常驻祈愿':
|
||||
# level = await get_level_from_list(
|
||||
# total_data[i]['avg'], [54, 61, 67, 73, 80]
|
||||
# )
|
||||
# else:
|
||||
# if i == '武器祈愿':
|
||||
# level = await get_level_from_list(
|
||||
# total_data[i]['avg_up'], [62, 75, 88, 99, 111]
|
||||
# )
|
||||
# else:
|
||||
# level = await get_level_from_list(
|
||||
# total_data[i]['avg_up'], [74, 87, 99, 105, 120]
|
||||
# )
|
||||
#
|
||||
# emo_pic = await random_emo_pic(level)
|
||||
# emo_pic = emo_pic.resize((154, 154))
|
||||
# title.paste(emo_pic, (703, 28), emo_pic)
|
||||
# title_draw = ImageDraw.Draw(title)
|
||||
# # 欧非描述
|
||||
# title_draw.text(
|
||||
# (778, 207), HOMO_TAG[level - 1], first_color, gs_font_36, 'mm'
|
||||
# )
|
||||
# # 卡池
|
||||
# title_draw.text((69, 72), i, first_color, gs_font_62, 'lm')
|
||||
# # 抽卡时间
|
||||
# if total_data[i]['time_range']:
|
||||
# time_range = total_data[i]['time_range']
|
||||
# else:
|
||||
# time_range = '暂未抽过卡!'
|
||||
# title_draw.text((68, 122), time_range, brown_color, gs_font_28, 'lm')
|
||||
# # 平均抽卡数量
|
||||
# title_draw.text(
|
||||
# (123, 176),
|
||||
# str(total_data[i]['avg']),
|
||||
# first_color,
|
||||
# gs_font_40,
|
||||
# 'mm',
|
||||
# )
|
||||
# # 平均up
|
||||
# title_draw.text(
|
||||
# (272, 176),
|
||||
# str(total_data[i]['avg_up']),
|
||||
# first_color,
|
||||
# gs_font_40,
|
||||
# 'mm',
|
||||
# )
|
||||
# # 抽卡总数
|
||||
# title_draw.text(
|
||||
# (424, 176),
|
||||
# str(gacha_data[f'{CHANGE_MAP[i]}_gacha_num']),
|
||||
# first_color,
|
||||
# gs_font_40,
|
||||
# 'mm',
|
||||
# )
|
||||
# # 抽卡类型
|
||||
# title_draw.text(
|
||||
# (585, 176),
|
||||
# str(total_data[i]['type']),
|
||||
# first_color,
|
||||
# gs_font_40,
|
||||
# 'mm',
|
||||
# )
|
||||
# # 已抽数
|
||||
# title_draw.text(
|
||||
# (383, 85),
|
||||
# str(total_data[i]['remain']),
|
||||
# red_color,
|
||||
# gs_font_28,
|
||||
# 'mm',
|
||||
# )
|
||||
# y_extend += (
|
||||
# (1 + ((total_data[type_list[index - 1]]
|
||||
# ['total'] - 1) // 6)) * 150
|
||||
# if index != 0
|
||||
# else 0
|
||||
# )
|
||||
# y = 540 + index * 300 + y_extend
|
||||
# img.paste(title, (0, y), title)
|
||||
# tasks = []
|
||||
# for item_index, item in enumerate(total_data[i]['list']):
|
||||
# item_x = (item_index % 6) * 138 + 60
|
||||
# item_y = (item_index // 6) * 150 + y + 275
|
||||
# xy_point = (item_x, item_y)
|
||||
# tasks.append(
|
||||
# _draw_card(
|
||||
# img,
|
||||
# xy_point,
|
||||
# item['item_type'],
|
||||
# item['name'],
|
||||
# item['gacha_num'],
|
||||
# item['is_up'],
|
||||
# )
|
||||
# )
|
||||
# await asyncio.gather(*tasks)
|
||||
# tasks.clear()
|
||||
#
|
||||
# # 发送图片
|
||||
# res = await convert_img(img)
|
||||
# logger.info('[查询抽卡]绘图已完成,等待发送!')
|
||||
# return res
|
||||
Abg3_img = Image.open(TEXT_PATH / 'Abg3.png')
|
||||
bg1_img = Image.open(TEXT_PATH / 'bg1.png')
|
||||
|
||||
first_color = (29, 29, 29)
|
||||
brown_color = (41, 25, 0)
|
||||
red_color = (255, 66, 66)
|
||||
green_color = (74, 189, 119)
|
||||
white_color = (213, 213, 213)
|
||||
whole_white_color = (255, 255, 255)
|
||||
|
||||
CHANGE_MAP = {
|
||||
'始发跃迁': 'begin',
|
||||
'群星跃迁': 'normal',
|
||||
'角色跃迁': 'char',
|
||||
'光锥跃迁': 'weapon',
|
||||
}
|
||||
HOMO_TAG = ['非到极致', '运气不好', '平稳保底', '小欧一把', '欧狗在此']
|
||||
NORMAL_LIST = [
|
||||
'彦卿',
|
||||
'白露',
|
||||
'姬子',
|
||||
'瓦尔特',
|
||||
'布洛妮娅',
|
||||
'克拉拉',
|
||||
'杰帕德',
|
||||
'银河铁道之夜',
|
||||
'以世界之名',
|
||||
'但战斗还未结束',
|
||||
'制胜的瞬间',
|
||||
'无可取代的东西',
|
||||
'时节不居',
|
||||
]
|
||||
|
||||
UP_LIST = {
|
||||
'刻晴': [(2021, 2, 17, 18, 0, 0), (2021, 3, 2, 15, 59, 59)],
|
||||
'提纳里': [(2022, 8, 24, 11, 0, 0), (2022, 9, 9, 17, 59, 59)],
|
||||
'迪希雅': [(2023, 3, 1, 11, 0, 0), (2023, 3, 21, 17, 59, 59)],
|
||||
}
|
||||
|
||||
|
||||
async def _draw_card(
|
||||
img: Image.Image,
|
||||
xy_point: Tuple[int, int],
|
||||
type: str,
|
||||
name: str,
|
||||
gacha_num: int,
|
||||
is_up: bool,
|
||||
):
|
||||
card_img = Image.open(TEXT_PATH / 'char_bg.png')
|
||||
card_img_draw = ImageDraw.Draw(card_img)
|
||||
point = (47, 31)
|
||||
text_point = (100, 165)
|
||||
if type == '角色':
|
||||
_id = await name_to_avatar_id(name)
|
||||
item_pic = (
|
||||
Image.open(CHAR_ICON_PATH / f'{_id}.png')
|
||||
.convert('RGBA')
|
||||
.crop((0, 0, 112, 112))
|
||||
.resize((105, 105))
|
||||
)
|
||||
else:
|
||||
item_pic = (
|
||||
Image.open(WEAPON_PATH / f'{name}.png')
|
||||
.convert('RGBA')
|
||||
.crop((0, 0, 867, 867))
|
||||
)
|
||||
item_pic = item_pic.resize((105, 105))
|
||||
card_img.paste(item_pic, point, item_pic)
|
||||
if gacha_num >= 81:
|
||||
text_color = red_color
|
||||
elif gacha_num <= 55:
|
||||
text_color = green_color
|
||||
else:
|
||||
text_color = brown_color
|
||||
card_img_draw.text(
|
||||
text_point, f'{gacha_num}抽', text_color, sr_font_24, 'mm'
|
||||
)
|
||||
if is_up:
|
||||
print(f'up: {name}')
|
||||
# card_img.paste(up_tag, (47, -2), up_tag)
|
||||
img.paste(card_img, xy_point, card_img)
|
||||
|
||||
|
||||
async def random_emo_pic(level: int) -> Image.Image:
|
||||
emo_fold = EMO_PATH / f'3000{level}.png'
|
||||
return Image.open(emo_fold)
|
||||
|
||||
|
||||
async def get_level_from_list(ast: int, lst: List) -> int:
|
||||
if ast == 0:
|
||||
return 3
|
||||
|
||||
for num_index, num in enumerate(lst):
|
||||
if ast <= num:
|
||||
level = 5 - num_index
|
||||
break
|
||||
else:
|
||||
level = 1
|
||||
return level
|
||||
|
||||
|
||||
def check_up(name: str, _time: str) -> bool:
|
||||
for char in UP_LIST:
|
||||
if char == name:
|
||||
time = UP_LIST[char]
|
||||
s_time = datetime.datetime(*time[0])
|
||||
e_time = datetime.datetime(*time[1])
|
||||
gacha_time = datetime.datetime.strptime(_time, '%Y-%m-%d %H:%M:%S')
|
||||
if gacha_time < s_time or gacha_time > e_time:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
async def draw_gachalogs_img(uid: str, user_id: str) -> Union[bytes, str]:
|
||||
path = PLAYER_PATH / str(uid) / 'gacha_logs_test.json'
|
||||
if not path.exists():
|
||||
return '你还没有跃迁数据噢~\n请使用命令`sr导入抽卡链接`更新跃迁数据~'
|
||||
with open(path, 'r', encoding='UTF-8') as f:
|
||||
gacha_data = json.load(f)
|
||||
|
||||
# 数据初始化
|
||||
total_data = {}
|
||||
for i in ['群星跃迁', '始发跃迁', '角色跃迁', '光锥跃迁']:
|
||||
total_data[i] = {
|
||||
'total': 0, # 五星总数
|
||||
'avg': 0, # 抽卡平均数
|
||||
'avg_up': 0, # up平均数
|
||||
'remain': 0, # 已xx抽未出金
|
||||
'r_num': [], # 不包含首位的抽卡数量
|
||||
'e_num': [], # 包含首位的up抽卡数量
|
||||
'up_list': [], # 抽到的UP列表(不包含首位)
|
||||
'normal_list': [], # 抽到的五星列表(不包含首位)
|
||||
'list': [], # 抽到的五星列表
|
||||
'time_range': '', # 抽卡时间
|
||||
'all_time': 0, # 抽卡总计秒数
|
||||
'type': '一般型', # 抽卡类型: 随缘型, 氪金型, 规划型, 仓鼠型, 佛系型
|
||||
'short_gacha_data': {'time': 0, 'num': 0},
|
||||
'long_gacha_data': {'time': 0, 'num': 0},
|
||||
}
|
||||
# 拿到数据列表
|
||||
data_list = gacha_data['data'][i]
|
||||
print(data_list)
|
||||
# 初始化开关
|
||||
is_not_first = True
|
||||
# 开始初始化抽卡数
|
||||
num = 1
|
||||
# 从后面开始循环
|
||||
temp_time = datetime.datetime(2023, 4, 26, 8, 0, 0)
|
||||
for index, data in enumerate(data_list[::-1]):
|
||||
# 计算抽卡时间跨度
|
||||
if index == 0:
|
||||
total_data[i]['time_range'] = data['time']
|
||||
if index == len(data_list) - 1:
|
||||
total_data[i]['all_time'] = (
|
||||
datetime.datetime.strptime(
|
||||
data['time'], '%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
- datetime.datetime.strptime(
|
||||
total_data[i]['time_range'], '%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
).total_seconds()
|
||||
total_data[i]['time_range'] += '~' + data['time']
|
||||
|
||||
# 计算时间间隔
|
||||
if index != 0:
|
||||
now_time = datetime.datetime.strptime(
|
||||
data['time'], '%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
dis = (now_time - temp_time).total_seconds()
|
||||
temp_time = now_time
|
||||
if dis <= 5000:
|
||||
total_data[i]['short_gacha_data']['num'] += 1
|
||||
total_data[i]['short_gacha_data']['time'] += dis
|
||||
elif dis >= 86400:
|
||||
total_data[i]['long_gacha_data']['num'] += 1
|
||||
total_data[i]['long_gacha_data']['time'] += dis
|
||||
else:
|
||||
temp_time = datetime.datetime.strptime(
|
||||
data['time'], '%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# 如果这是个五星
|
||||
if data['rank_type'] == '5':
|
||||
# 抽到这个五星花了多少抽
|
||||
data['gacha_num'] = num
|
||||
|
||||
# 判断是否是UP
|
||||
if data['name'] in NORMAL_LIST:
|
||||
data['is_up'] = False
|
||||
elif data['name'] in UP_LIST:
|
||||
data['is_up'] = check_up(data['name'], data['time'])
|
||||
else:
|
||||
data['is_up'] = True
|
||||
|
||||
# 往里加东西
|
||||
if is_not_first:
|
||||
total_data[i]['r_num'].append(num)
|
||||
total_data[i]['normal_list'].append(data)
|
||||
if data['is_up']:
|
||||
total_data[i]['up_list'].append(data)
|
||||
|
||||
# 把这个数据扔到抽到的五星列表内
|
||||
total_data[i]['list'].append(data)
|
||||
|
||||
# 判断经过了第一个
|
||||
if total_data[i]['list']:
|
||||
is_not_first = True
|
||||
|
||||
num = 1
|
||||
# 五星总数增加1
|
||||
total_data[i]['total'] += 1
|
||||
else:
|
||||
num += 1
|
||||
|
||||
# 计算已多少抽
|
||||
total_data[i]['remain'] = num - 1
|
||||
|
||||
# 计算平均抽卡数
|
||||
if len(total_data[i]['normal_list']) == 0:
|
||||
total_data[i]['avg'] = 0
|
||||
else:
|
||||
total_data[i]['avg'] = float(
|
||||
'{:.2f}'.format(
|
||||
sum(total_data[i]['r_num']) / len(total_data[i]['r_num'])
|
||||
)
|
||||
)
|
||||
# 计算平均up数量
|
||||
if len(total_data[i]['up_list']) == 0:
|
||||
total_data[i]['avg_up'] = 0
|
||||
else:
|
||||
total_data[i]['avg_up'] = float(
|
||||
'{:.2f}'.format(
|
||||
sum(total_data[i]['r_num']) / len(total_data[i]['up_list'])
|
||||
)
|
||||
)
|
||||
|
||||
# 计算抽卡类型
|
||||
# 如果抽卡总数小于40
|
||||
if gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] <= 40:
|
||||
total_data[i]['type'] = '佛系型'
|
||||
# 如果长时抽卡总数占据了总抽卡数的70%
|
||||
elif (
|
||||
total_data[i]['long_gacha_data']['num']
|
||||
/ gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||
>= 0.7
|
||||
):
|
||||
total_data[i]['type'] = '随缘型'
|
||||
# 如果短时抽卡总数占据了总抽卡数的70%
|
||||
elif (
|
||||
total_data[i]['short_gacha_data']['num']
|
||||
/ gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||
>= 0.7
|
||||
):
|
||||
total_data[i]['type'] = '规划型'
|
||||
# 如果抽卡数量远远大于标称抽卡数量
|
||||
elif (
|
||||
total_data[i]['all_time'] / 30000
|
||||
<= gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||
):
|
||||
# 如果长时抽卡数量大于短时抽卡数量
|
||||
if (
|
||||
total_data[i]['long_gacha_data']['num']
|
||||
>= total_data[i]['short_gacha_data']['num']
|
||||
):
|
||||
total_data[i]['type'] = '规划型'
|
||||
else:
|
||||
total_data[i]['type'] = '氪金型'
|
||||
# 如果抽卡数量远远小于标称抽卡数量
|
||||
elif (
|
||||
total_data[i]['all_time'] / 32000
|
||||
>= gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] * 2
|
||||
):
|
||||
total_data[i]['type'] = '仓鼠型'
|
||||
|
||||
print(total_data)
|
||||
# 常量偏移数据
|
||||
single_y = 150
|
||||
|
||||
# 计算图片尺寸
|
||||
normal_y = (1 + ((total_data['群星跃迁']['total'] - 1) // 6)) * single_y
|
||||
begin_y = (1 + ((total_data['始发跃迁']['total'] - 1) // 6)) * single_y
|
||||
char_y = (1 + ((total_data['角色跃迁']['total'] - 1) // 6)) * single_y
|
||||
weapon_y = (1 + ((total_data['光锥跃迁']['total'] - 1) // 6)) * single_y
|
||||
|
||||
# 获取背景图片各项参数
|
||||
_id = str(user_id)
|
||||
if _id.startswith('http'):
|
||||
char_pic = await get_qq_avatar(avatar_url=_id)
|
||||
else:
|
||||
char_pic = await get_qq_avatar(qid=user_id)
|
||||
char_pic = await draw_pic_with_ring(char_pic, 206)
|
||||
|
||||
# 获取背景图片各项参数
|
||||
img = Abg3_img.copy()
|
||||
img = await get_color_bg(
|
||||
800, 1600 + 400 + normal_y + char_y + weapon_y + begin_y
|
||||
)
|
||||
gacha_title = bg1_img.copy()
|
||||
gacha_title.paste(char_pic, (297, 81), char_pic)
|
||||
img.paste(gacha_title, (0, 0), gacha_title)
|
||||
img_draw = ImageDraw.Draw(img)
|
||||
img_draw.text((400, 345), f'UID {uid}', white_color, sr_font_28, 'mm')
|
||||
|
||||
# 处理title
|
||||
# {'total': 0, 'avg': 0, 'remain': 0, 'list': []}
|
||||
type_list = ['群星跃迁', '始发跃迁', '角色跃迁', '光锥跃迁']
|
||||
y_extend = 0
|
||||
level = 3
|
||||
for index, i in enumerate(type_list):
|
||||
title = Image.open(TEXT_PATH / 'bg2.png')
|
||||
if i == '群星跃迁':
|
||||
level = await get_level_from_list(
|
||||
total_data[i]['avg'], [54, 61, 67, 73, 80]
|
||||
)
|
||||
elif i == '始发跃迁':
|
||||
level = await get_level_from_list(
|
||||
total_data[i]['avg'], [62, 75, 88, 99, 111]
|
||||
)
|
||||
else:
|
||||
if i == '光锥跃迁':
|
||||
level = await get_level_from_list(
|
||||
total_data[i]['avg_up'], [62, 75, 88, 99, 111]
|
||||
)
|
||||
else:
|
||||
level = await get_level_from_list(
|
||||
total_data[i]['avg_up'], [74, 87, 99, 105, 120]
|
||||
)
|
||||
|
||||
emo_pic = await random_emo_pic(level)
|
||||
emo_pic = emo_pic.resize((195, 195))
|
||||
title.paste(emo_pic, (500, 123), emo_pic)
|
||||
title_draw = ImageDraw.Draw(title)
|
||||
# 卡池
|
||||
title_draw.text((110, 73), i, whole_white_color, sr_font_38, 'lm')
|
||||
# 抽卡时间
|
||||
if total_data[i]['time_range']:
|
||||
time_range = total_data[i]['time_range']
|
||||
else:
|
||||
time_range = '暂未抽过卡!'
|
||||
title_draw.text((78, 340), time_range, brown_color, sr_font_20, 'lm')
|
||||
# 平均抽卡数量
|
||||
title_draw.text(
|
||||
(143, 215),
|
||||
str(total_data[i]['avg']),
|
||||
first_color,
|
||||
sr_font_40,
|
||||
'mm',
|
||||
)
|
||||
# 平均up
|
||||
title_draw.text(
|
||||
(280, 215),
|
||||
str(total_data[i]['avg_up']),
|
||||
first_color,
|
||||
sr_font_40,
|
||||
'mm',
|
||||
)
|
||||
# 抽卡总数
|
||||
title_draw.text(
|
||||
(413, 215),
|
||||
str(gacha_data[f'{CHANGE_MAP[i]}_gacha_num']),
|
||||
first_color,
|
||||
sr_font_40,
|
||||
'mm',
|
||||
)
|
||||
# 已抽数
|
||||
title_draw.text(
|
||||
(333, 75),
|
||||
str(total_data[i]['remain']),
|
||||
red_color,
|
||||
sr_font_28,
|
||||
'mm',
|
||||
)
|
||||
y_extend += (
|
||||
(1 + ((total_data[type_list[index - 1]]['total'] - 1) // 6)) * 150
|
||||
if index != 0
|
||||
else 0
|
||||
)
|
||||
y = 350 + index * 400 + y_extend
|
||||
img.paste(title, (0, y), title)
|
||||
tasks = []
|
||||
for item_index, item in enumerate(total_data[i]['list']):
|
||||
item_x = (item_index % 6) * 138 + 45
|
||||
item_y = (item_index // 6) * 150 + y + 355
|
||||
xy_point = (item_x, item_y)
|
||||
tasks.append(
|
||||
_draw_card(
|
||||
img,
|
||||
xy_point,
|
||||
item['item_type'],
|
||||
item['name'],
|
||||
item['gacha_num'],
|
||||
item['is_up'],
|
||||
)
|
||||
)
|
||||
await asyncio.gather(*tasks)
|
||||
tasks.clear()
|
||||
|
||||
# 发送图片
|
||||
res = await convert_img(img)
|
||||
logger.info('[查询抽卡]绘图已完成,等待发送!')
|
||||
# res = 123
|
||||
return res
|
||||
|
BIN
StarRailUID/utils/image/bg/nm_bg/Abg1.png
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
StarRailUID/utils/image/bg/nm_bg/Abg2.png
Normal file
After Width: | Height: | Size: 398 KiB |
BIN
StarRailUID/utils/image/bg/nm_bg/Abg3.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
StarRailUID/utils/image/bg/nm_bg/Abg4.png
Normal file
After Width: | Height: | Size: 297 KiB |
BIN
StarRailUID/utils/image/bg/nm_bg/Abg5.png
Normal file
After Width: | Height: | Size: 959 KiB |
BIN
StarRailUID/utils/image/bg/nm_bg/Abg6.png
Normal file
After Width: | Height: | Size: 302 KiB |
264
StarRailUID/utils/image/image_tools.py
Normal file
@ -0,0 +1,264 @@
|
||||
import math
|
||||
import random
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from typing import Tuple, Union, Optional
|
||||
|
||||
from PIL import Image
|
||||
from httpx import get
|
||||
|
||||
from ...starrailuid_config.sr_config import srconfig
|
||||
from ..resource.RESOURCE_PATH import CU_BG_PATH, TEXT2D_PATH
|
||||
|
||||
BG_PATH = Path(__file__).parent / 'bg'
|
||||
TEXT_PATH = Path(__file__).parent / 'texture2d'
|
||||
ring_pic = Image.open(TEXT_PATH / 'ring.png')
|
||||
mask_pic = Image.open(TEXT_PATH / 'mask.png')
|
||||
NM_BG_PATH = BG_PATH / 'nm_bg'
|
||||
SP_BG_PATH = BG_PATH / 'sp_bg'
|
||||
|
||||
|
||||
if list(CU_BG_PATH.iterdir()) != []:
|
||||
bg_path = CU_BG_PATH
|
||||
else:
|
||||
bg_path = NM_BG_PATH
|
||||
|
||||
|
||||
async def get_qq_avatar(
|
||||
qid: Optional[Union[int, str]] = None, avatar_url: Optional[str] = None
|
||||
) -> Image.Image:
|
||||
if qid:
|
||||
avatar_url = f'http://q1.qlogo.cn/g?b=qq&nk={qid}&s=640'
|
||||
elif avatar_url is None:
|
||||
avatar_url = 'https://q1.qlogo.cn/g?b=qq&nk=3399214199&s=640'
|
||||
char_pic = Image.open(BytesIO(get(avatar_url).content)).convert('RGBA')
|
||||
return char_pic
|
||||
|
||||
|
||||
async def get_color_bg(
|
||||
based_w: int,
|
||||
based_h: int,
|
||||
bg: Optional[str] = None,
|
||||
without_mask: bool = False,
|
||||
) -> Image.Image:
|
||||
image = ''
|
||||
if bg and srconfig.get_config('DefaultBaseBG').data:
|
||||
path = SP_BG_PATH / f'{bg}.jpg'
|
||||
path2 = CU_BG_PATH / f'{bg}.jpg'
|
||||
if path2.exists():
|
||||
image = Image.open(path2)
|
||||
elif path.exists():
|
||||
image = Image.open(path)
|
||||
CI_img = CustomizeImage(image, based_w, based_h)
|
||||
img = CI_img.bg_img
|
||||
color = CI_img.bg_color
|
||||
if not without_mask:
|
||||
color_mask = Image.new('RGBA', (based_w, based_h), color)
|
||||
enka_mask = Image.open(TEXT2D_PATH / 'mask.png').resize(
|
||||
(based_w, based_h)
|
||||
)
|
||||
img.paste(color_mask, (0, 0), enka_mask)
|
||||
return img
|
||||
|
||||
|
||||
def crop_center_img(
|
||||
img: Image.Image, based_w: int, based_h: int
|
||||
) -> Image.Image:
|
||||
# 确定图片的长宽
|
||||
based_scale = '%.3f' % (based_w / based_h)
|
||||
w, h = img.size
|
||||
scale_f = '%.3f' % (w / h)
|
||||
new_w = math.ceil(based_h * float(scale_f))
|
||||
new_h = math.ceil(based_w / float(scale_f))
|
||||
if scale_f > based_scale:
|
||||
resize_img = img.resize((new_w, based_h), Image.ANTIALIAS)
|
||||
x1 = int(new_w / 2 - based_w / 2)
|
||||
y1 = 0
|
||||
x2 = int(new_w / 2 + based_w / 2)
|
||||
y2 = based_h
|
||||
else:
|
||||
resize_img = img.resize((based_w, new_h), Image.ANTIALIAS)
|
||||
x1 = 0
|
||||
y1 = int(new_h / 2 - based_h / 2)
|
||||
x2 = based_w
|
||||
y2 = int(new_h / 2 + based_h / 2)
|
||||
crop_img = resize_img.crop((x1, y1, x2, y2))
|
||||
return crop_img
|
||||
|
||||
|
||||
async def draw_pic_with_ring(
|
||||
pic: Image.Image,
|
||||
size: int,
|
||||
bg_color: Optional[Tuple[int, int, int]] = None,
|
||||
):
|
||||
'''
|
||||
:说明:
|
||||
绘制一张带白色圆环的1:1比例图片。
|
||||
|
||||
:参数:
|
||||
* pic: `Image.Image`: 要修改的图片。
|
||||
* size: `int`: 最后传出图片的大小(1:1)。
|
||||
* bg_color: `Optional[Tuple[int, int, int]]`: 是否指定圆环内背景颜色。
|
||||
|
||||
:返回:
|
||||
* img: `Image.Image`: 图片对象
|
||||
'''
|
||||
img = Image.new('RGBA', (size, size))
|
||||
mask = mask_pic.resize((size, size))
|
||||
# ring = ring_pic.resize((size, size))
|
||||
resize_pic = crop_center_img(pic, size, size)
|
||||
if bg_color:
|
||||
img_color = Image.new('RGBA', (size, size), bg_color)
|
||||
img_color.paste(resize_pic, (0, 0), resize_pic)
|
||||
img.paste(img_color, (0, 0), mask)
|
||||
else:
|
||||
img.paste(resize_pic, (0, 0), mask)
|
||||
# img.paste(ring, (0, 0), ring)
|
||||
return img
|
||||
|
||||
|
||||
class CustomizeImage:
|
||||
def __init__(
|
||||
self, image: Union[str, Image.Image], based_w: int, based_h: int
|
||||
) -> None:
|
||||
self.bg_img = self.get_image(image, based_w, based_h)
|
||||
self.bg_color = self.get_bg_color(self.bg_img, is_light=True)
|
||||
self.text_color = self.get_text_color(self.bg_color)
|
||||
self.highlight_color = self.get_highlight_color(self.bg_color)
|
||||
self.char_color = self.get_char_color(self.bg_color)
|
||||
self.bg_detail_color = self.get_bg_detail_color(self.bg_color)
|
||||
self.char_high_color = self.get_char_high_color(self.bg_color)
|
||||
|
||||
@staticmethod
|
||||
def get_image(
|
||||
image: Union[str, Image.Image], based_w: int, based_h: int
|
||||
) -> Image.Image:
|
||||
# 获取背景图片
|
||||
if isinstance(image, Image.Image):
|
||||
edit_bg = image
|
||||
elif image:
|
||||
edit_bg = Image.open(BytesIO(get(image).content)).convert('RGBA')
|
||||
else:
|
||||
path = random.choice(list(bg_path.iterdir()))
|
||||
edit_bg = Image.open(path).convert('RGBA')
|
||||
|
||||
# 确定图片的长宽
|
||||
bg_img = crop_center_img(edit_bg, based_w, based_h)
|
||||
return bg_img
|
||||
|
||||
@staticmethod
|
||||
def get_dominant_color(pil_img: Image.Image) -> Tuple[int, int, int]:
|
||||
img = pil_img.copy()
|
||||
img = img.convert("RGBA")
|
||||
img = img.resize((1, 1), resample=0)
|
||||
dominant_color = img.getpixel((0, 0))
|
||||
return dominant_color
|
||||
|
||||
@staticmethod
|
||||
def get_bg_color(
|
||||
edit_bg: Image.Image, is_light: Optional[bool] = False
|
||||
) -> Tuple[int, int, int]:
|
||||
# 获取背景主色
|
||||
color = 8
|
||||
q = edit_bg.quantize(colors=color, method=2)
|
||||
bg_color = (0, 0, 0)
|
||||
if is_light:
|
||||
based_light = 195
|
||||
else:
|
||||
based_light = 120
|
||||
temp = 9999
|
||||
for i in range(color):
|
||||
bg = tuple(
|
||||
q.getpalette()[ # type:ignore
|
||||
i * 3 : (i * 3) + 3 # noqa:E203
|
||||
]
|
||||
)
|
||||
light_value = bg[0] * 0.3 + bg[1] * 0.6 + bg[2] * 0.1
|
||||
if abs(light_value - based_light) < temp: # noqa:E203
|
||||
bg_color = bg
|
||||
temp = abs(light_value - based_light)
|
||||
return bg_color
|
||||
|
||||
@staticmethod
|
||||
def get_text_color(bg_color: Tuple[int, int, int]) -> Tuple[int, int, int]:
|
||||
# 通过背景主色(bg_color)确定文字主色
|
||||
r = 125
|
||||
if max(*bg_color) > 255 - r:
|
||||
r *= -1
|
||||
text_color = (
|
||||
math.floor(bg_color[0] + r if bg_color[0] + r <= 255 else 255),
|
||||
math.floor(bg_color[1] + r if bg_color[1] + r <= 255 else 255),
|
||||
math.floor(bg_color[2] + r if bg_color[2] + r <= 255 else 255),
|
||||
)
|
||||
return text_color
|
||||
|
||||
@staticmethod
|
||||
def get_char_color(bg_color: Tuple[int, int, int]) -> Tuple[int, int, int]:
|
||||
r = 140
|
||||
if max(*bg_color) > 255 - r:
|
||||
r *= -1
|
||||
char_color = (
|
||||
math.floor(bg_color[0] + 5 if bg_color[0] + r <= 255 else 255),
|
||||
math.floor(bg_color[1] + 5 if bg_color[1] + r <= 255 else 255),
|
||||
math.floor(bg_color[2] + 5 if bg_color[2] + r <= 255 else 255),
|
||||
)
|
||||
return char_color
|
||||
|
||||
@staticmethod
|
||||
def get_char_high_color(
|
||||
bg_color: Tuple[int, int, int]
|
||||
) -> Tuple[int, int, int]:
|
||||
r = 140
|
||||
d = 20
|
||||
if max(*bg_color) > 255 - r:
|
||||
r *= -1
|
||||
char_color = (
|
||||
math.floor(bg_color[0] + d if bg_color[0] + r <= 255 else 255),
|
||||
math.floor(bg_color[1] + d if bg_color[1] + r <= 255 else 255),
|
||||
math.floor(bg_color[2] + d if bg_color[2] + r <= 255 else 255),
|
||||
)
|
||||
return char_color
|
||||
|
||||
@staticmethod
|
||||
def get_bg_detail_color(
|
||||
bg_color: Tuple[int, int, int]
|
||||
) -> Tuple[int, int, int]:
|
||||
r = 140
|
||||
if max(*bg_color) > 255 - r:
|
||||
r *= -1
|
||||
bg_detail_color = (
|
||||
math.floor(bg_color[0] - 20 if bg_color[0] + r <= 255 else 255),
|
||||
math.floor(bg_color[1] - 20 if bg_color[1] + r <= 255 else 255),
|
||||
math.floor(bg_color[2] - 20 if bg_color[2] + r <= 255 else 255),
|
||||
)
|
||||
return bg_detail_color
|
||||
|
||||
@staticmethod
|
||||
def get_highlight_color(
|
||||
color: Tuple[int, int, int]
|
||||
) -> Tuple[int, int, int]:
|
||||
red_color = color[0]
|
||||
green_color = color[1]
|
||||
blue_color = color[2]
|
||||
|
||||
highlight_color = {
|
||||
'red': red_color - 127 if red_color > 127 else 127,
|
||||
'green': green_color - 127 if green_color > 127 else 127,
|
||||
'blue': blue_color - 127 if blue_color > 127 else 127,
|
||||
}
|
||||
|
||||
max_color = max(highlight_color.values())
|
||||
|
||||
name = ''
|
||||
for _highlight_color in highlight_color:
|
||||
if highlight_color[_highlight_color] == max_color:
|
||||
name = str(_highlight_color)
|
||||
|
||||
if name == 'red':
|
||||
return red_color, highlight_color['green'], highlight_color['blue']
|
||||
elif name == 'green':
|
||||
return highlight_color['red'], green_color, highlight_color['blue']
|
||||
elif name == 'blue':
|
||||
return highlight_color['red'], highlight_color['green'], blue_color
|
||||
else:
|
||||
return 0, 0, 0 # Error
|
@ -1,70 +0,0 @@
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, TypedDict
|
||||
|
||||
from msgspec import json as msgjson
|
||||
|
||||
from ...version import StarRail_version
|
||||
|
||||
MAP = Path(__file__).parent / 'data'
|
||||
|
||||
version = StarRail_version
|
||||
|
||||
avatarName2Element_fileName = f'avatarName2Element_mapping_{version}.json'
|
||||
weaponHash2Name_fileName = f'weaponHash2Name_mapping_{version}.json'
|
||||
weaponHash2Type_fileName = f'weaponHash2Type_mapping_{version}.json'
|
||||
skillId2Name_fileName = f'skillId2Name_mapping_{version}.json'
|
||||
talentId2Name_fileName = f'talentId2Name_mapping_{version}.json'
|
||||
avatarId2Name_fileName = f'avatarId2Name_mapping_{version}.json'
|
||||
avatarId2Star_fileName = f'avatarId2Star_mapping_{version}.json'
|
||||
artifact2attr_fileName = f'artifact2attr_mapping_{version}.json'
|
||||
enName2Id_fileName = f'enName2AvatarID_mapping_{version}.json'
|
||||
icon2Name_fileName = f'icon2Name_mapping_{version}.json'
|
||||
avatarName2Weapon_fileName = f'avatarName2Weapon_mapping_{version}.json'
|
||||
|
||||
|
||||
class TS(TypedDict):
|
||||
Name: Dict[str, str]
|
||||
Icon: Dict[str, str]
|
||||
|
||||
|
||||
with open(MAP / avatarId2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
avatarId2Name = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / icon2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
icon2Name = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / artifact2attr_fileName, 'r', encoding='UTF-8') as f:
|
||||
artifact2attr = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / 'propId2Name_mapping.json', 'r', encoding='UTF-8') as f:
|
||||
propId2Name = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / weaponHash2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
weaponHash2Name = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / weaponHash2Type_fileName, 'r', encoding='UTF-8') as f:
|
||||
weaponHash2Type = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / 'artifactId2Piece_mapping.json', 'r', encoding='UTF-8') as f:
|
||||
artifactId2Piece = msgjson.decode(f.read(), type=Dict[str, List[str]])
|
||||
|
||||
with open(MAP / skillId2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
skillId2Name = msgjson.decode(f.read(), type=TS)
|
||||
|
||||
with open(MAP / talentId2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
talentId2Name = msgjson.decode(f.read(), type=TS)
|
||||
|
||||
with open(MAP / avatarName2Element_fileName, 'r', encoding='UTF-8') as f:
|
||||
avatarName2Element = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / avatarName2Weapon_fileName, 'r', encoding='UTF-8') as f:
|
||||
avatarName2Weapon = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / 'char_alias.json', 'r', encoding='UTF-8') as f:
|
||||
alias_data = msgjson.decode(f.read(), type=Dict[str, List[str]])
|
||||
|
||||
with open(MAP / avatarId2Star_fileName, 'r', encoding='utf8') as f:
|
||||
avatarId2Star_data = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / enName2Id_fileName, 'r', encoding='utf8') as f:
|
||||
enName_to_avatarId_data = msgjson.decode(f.read(), type=Dict[str, str])
|
25
StarRailUID/utils/map/SR_MAP_PATH.py
Normal file
@ -0,0 +1,25 @@
|
||||
from pathlib import Path
|
||||
from typing import Dict, TypedDict
|
||||
|
||||
from msgspec import json as msgjson
|
||||
|
||||
from ...version import StarRail_version
|
||||
|
||||
MAP = Path(__file__).parent / 'data'
|
||||
|
||||
version = StarRail_version
|
||||
|
||||
avatarId2Name_fileName = f'avatarId2Name_mapping_{version}.json'
|
||||
EquipmentID2Name_fileName = f'EquipmentID2Name_mapping_{version}.json'
|
||||
|
||||
|
||||
class TS(TypedDict):
|
||||
Name: Dict[str, str]
|
||||
Icon: Dict[str, str]
|
||||
|
||||
|
||||
with open(MAP / avatarId2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
avatarId2Name = msgjson.decode(f.read(), type=Dict[str, str])
|
||||
|
||||
with open(MAP / EquipmentID2Name_fileName, 'r', encoding='UTF-8') as f:
|
||||
EquipmentID2Name = msgjson.decode(f.read(), type=Dict[str, str])
|
@ -0,0 +1 @@
|
||||
{"20000": "锋镝", "20001": "物穰", "20002": "天倾", "20003": "琥珀", "20004": "幽邃", "20005": "齐颂", "20006": "智库", "20007": "离弦", "20008": "嘉果", "20009": "乐圮", "20010": "戍御", "20011": "渊环", "20012": "轮契", "20013": "灵钥", "20014": "相抗", "20015": "蕃息", "20016": "俱殁", "20017": "开疆", "20018": "匿影", "20019": "调和", "20020": "睿见", "21000": "一场术后对话", "21001": "晚安与睡颜", "21002": "余生的第一天", "21003": "唯有沉默", "21004": "记忆中的模样", "21005": "鼹鼠党欢迎你", "21006": "「我」的诞生", "21007": "同一种心情", "21008": "猎物的视线", "21009": "朗道的选择", "21010": "论剑", "21011": "与行星相会", "21012": "秘密誓心", "21014": "此时恰好", "21015": "决心如汗珠般闪耀", "21016": "宇宙市场趋势", "21017": "点个关注吧!", "21021": "等价交换", "21028": "暖夜不会漫长", "23001": "于夜色中", "23003": "但战斗还未结束", "23004": "以世界之名", "23005": "制胜的瞬间", "23012": "如泥酣眠", "23013": "时节不居", "24000": "记一位星神的陨落", "24001": "星海巡航", "24002": "记忆的质料", "29000": "dev_测试白板", "21013": "别让世界静下来", "23000": "银河铁道之夜", "23010": "拂晓之前", "21019": "在蓝天下", "21020": "天才们的休憩", "21023": "我们是地火", "21024": "春水初生", "21022": "延长记号", "21026": "汪!散步时间!", "21027": "早餐的仪式感", "21029": "后会有期", "21030": "这就是我啦!", "21031": "重返幽冥", "21032": "镂月裁云之意", "21033": "无处可逃", "21034": "今日亦是和平的一日", "23002": "无可取代的东西", "21018": "舞!舞!舞!", "21025": "过往未来"}
|
@ -1,9 +1,4 @@
|
||||
from .GS_MAP_PATH import (
|
||||
alias_data,
|
||||
avatarId2Name,
|
||||
avatarId2Star_data,
|
||||
enName_to_avatarId_data,
|
||||
)
|
||||
from .SR_MAP_PATH import EquipmentID2Name, avatarId2Name
|
||||
|
||||
|
||||
async def avatar_id_to_name(avatar_id: str) -> str:
|
||||
@ -20,26 +15,15 @@ async def name_to_avatar_id(name: str) -> str:
|
||||
return avatar_id
|
||||
|
||||
|
||||
async def avatar_id_to_char_star(char_id: str) -> str:
|
||||
char_star = avatarId2Star_data[str(char_id)]
|
||||
return char_star
|
||||
async def weapon_id_to_name(weapon_id: str) -> str:
|
||||
weapon_name = EquipmentID2Name[weapon_id]
|
||||
return weapon_name
|
||||
|
||||
|
||||
async def alias_to_char_name(char_name: str) -> str:
|
||||
for i in alias_data:
|
||||
if (char_name in i) or (char_name in alias_data[i]):
|
||||
return i
|
||||
return char_name
|
||||
|
||||
|
||||
async def enName_to_avatarId(en_name: str) -> str:
|
||||
avatar_id = enName_to_avatarId_data[en_name]
|
||||
return avatar_id
|
||||
|
||||
|
||||
async def avatarId_to_enName(avatarId: str) -> str:
|
||||
for name in enName_to_avatarId_data:
|
||||
if enName_to_avatarId_data[name] == avatarId:
|
||||
return name
|
||||
else:
|
||||
return 'Ayaka'
|
||||
async def name_to_weapon_id(name: str) -> str:
|
||||
weapon_id = ''
|
||||
for i in EquipmentID2Name:
|
||||
if EquipmentID2Name[i] == name:
|
||||
weapon_id = i
|
||||
break
|
||||
return weapon_id
|
||||
|
@ -1,4 +1,5 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from gsuid_core.data_store import get_res_path
|
||||
|
||||
@ -7,12 +8,22 @@ sys.path.append(str(MAIN_PATH))
|
||||
CONFIG_PATH = MAIN_PATH / 'config.json'
|
||||
RESOURCE_PATH = MAIN_PATH / 'resource'
|
||||
PLAYER_PATH = MAIN_PATH / 'players'
|
||||
CHAR_PATH = RESOURCE_PATH / 'chars'
|
||||
CU_BG_PATH = MAIN_PATH / 'bg'
|
||||
CHAR_ICON_PATH = RESOURCE_PATH / 'char_icon'
|
||||
WEAPON_PATH = RESOURCE_PATH / 'weapons'
|
||||
TEXT2D_PATH = Path(__file__).parent / 'texture2d'
|
||||
|
||||
|
||||
def init_dir():
|
||||
for i in [MAIN_PATH, RESOURCE_PATH, PLAYER_PATH, CHAR_PATH, WEAPON_PATH]:
|
||||
for i in [
|
||||
MAIN_PATH,
|
||||
RESOURCE_PATH,
|
||||
PLAYER_PATH,
|
||||
CHAR_ICON_PATH,
|
||||
WEAPON_PATH,
|
||||
TEXT2D_PATH,
|
||||
CU_BG_PATH,
|
||||
]:
|
||||
i.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
|
BIN
StarRailUID/utils/resource/texture2d/mask.png
Normal file
After Width: | Height: | Size: 53 KiB |