🚧完成sr抽卡记录
@ -5,8 +5,7 @@ from gsuid_core.models import Event
|
|||||||
from ..utils.convert import get_uid
|
from ..utils.convert import get_uid
|
||||||
from ..utils.error_reply import UID_HINT
|
from ..utils.error_reply import UID_HINT
|
||||||
from .get_gachalogs import save_gachalogs
|
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_gacha_log = SV('sr抽卡记录')
|
||||||
sv_get_gachalog_by_link = SV('sr导入抽卡链接', area='DIRECT')
|
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)
|
uid, user_id = await get_uid(bot, ev, True)
|
||||||
if uid is None:
|
if uid is None:
|
||||||
return await bot.send(UID_HINT)
|
return await bot.send(UID_HINT)
|
||||||
# im = await draw_gachalogs_img(uid, user_id)
|
im = await draw_gachalogs_img(uid, user_id)
|
||||||
im = '画个饼先,在做了在做了'
|
|
||||||
await bot.send(im)
|
await bot.send(im)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,426 +1,438 @@
|
|||||||
# import json
|
import json
|
||||||
# import random
|
import asyncio
|
||||||
# import asyncio
|
import datetime
|
||||||
# import datetime
|
from pathlib import Path
|
||||||
# from pathlib import Path
|
from typing import List, Tuple, Union
|
||||||
# from typing import List, Tuple, Union
|
|
||||||
#
|
from PIL import Image, ImageDraw
|
||||||
# from PIL import Image, ImageDraw
|
from gsuid_core.logger import logger
|
||||||
# from gsuid_core.logger import logger
|
|
||||||
#
|
from ..utils.image.convert import convert_img
|
||||||
# from ..utils.image.convert import convert_img
|
from ..utils.map.name_covert import name_to_avatar_id
|
||||||
# from ..utils.map.name_covert import name_to_avatar_id
|
from ..utils.resource.RESOURCE_PATH import (
|
||||||
# from ..utils.resource.RESOURCE_PATH import
|
PLAYER_PATH,
|
||||||
# CHAR_PATH, PLAYER_PATH, WEAPON_PATH
|
WEAPON_PATH,
|
||||||
# from ..utils.image.image_tools import (
|
CHAR_ICON_PATH,
|
||||||
# get_color_bg,
|
)
|
||||||
# get_qq_avatar,
|
from ..utils.image.image_tools import (
|
||||||
# draw_pic_with_ring,
|
get_color_bg,
|
||||||
# )
|
get_qq_avatar,
|
||||||
# from ..utils.fonts.starrail_fonts import (
|
draw_pic_with_ring,
|
||||||
# sr_font_24,
|
)
|
||||||
# sr_font_28,
|
from ..utils.fonts.starrail_fonts import (
|
||||||
# sr_font_36,
|
sr_font_20,
|
||||||
# sr_font_40,
|
sr_font_24,
|
||||||
# sr_font_62,
|
sr_font_28,
|
||||||
# )
|
sr_font_38,
|
||||||
#
|
sr_font_40,
|
||||||
# TEXT_PATH = Path(__file__).parent / 'texture2d'
|
)
|
||||||
#
|
|
||||||
|
TEXT_PATH = Path(__file__).parent / 'texture2d'
|
||||||
|
EMO_PATH = Path(__file__).parent / 'texture2d' / 'emo'
|
||||||
|
|
||||||
# up_tag = Image.open(TEXT_PATH / 'up.png')
|
# up_tag = Image.open(TEXT_PATH / 'up.png')
|
||||||
#
|
Abg3_img = Image.open(TEXT_PATH / 'Abg3.png')
|
||||||
# first_color = (29, 29, 29)
|
bg1_img = Image.open(TEXT_PATH / 'bg1.png')
|
||||||
# brown_color = (41, 25, 0)
|
|
||||||
# red_color = (255, 66, 66)
|
first_color = (29, 29, 29)
|
||||||
# green_color = (74, 189, 119)
|
brown_color = (41, 25, 0)
|
||||||
#
|
red_color = (255, 66, 66)
|
||||||
# CHANGE_MAP = {'常驻祈愿': 'normal', '角色祈愿': 'char', '武器祈愿': 'weapon'}
|
green_color = (74, 189, 119)
|
||||||
# HOMO_TAG = ['非到极致', '运气不好', '平稳保底', '小欧一把', '欧狗在此']
|
white_color = (213, 213, 213)
|
||||||
# NORMAL_LIST = [
|
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,
|
UP_LIST = {
|
||||||
# xy_point: Tuple[int, int],
|
'刻晴': [(2021, 2, 17, 18, 0, 0), (2021, 3, 2, 15, 59, 59)],
|
||||||
# name: str,
|
'提纳里': [(2022, 8, 24, 11, 0, 0), (2022, 9, 9, 17, 59, 59)],
|
||||||
# gacha_num: int,
|
'迪希雅': [(2023, 3, 1, 11, 0, 0), (2023, 3, 21, 17, 59, 59)],
|
||||||
# is_up: bool,
|
}
|
||||||
# ):
|
|
||||||
# card_img = Image.open(TEXT_PATH / 'item_bg.png')
|
|
||||||
# card_img_draw = ImageDraw.Draw(card_img)
|
async def _draw_card(
|
||||||
# point = (1, 0)
|
img: Image.Image,
|
||||||
# text_point = (55, 124)
|
xy_point: Tuple[int, int],
|
||||||
# if type == '角色':
|
type: str,
|
||||||
# _id = await name_to_avatar_id(name)
|
name: str,
|
||||||
# item_pic = (
|
gacha_num: int,
|
||||||
# Image.open(CHAR_PATH / f'{_id}.png')
|
is_up: bool,
|
||||||
# .convert('RGBA')
|
):
|
||||||
# .resize((108, 108))
|
card_img = Image.open(TEXT_PATH / 'char_bg.png')
|
||||||
# )
|
card_img_draw = ImageDraw.Draw(card_img)
|
||||||
# else:
|
point = (47, 31)
|
||||||
# item_pic = (
|
text_point = (100, 165)
|
||||||
# Image.open(WEAPON_PATH / f'{name}.png')
|
if type == '角色':
|
||||||
# .convert('RGBA')
|
_id = await name_to_avatar_id(name)
|
||||||
# .resize((108, 108))
|
item_pic = (
|
||||||
# )
|
Image.open(CHAR_ICON_PATH / f'{_id}.png')
|
||||||
# card_img.paste(item_pic, point, item_pic)
|
.convert('RGBA')
|
||||||
# if gacha_num >= 81:
|
.crop((0, 0, 112, 112))
|
||||||
# text_color = red_color
|
.resize((105, 105))
|
||||||
# elif gacha_num <= 55:
|
)
|
||||||
# text_color = green_color
|
else:
|
||||||
# else:
|
item_pic = (
|
||||||
# text_color = brown_color
|
Image.open(WEAPON_PATH / f'{name}.png')
|
||||||
# card_img_draw.text(
|
.convert('RGBA')
|
||||||
# text_point, f'{gacha_num}抽', text_color, gs_font_24, 'mm'
|
.crop((0, 0, 867, 867))
|
||||||
# )
|
)
|
||||||
# if is_up:
|
item_pic = item_pic.resize((105, 105))
|
||||||
# card_img.paste(up_tag, (47, -2), up_tag)
|
card_img.paste(item_pic, point, item_pic)
|
||||||
# img.paste(card_img, xy_point, card_img)
|
if gacha_num >= 81:
|
||||||
#
|
text_color = red_color
|
||||||
#
|
elif gacha_num <= 55:
|
||||||
# async def random_emo_pic(level: int) -> Image.Image:
|
text_color = green_color
|
||||||
# emo_fold = TEXT_PATH / str(level)
|
else:
|
||||||
# return Image.open(random.choice(list(emo_fold.iterdir())))
|
text_color = brown_color
|
||||||
#
|
card_img_draw.text(
|
||||||
#
|
text_point, f'{gacha_num}抽', text_color, sr_font_24, 'mm'
|
||||||
# async def get_level_from_list(ast: int, lst: List) -> int:
|
)
|
||||||
# if ast == 0:
|
if is_up:
|
||||||
# return 3
|
print(f'up: {name}')
|
||||||
#
|
# card_img.paste(up_tag, (47, -2), up_tag)
|
||||||
# for num_index, num in enumerate(lst):
|
img.paste(card_img, xy_point, card_img)
|
||||||
# if ast <= num:
|
|
||||||
# level = 5 - num_index
|
|
||||||
# break
|
async def random_emo_pic(level: int) -> Image.Image:
|
||||||
# else:
|
emo_fold = EMO_PATH / f'3000{level}.png'
|
||||||
# level = 1
|
return Image.open(emo_fold)
|
||||||
# return level
|
|
||||||
#
|
|
||||||
#
|
async def get_level_from_list(ast: int, lst: List) -> int:
|
||||||
# def check_up(name: str, _time: str) -> bool:
|
if ast == 0:
|
||||||
# for char in UP_LIST:
|
return 3
|
||||||
# if char == name:
|
|
||||||
# time = UP_LIST[char]
|
for num_index, num in enumerate(lst):
|
||||||
# s_time = datetime.datetime(*time[0])
|
if ast <= num:
|
||||||
# e_time = datetime.datetime(*time[1])
|
level = 5 - num_index
|
||||||
# gacha_time = datetime.datetime.strptime
|
break
|
||||||
# (_time, '%Y-%m-%d %H:%M:%S')
|
else:
|
||||||
# if gacha_time < s_time or gacha_time > e_time:
|
level = 1
|
||||||
# return False
|
return level
|
||||||
# else:
|
|
||||||
# return True
|
|
||||||
# else:
|
def check_up(name: str, _time: str) -> bool:
|
||||||
# return False
|
for char in UP_LIST:
|
||||||
#
|
if char == name:
|
||||||
#
|
time = UP_LIST[char]
|
||||||
# async def draw_gachalogs_img(uid: str, user_id: str) -> Union[bytes, str]:
|
s_time = datetime.datetime(*time[0])
|
||||||
# path = PLAYER_PATH / str(uid) / 'gacha_logs.json'
|
e_time = datetime.datetime(*time[1])
|
||||||
# if not path.exists():
|
gacha_time = datetime.datetime.strptime(_time, '%Y-%m-%d %H:%M:%S')
|
||||||
# return '你还没有祈愿数据噢~\n请添加Stoken后使用命令`刷新抽卡记录`更新祈愿数据~'
|
if gacha_time < s_time or gacha_time > e_time:
|
||||||
# with open(path, 'r', encoding='UTF-8') as f:
|
return False
|
||||||
# gacha_data = json.load(f)
|
else:
|
||||||
#
|
return True
|
||||||
# # 数据初始化
|
else:
|
||||||
# total_data = {}
|
return False
|
||||||
# for i in ['群星跃迁', '角色跃迁', '光锥跃迁']:
|
|
||||||
# total_data[i] = {
|
|
||||||
# 'total': 0, # 五星总数
|
async def draw_gachalogs_img(uid: str, user_id: str) -> Union[bytes, str]:
|
||||||
# 'avg': 0, # 抽卡平均数
|
path = PLAYER_PATH / str(uid) / 'gacha_logs_test.json'
|
||||||
# 'avg_up': 0, # up平均数
|
if not path.exists():
|
||||||
# 'remain': 0, # 已xx抽未出金
|
return '你还没有跃迁数据噢~\n请使用命令`sr导入抽卡链接`更新跃迁数据~'
|
||||||
# 'r_num': [], # 不包含首位的抽卡数量
|
with open(path, 'r', encoding='UTF-8') as f:
|
||||||
# 'e_num': [], # 包含首位的up抽卡数量
|
gacha_data = json.load(f)
|
||||||
# 'up_list': [], # 抽到的UP列表(不包含首位)
|
|
||||||
# 'normal_list': [], # 抽到的五星列表(不包含首位)
|
# 数据初始化
|
||||||
# 'list': [], # 抽到的五星列表
|
total_data = {}
|
||||||
# 'time_range': '', # 抽卡时间
|
for i in ['群星跃迁', '始发跃迁', '角色跃迁', '光锥跃迁']:
|
||||||
# 'all_time': 0, # 抽卡总计秒数
|
total_data[i] = {
|
||||||
# 'type': '一般型', # 抽卡类型: 随缘型, 氪金型, 规划型, 仓鼠型, 佛系型
|
'total': 0, # 五星总数
|
||||||
# 'short_gacha_data': {'time': 0, 'num': 0},
|
'avg': 0, # 抽卡平均数
|
||||||
# 'long_gacha_data': {'time': 0, 'num': 0},
|
'avg_up': 0, # up平均数
|
||||||
# }
|
'remain': 0, # 已xx抽未出金
|
||||||
# # 拿到数据列表
|
'r_num': [], # 不包含首位的抽卡数量
|
||||||
# data_list = gacha_data['list'][i]
|
'e_num': [], # 包含首位的up抽卡数量
|
||||||
# # 初始化开关
|
'up_list': [], # 抽到的UP列表(不包含首位)
|
||||||
# is_not_first = False
|
'normal_list': [], # 抽到的五星列表(不包含首位)
|
||||||
# # 开始初始化抽卡数
|
'list': [], # 抽到的五星列表
|
||||||
# num = 1
|
'time_range': '', # 抽卡时间
|
||||||
# # 从后面开始循环
|
'all_time': 0, # 抽卡总计秒数
|
||||||
# temp_time = datetime.datetime(2023, 4, 26, 8, 0, 0)
|
'type': '一般型', # 抽卡类型: 随缘型, 氪金型, 规划型, 仓鼠型, 佛系型
|
||||||
# for index, data in enumerate(data_list[::-1]):
|
'short_gacha_data': {'time': 0, 'num': 0},
|
||||||
# # 计算抽卡时间跨度
|
'long_gacha_data': {'time': 0, 'num': 0},
|
||||||
# if index == 0:
|
}
|
||||||
# total_data[i]['time_range'] = data['time']
|
# 拿到数据列表
|
||||||
# if index == len(data_list) - 1:
|
data_list = gacha_data['data'][i]
|
||||||
# total_data[i]['all_time'] = (
|
print(data_list)
|
||||||
# datetime.datetime.strptime(
|
# 初始化开关
|
||||||
# data['time'], '%Y-%m-%d %H:%M:%S'
|
is_not_first = True
|
||||||
# )
|
# 开始初始化抽卡数
|
||||||
# - datetime.datetime.strptime(
|
num = 1
|
||||||
# total_data[i]['time_range'], '%Y-%m-%d %H:%M:%S'
|
# 从后面开始循环
|
||||||
# )
|
temp_time = datetime.datetime(2023, 4, 26, 8, 0, 0)
|
||||||
# ).total_seconds()
|
for index, data in enumerate(data_list[::-1]):
|
||||||
# total_data[i]['time_range'] += '~' + data['time']
|
# 计算抽卡时间跨度
|
||||||
#
|
if index == 0:
|
||||||
# # 计算时间间隔
|
total_data[i]['time_range'] = data['time']
|
||||||
# if index != 0:
|
if index == len(data_list) - 1:
|
||||||
# now_time = datetime.datetime.strptime(
|
total_data[i]['all_time'] = (
|
||||||
# data['time'], '%Y-%m-%d %H:%M:%S'
|
datetime.datetime.strptime(
|
||||||
# )
|
data['time'], '%Y-%m-%d %H:%M:%S'
|
||||||
# dis = (now_time - temp_time).total_seconds()
|
)
|
||||||
# temp_time = now_time
|
- datetime.datetime.strptime(
|
||||||
# if dis <= 5000:
|
total_data[i]['time_range'], '%Y-%m-%d %H:%M:%S'
|
||||||
# total_data[i]['short_gacha_data']['num'] += 1
|
)
|
||||||
# total_data[i]['short_gacha_data']['time'] += dis
|
).total_seconds()
|
||||||
# elif dis >= 86400:
|
total_data[i]['time_range'] += '~' + data['time']
|
||||||
# total_data[i]['long_gacha_data']['num'] += 1
|
|
||||||
# total_data[i]['long_gacha_data']['time'] += dis
|
# 计算时间间隔
|
||||||
# else:
|
if index != 0:
|
||||||
# temp_time = datetime.datetime.strptime(
|
now_time = datetime.datetime.strptime(
|
||||||
# data['time'], '%Y-%m-%d %H:%M:%S'
|
data['time'], '%Y-%m-%d %H:%M:%S'
|
||||||
# )
|
)
|
||||||
#
|
dis = (now_time - temp_time).total_seconds()
|
||||||
# # 如果这是个五星
|
temp_time = now_time
|
||||||
# if data['rank_type'] == '5':
|
if dis <= 5000:
|
||||||
# # 抽到这个五星花了多少抽
|
total_data[i]['short_gacha_data']['num'] += 1
|
||||||
# data['gacha_num'] = num
|
total_data[i]['short_gacha_data']['time'] += dis
|
||||||
#
|
elif dis >= 86400:
|
||||||
# # 判断是否是UP
|
total_data[i]['long_gacha_data']['num'] += 1
|
||||||
# if data['name'] in NORMAL_LIST:
|
total_data[i]['long_gacha_data']['time'] += dis
|
||||||
# data['is_up'] = False
|
else:
|
||||||
# elif data['name'] in UP_LIST:
|
temp_time = datetime.datetime.strptime(
|
||||||
# data['is_up'] = check_up(data['name'], data['time'])
|
data['time'], '%Y-%m-%d %H:%M:%S'
|
||||||
# else:
|
)
|
||||||
# data['is_up'] = True
|
|
||||||
#
|
# 如果这是个五星
|
||||||
# # 往里加东西
|
if data['rank_type'] == '5':
|
||||||
# if is_not_first:
|
# 抽到这个五星花了多少抽
|
||||||
# total_data[i]['r_num'].append(num)
|
data['gacha_num'] = num
|
||||||
# total_data[i]['normal_list'].append(data)
|
|
||||||
# if data['is_up']:
|
# 判断是否是UP
|
||||||
# total_data[i]['up_list'].append(data)
|
if data['name'] in NORMAL_LIST:
|
||||||
#
|
data['is_up'] = False
|
||||||
# # 把这个数据扔到抽到的五星列表内
|
elif data['name'] in UP_LIST:
|
||||||
# total_data[i]['list'].append(data)
|
data['is_up'] = check_up(data['name'], data['time'])
|
||||||
#
|
else:
|
||||||
# # 判断经过了第一个
|
data['is_up'] = True
|
||||||
# if total_data[i]['list']:
|
|
||||||
# is_not_first = True
|
# 往里加东西
|
||||||
#
|
if is_not_first:
|
||||||
# num = 1
|
total_data[i]['r_num'].append(num)
|
||||||
# # 五星总数增加1
|
total_data[i]['normal_list'].append(data)
|
||||||
# total_data[i]['total'] += 1
|
if data['is_up']:
|
||||||
# else:
|
total_data[i]['up_list'].append(data)
|
||||||
# num += 1
|
|
||||||
#
|
# 把这个数据扔到抽到的五星列表内
|
||||||
# # 计算已多少抽
|
total_data[i]['list'].append(data)
|
||||||
# total_data[i]['remain'] = num - 1
|
|
||||||
#
|
# 判断经过了第一个
|
||||||
# # 计算平均抽卡数
|
if total_data[i]['list']:
|
||||||
# if len(total_data[i]['normal_list']) == 0:
|
is_not_first = True
|
||||||
# total_data[i]['avg'] = 0
|
|
||||||
# else:
|
num = 1
|
||||||
# total_data[i]['avg'] = float(
|
# 五星总数增加1
|
||||||
# '{:.2f}'.format(
|
total_data[i]['total'] += 1
|
||||||
# sum(total_data[i]['r_num']) / len(total_data[i]['r_num'])
|
else:
|
||||||
# )
|
num += 1
|
||||||
# )
|
|
||||||
# # 计算平均up数量
|
# 计算已多少抽
|
||||||
# if len(total_data[i]['up_list']) == 0:
|
total_data[i]['remain'] = num - 1
|
||||||
# total_data[i]['avg_up'] = 0
|
|
||||||
# else:
|
# 计算平均抽卡数
|
||||||
# total_data[i]['avg_up'] = float(
|
if len(total_data[i]['normal_list']) == 0:
|
||||||
# '{:.2f}'.format(
|
total_data[i]['avg'] = 0
|
||||||
# sum(total_data[i]['r_num'])
|
else:
|
||||||
# / len(total_data[i]['up_list'])
|
total_data[i]['avg'] = float(
|
||||||
# )
|
'{:.2f}'.format(
|
||||||
# )
|
sum(total_data[i]['r_num']) / len(total_data[i]['r_num'])
|
||||||
#
|
)
|
||||||
# # 计算抽卡类型
|
)
|
||||||
# # 如果抽卡总数小于40
|
# 计算平均up数量
|
||||||
# if gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] <= 40:
|
if len(total_data[i]['up_list']) == 0:
|
||||||
# total_data[i]['type'] = '佛系型'
|
total_data[i]['avg_up'] = 0
|
||||||
# # 如果长时抽卡总数占据了总抽卡数的70%
|
else:
|
||||||
# elif (
|
total_data[i]['avg_up'] = float(
|
||||||
# total_data[i]['long_gacha_data']['num']
|
'{:.2f}'.format(
|
||||||
# / gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
sum(total_data[i]['r_num']) / len(total_data[i]['up_list'])
|
||||||
# >= 0.7
|
)
|
||||||
# ):
|
)
|
||||||
# total_data[i]['type'] = '随缘型'
|
|
||||||
# # 如果短时抽卡总数占据了总抽卡数的70%
|
# 计算抽卡类型
|
||||||
# elif (
|
# 如果抽卡总数小于40
|
||||||
# total_data[i]['short_gacha_data']['num']
|
if gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] <= 40:
|
||||||
# / gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
total_data[i]['type'] = '佛系型'
|
||||||
# >= 0.7
|
# 如果长时抽卡总数占据了总抽卡数的70%
|
||||||
# ):
|
elif (
|
||||||
# total_data[i]['type'] = '规划型'
|
total_data[i]['long_gacha_data']['num']
|
||||||
# # 如果抽卡数量远远大于标称抽卡数量
|
/ gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||||
# elif (
|
>= 0.7
|
||||||
# total_data[i]['all_time'] / 30000
|
):
|
||||||
# <= gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
total_data[i]['type'] = '随缘型'
|
||||||
# ):
|
# 如果短时抽卡总数占据了总抽卡数的70%
|
||||||
# # 如果长时抽卡数量大于短时抽卡数量
|
elif (
|
||||||
# if (
|
total_data[i]['short_gacha_data']['num']
|
||||||
# total_data[i]['long_gacha_data']['num']
|
/ gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||||
# >= total_data[i]['short_gacha_data']['num']
|
>= 0.7
|
||||||
# ):
|
):
|
||||||
# total_data[i]['type'] = '规划型'
|
total_data[i]['type'] = '规划型'
|
||||||
# else:
|
# 如果抽卡数量远远大于标称抽卡数量
|
||||||
# total_data[i]['type'] = '氪金型'
|
elif (
|
||||||
# # 如果抽卡数量远远小于标称抽卡数量
|
total_data[i]['all_time'] / 30000
|
||||||
# elif (
|
<= gacha_data[f'{CHANGE_MAP[i]}_gacha_num']
|
||||||
# total_data[i]['all_time'] / 32000
|
):
|
||||||
# >= gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] * 2
|
# 如果长时抽卡数量大于短时抽卡数量
|
||||||
# ):
|
if (
|
||||||
# total_data[i]['type'] = '仓鼠型'
|
total_data[i]['long_gacha_data']['num']
|
||||||
#
|
>= total_data[i]['short_gacha_data']['num']
|
||||||
# # 常量偏移数据
|
):
|
||||||
# single_y = 150
|
total_data[i]['type'] = '规划型'
|
||||||
#
|
else:
|
||||||
# # 计算图片尺寸
|
total_data[i]['type'] = '氪金型'
|
||||||
# normal_y = (1 + ((total_data['常驻祈愿']['total'] - 1) // 6)) * single_y
|
# 如果抽卡数量远远小于标称抽卡数量
|
||||||
# char_y = (1 + ((total_data['角色祈愿']['total'] - 1) // 6)) * single_y
|
elif (
|
||||||
# weapon_y = (1 + ((total_data['武器祈愿']['total'] - 1) // 6)) * single_y
|
total_data[i]['all_time'] / 32000
|
||||||
#
|
>= gacha_data[f'{CHANGE_MAP[i]}_gacha_num'] * 2
|
||||||
# # 获取背景图片各项参数
|
):
|
||||||
# _id = str(user_id)
|
total_data[i]['type'] = '仓鼠型'
|
||||||
# if _id.startswith('http'):
|
|
||||||
# char_pic = await get_qq_avatar(avatar_url=_id)
|
print(total_data)
|
||||||
# else:
|
# 常量偏移数据
|
||||||
# char_pic = await get_qq_avatar(qid=user_id)
|
single_y = 150
|
||||||
# char_pic = await draw_pic_with_ring(char_pic, 320)
|
|
||||||
#
|
# 计算图片尺寸
|
||||||
# avatar_title = Image.open(TEXT_PATH / 'avatar_title.png')
|
normal_y = (1 + ((total_data['群星跃迁']['total'] - 1) // 6)) * single_y
|
||||||
# img = await get_color_bg(950, 530 + 900 + normal_y + char_y + weapon_y)
|
begin_y = (1 + ((total_data['始发跃迁']['total'] - 1) // 6)) * single_y
|
||||||
# img.paste(avatar_title, (0, 0), avatar_title)
|
char_y = (1 + ((total_data['角色跃迁']['total'] - 1) // 6)) * single_y
|
||||||
# img.paste(char_pic, (318, 83), char_pic)
|
weapon_y = (1 + ((total_data['光锥跃迁']['total'] - 1) // 6)) * single_y
|
||||||
# img_draw = ImageDraw.Draw(img)
|
|
||||||
# img_draw.text((475, 454), f'UID {uid}', first_color, gs_font_36, 'mm')
|
# 获取背景图片各项参数
|
||||||
#
|
_id = str(user_id)
|
||||||
# # 处理title
|
if _id.startswith('http'):
|
||||||
# # {'total': 0, 'avg': 0, 'remain': 0, 'list': []}
|
char_pic = await get_qq_avatar(avatar_url=_id)
|
||||||
# type_list = ['常驻祈愿', '角色祈愿', '武器祈愿']
|
else:
|
||||||
# y_extend = 0
|
char_pic = await get_qq_avatar(qid=user_id)
|
||||||
# level = 3
|
char_pic = await draw_pic_with_ring(char_pic, 206)
|
||||||
# for index, i in enumerate(type_list):
|
|
||||||
# title = Image.open(TEXT_PATH / 'gahca_title.png')
|
# 获取背景图片各项参数
|
||||||
# if i == '常驻祈愿':
|
img = Abg3_img.copy()
|
||||||
# level = await get_level_from_list(
|
img = await get_color_bg(
|
||||||
# total_data[i]['avg'], [54, 61, 67, 73, 80]
|
800, 1600 + 400 + normal_y + char_y + weapon_y + begin_y
|
||||||
# )
|
)
|
||||||
# else:
|
gacha_title = bg1_img.copy()
|
||||||
# if i == '武器祈愿':
|
gacha_title.paste(char_pic, (297, 81), char_pic)
|
||||||
# level = await get_level_from_list(
|
img.paste(gacha_title, (0, 0), gacha_title)
|
||||||
# total_data[i]['avg_up'], [62, 75, 88, 99, 111]
|
img_draw = ImageDraw.Draw(img)
|
||||||
# )
|
img_draw.text((400, 345), f'UID {uid}', white_color, sr_font_28, 'mm')
|
||||||
# else:
|
|
||||||
# level = await get_level_from_list(
|
# 处理title
|
||||||
# total_data[i]['avg_up'], [74, 87, 99, 105, 120]
|
# {'total': 0, 'avg': 0, 'remain': 0, 'list': []}
|
||||||
# )
|
type_list = ['群星跃迁', '始发跃迁', '角色跃迁', '光锥跃迁']
|
||||||
#
|
y_extend = 0
|
||||||
# emo_pic = await random_emo_pic(level)
|
level = 3
|
||||||
# emo_pic = emo_pic.resize((154, 154))
|
for index, i in enumerate(type_list):
|
||||||
# title.paste(emo_pic, (703, 28), emo_pic)
|
title = Image.open(TEXT_PATH / 'bg2.png')
|
||||||
# title_draw = ImageDraw.Draw(title)
|
if i == '群星跃迁':
|
||||||
# # 欧非描述
|
level = await get_level_from_list(
|
||||||
# title_draw.text(
|
total_data[i]['avg'], [54, 61, 67, 73, 80]
|
||||||
# (778, 207), HOMO_TAG[level - 1], first_color, gs_font_36, 'mm'
|
)
|
||||||
# )
|
elif i == '始发跃迁':
|
||||||
# # 卡池
|
level = await get_level_from_list(
|
||||||
# title_draw.text((69, 72), i, first_color, gs_font_62, 'lm')
|
total_data[i]['avg'], [62, 75, 88, 99, 111]
|
||||||
# # 抽卡时间
|
)
|
||||||
# if total_data[i]['time_range']:
|
else:
|
||||||
# time_range = total_data[i]['time_range']
|
if i == '光锥跃迁':
|
||||||
# else:
|
level = await get_level_from_list(
|
||||||
# time_range = '暂未抽过卡!'
|
total_data[i]['avg_up'], [62, 75, 88, 99, 111]
|
||||||
# title_draw.text((68, 122), time_range, brown_color, gs_font_28, 'lm')
|
)
|
||||||
# # 平均抽卡数量
|
else:
|
||||||
# title_draw.text(
|
level = await get_level_from_list(
|
||||||
# (123, 176),
|
total_data[i]['avg_up'], [74, 87, 99, 105, 120]
|
||||||
# str(total_data[i]['avg']),
|
)
|
||||||
# first_color,
|
|
||||||
# gs_font_40,
|
emo_pic = await random_emo_pic(level)
|
||||||
# 'mm',
|
emo_pic = emo_pic.resize((195, 195))
|
||||||
# )
|
title.paste(emo_pic, (500, 123), emo_pic)
|
||||||
# # 平均up
|
title_draw = ImageDraw.Draw(title)
|
||||||
# title_draw.text(
|
# 卡池
|
||||||
# (272, 176),
|
title_draw.text((110, 73), i, whole_white_color, sr_font_38, 'lm')
|
||||||
# str(total_data[i]['avg_up']),
|
# 抽卡时间
|
||||||
# first_color,
|
if total_data[i]['time_range']:
|
||||||
# gs_font_40,
|
time_range = total_data[i]['time_range']
|
||||||
# 'mm',
|
else:
|
||||||
# )
|
time_range = '暂未抽过卡!'
|
||||||
# # 抽卡总数
|
title_draw.text((78, 340), time_range, brown_color, sr_font_20, 'lm')
|
||||||
# title_draw.text(
|
# 平均抽卡数量
|
||||||
# (424, 176),
|
title_draw.text(
|
||||||
# str(gacha_data[f'{CHANGE_MAP[i]}_gacha_num']),
|
(143, 215),
|
||||||
# first_color,
|
str(total_data[i]['avg']),
|
||||||
# gs_font_40,
|
first_color,
|
||||||
# 'mm',
|
sr_font_40,
|
||||||
# )
|
'mm',
|
||||||
# # 抽卡类型
|
)
|
||||||
# title_draw.text(
|
# 平均up
|
||||||
# (585, 176),
|
title_draw.text(
|
||||||
# str(total_data[i]['type']),
|
(280, 215),
|
||||||
# first_color,
|
str(total_data[i]['avg_up']),
|
||||||
# gs_font_40,
|
first_color,
|
||||||
# 'mm',
|
sr_font_40,
|
||||||
# )
|
'mm',
|
||||||
# # 已抽数
|
)
|
||||||
# title_draw.text(
|
# 抽卡总数
|
||||||
# (383, 85),
|
title_draw.text(
|
||||||
# str(total_data[i]['remain']),
|
(413, 215),
|
||||||
# red_color,
|
str(gacha_data[f'{CHANGE_MAP[i]}_gacha_num']),
|
||||||
# gs_font_28,
|
first_color,
|
||||||
# 'mm',
|
sr_font_40,
|
||||||
# )
|
'mm',
|
||||||
# y_extend += (
|
)
|
||||||
# (1 + ((total_data[type_list[index - 1]]
|
# 已抽数
|
||||||
# ['total'] - 1) // 6)) * 150
|
title_draw.text(
|
||||||
# if index != 0
|
(333, 75),
|
||||||
# else 0
|
str(total_data[i]['remain']),
|
||||||
# )
|
red_color,
|
||||||
# y = 540 + index * 300 + y_extend
|
sr_font_28,
|
||||||
# img.paste(title, (0, y), title)
|
'mm',
|
||||||
# tasks = []
|
)
|
||||||
# for item_index, item in enumerate(total_data[i]['list']):
|
y_extend += (
|
||||||
# item_x = (item_index % 6) * 138 + 60
|
(1 + ((total_data[type_list[index - 1]]['total'] - 1) // 6)) * 150
|
||||||
# item_y = (item_index // 6) * 150 + y + 275
|
if index != 0
|
||||||
# xy_point = (item_x, item_y)
|
else 0
|
||||||
# tasks.append(
|
)
|
||||||
# _draw_card(
|
y = 350 + index * 400 + y_extend
|
||||||
# img,
|
img.paste(title, (0, y), title)
|
||||||
# xy_point,
|
tasks = []
|
||||||
# item['item_type'],
|
for item_index, item in enumerate(total_data[i]['list']):
|
||||||
# item['name'],
|
item_x = (item_index % 6) * 138 + 45
|
||||||
# item['gacha_num'],
|
item_y = (item_index // 6) * 150 + y + 355
|
||||||
# item['is_up'],
|
xy_point = (item_x, item_y)
|
||||||
# )
|
tasks.append(
|
||||||
# )
|
_draw_card(
|
||||||
# await asyncio.gather(*tasks)
|
img,
|
||||||
# tasks.clear()
|
xy_point,
|
||||||
#
|
item['item_type'],
|
||||||
# # 发送图片
|
item['name'],
|
||||||
# res = await convert_img(img)
|
item['gacha_num'],
|
||||||
# logger.info('[查询抽卡]绘图已完成,等待发送!')
|
item['is_up'],
|
||||||
# return res
|
)
|
||||||
|
)
|
||||||
|
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 (
|
from .SR_MAP_PATH import EquipmentID2Name, avatarId2Name
|
||||||
alias_data,
|
|
||||||
avatarId2Name,
|
|
||||||
avatarId2Star_data,
|
|
||||||
enName_to_avatarId_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def avatar_id_to_name(avatar_id: str) -> str:
|
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
|
return avatar_id
|
||||||
|
|
||||||
|
|
||||||
async def avatar_id_to_char_star(char_id: str) -> str:
|
async def weapon_id_to_name(weapon_id: str) -> str:
|
||||||
char_star = avatarId2Star_data[str(char_id)]
|
weapon_name = EquipmentID2Name[weapon_id]
|
||||||
return char_star
|
return weapon_name
|
||||||
|
|
||||||
|
|
||||||
async def alias_to_char_name(char_name: str) -> str:
|
async def name_to_weapon_id(name: str) -> str:
|
||||||
for i in alias_data:
|
weapon_id = ''
|
||||||
if (char_name in i) or (char_name in alias_data[i]):
|
for i in EquipmentID2Name:
|
||||||
return i
|
if EquipmentID2Name[i] == name:
|
||||||
return char_name
|
weapon_id = i
|
||||||
|
break
|
||||||
|
return weapon_id
|
||||||
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'
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from gsuid_core.data_store import get_res_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'
|
CONFIG_PATH = MAIN_PATH / 'config.json'
|
||||||
RESOURCE_PATH = MAIN_PATH / 'resource'
|
RESOURCE_PATH = MAIN_PATH / 'resource'
|
||||||
PLAYER_PATH = MAIN_PATH / 'players'
|
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'
|
WEAPON_PATH = RESOURCE_PATH / 'weapons'
|
||||||
|
TEXT2D_PATH = Path(__file__).parent / 'texture2d'
|
||||||
|
|
||||||
|
|
||||||
def init_dir():
|
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)
|
i.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
BIN
StarRailUID/utils/resource/texture2d/mask.png
Normal file
After Width: | Height: | Size: 53 KiB |