740 lines
31 KiB
Python
740 lines
31 KiB
Python
import json
|
|
import lzma
|
|
import math
|
|
import os
|
|
import pickle
|
|
import re
|
|
import shutil
|
|
from datetime import datetime
|
|
|
|
import cv2
|
|
import numpy as np
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
from skimage.feature import hog
|
|
from sklearn.neighbors import KNeighborsClassifier
|
|
|
|
from mower.utils.character_recognize import fast_keypoints
|
|
from mower.utils.image import loadimg, thres2
|
|
from mower.utils.vector import sa
|
|
|
|
|
|
def 加载json(file_path):
|
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
class Arknights数据处理器:
|
|
def __init__(self):
|
|
self.当前时间戳 = datetime.now().timestamp()
|
|
仓库_1 = "ArknightsGameResource/gamedata/excel"
|
|
仓库_2 = "ArknightsGameData/zh_CN/gamedata/excel"
|
|
仓库_3 = "ArknightsResource/gamedata/excel" # noqa: F841
|
|
self.物品表 = 加载json(f"./{仓库_2}/item_table.json")
|
|
self.干员表 = 加载json(f"./{仓库_2}/character_table.json")
|
|
self.阿米娅表 = 加载json(f"./{仓库_1}/char_patch_table.json")
|
|
self.抽卡表 = 加载json(f"./{仓库_2}/gacha_table.json")
|
|
self.关卡表 = 加载json(f"./{仓库_2}/stage_table.json")
|
|
self.活动表 = 加载json(f"./{仓库_2}/activity_table.json")
|
|
self.基建表 = 加载json(f"./{仓库_2}/building_data.json")
|
|
self.游戏变量 = 加载json(f"./{仓库_2}/gamedata_const.json")
|
|
self.模组 = 加载json(f"./{仓库_2}/uniequip_table.json")
|
|
self.战斗技能 = 加载json(f"./{仓库_2}/skill_table.json")
|
|
self.装仓库物品的字典 = {"NORMAL": [], "CONSUME": [], "MATERIAL": []}
|
|
self.常驻关卡 = 加载json("mower/data/stage_data.json")
|
|
|
|
self.所有buff = []
|
|
|
|
self.限定十连 = self.抽卡表["limitTenGachaItem"]
|
|
self.联动十连 = self.抽卡表["linkageTenGachaItem"]
|
|
self.普通十连 = self.抽卡表["normalGachaItem"]
|
|
self.所有卡池 = self.限定十连 + self.联动十连 + self.普通十连
|
|
self.总掉落表 = []
|
|
|
|
def 添加物品至前端文件(self):
|
|
"""和 数据处理器.输出_活动关卡和掉落() 有联动 , 读取活动关卡提供了额外的图片 活动代币"""
|
|
|
|
def 检查图标代码匹配(目标图标代码, 物品类型, 分类类型, 排序代码):
|
|
匹配结果 = False
|
|
for 池子限时物品 in self.所有卡池:
|
|
if (
|
|
池子限时物品["itemId"] == 目标图标代码
|
|
and self.当前时间戳 > 池子限时物品["endTime"]
|
|
):
|
|
匹配结果 = True
|
|
break
|
|
分割部分 = 目标图标代码.split("_")
|
|
if len(分割部分) == 2 and 分割部分[0].endswith("recruitment10"):
|
|
匹配结果 = True
|
|
if len(分割部分) == 6 and int(分割部分[5]) < 2023:
|
|
匹配结果 = True
|
|
|
|
if len(分割部分) == 3 and 目标图标代码.startswith("uni"):
|
|
匹配结果 = True
|
|
|
|
if len(分割部分) == 3 and 目标图标代码.startswith("voucher_full"):
|
|
匹配结果 = True
|
|
if 目标图标代码 == "ap_supply_lt_60":
|
|
匹配结果 = True
|
|
抽卡 = self.抽卡表.get("gachaPoolClient", [])
|
|
for 卡池 in 抽卡:
|
|
if 卡池["LMTGSID"] == 目标图标代码 and self.当前时间戳 > int(
|
|
卡池["endTime"]
|
|
):
|
|
匹配结果 = True
|
|
if 分类类型 == "NONE":
|
|
匹配结果 = True
|
|
if 排序代码 <= 0:
|
|
匹配结果 = True
|
|
if 分类类型 == "NONE":
|
|
for item in self.总掉落表:
|
|
if 目标图标代码 == item["id"]:
|
|
匹配结果 = False
|
|
return 匹配结果
|
|
|
|
self.物品_名称_输出用 = {}
|
|
self.物品_名称_模型用 = {}
|
|
if not os.path.exists("./ui/public/depot/EXP.webp"):
|
|
png_image = Image.open("./ArknightsGameResource/item/EXP_PLAYER.png")
|
|
png_image.save("./ui/public/depot/EXP.webp", "WEBP")
|
|
for 物品代码, 物品数据 in self.物品表["items"].items():
|
|
中文名称 = 物品数据.get("name", "")
|
|
图标代码 = 物品数据.get("iconId", "")
|
|
排序代码 = 物品数据.get("sortId", "")
|
|
分类类型 = 物品数据.get("classifyType", "")
|
|
物品类型 = 物品数据.get("itemType", "")
|
|
源文件路径 = f"./ArknightsGameResource/item/{图标代码}.png"
|
|
排除开关 = False
|
|
排除开关 = 检查图标代码匹配(图标代码, 物品类型, 分类类型, 排序代码)
|
|
if not 排除开关:
|
|
if os.path.exists(源文件路径):
|
|
目标文件路径 = f"./ui/public/depot/{中文名称}.webp"
|
|
if not os.path.exists(目标文件路径):
|
|
png_image = Image.open(源文件路径)
|
|
png_image.save(目标文件路径, "WEBP")
|
|
if 分类类型 != "NONE":
|
|
self.装仓库物品的字典[分类类型].append(
|
|
[目标文件路径, 源文件路径]
|
|
)
|
|
templist = [物品代码, 图标代码, 中文名称, 分类类型, 排序代码]
|
|
self.物品_名称_输出用[物品代码] = templist
|
|
self.物品_名称_模型用[中文名称] = templist
|
|
self.物品_名称_模型用[物品代码] = templist
|
|
print(f"复制 {源文件路径} 到 {目标文件路径}")
|
|
with open("./mower/data/key_mapping.json", "w", encoding="utf8") as json_file:
|
|
json.dump(self.物品_名称_输出用, json_file, ensure_ascii=False, indent=4)
|
|
print()
|
|
|
|
def 干员列表(self):
|
|
"""读取干员列表并输出至./mower/data/agent.json"""
|
|
干员_名称列表 = {}
|
|
for 干员代码, 干员数据 in self.干员表.items():
|
|
if not 干员数据["itemObtainApproach"]:
|
|
continue
|
|
干员名 = 干员数据["name"]
|
|
干员_名称列表[干员名] = {
|
|
"key": 干员代码,
|
|
"profession": 干员数据["profession"],
|
|
"name": 干员数据["appellation"],
|
|
}
|
|
干员头像路径 = f"./ArknightsGameResource/avatar/{干员代码}.png"
|
|
目标路径 = f"./ui/public/avatar/{干员数据['name']}.webp"
|
|
print(f"{干员名}: {干员代码}")
|
|
|
|
png_image = Image.open(干员头像路径)
|
|
png_image.save(目标路径, "WEBP")
|
|
干员_名称列表 = dict(sorted(干员_名称列表.items()))
|
|
with open("./mower/data/agent.json", "w", encoding="utf-8") as f:
|
|
json.dump(干员_名称列表, f, ensure_ascii=False, indent=4)
|
|
|
|
def 读取卡池(self):
|
|
"""读取当前开放的卡池,暂无输出"""
|
|
抽卡 = self.抽卡表.get("gachaPoolClient", [])
|
|
卡池类型映射 = {
|
|
"SINGLE": "单人池",
|
|
"LIMITED": "限定池",
|
|
"NORM": "普通池",
|
|
"CLASSIC": "中坚池",
|
|
"CLASSIC_ATTAIN": "跨年中坚池",
|
|
"LINKAGE": "联动池",
|
|
"ATTAIN": "跨年池",
|
|
"FESCLASSIC": "中坚甄选",
|
|
}
|
|
|
|
for 项 in 抽卡:
|
|
卡池名称 = 项.get("gachaPoolName")
|
|
开始时间戳 = 项.get("openTime")
|
|
结束时间戳 = 项.get("endTime")
|
|
卡池类型代码 = 项.get("gachaPoolId")
|
|
卡池出人 = 项.get("dynMeta")
|
|
|
|
if self.当前时间戳 < 结束时间戳:
|
|
卡池类型 = 卡池类型映射.get(卡池类型代码.split("_")[0], 卡池类型代码)
|
|
if 卡池类型代码.split("_")[1] == "ATTAIN":
|
|
卡池类型 = "跨年中坚池"
|
|
if 卡池名称 == "适合多种场合的强力干员":
|
|
卡池名称 = 卡池类型
|
|
开始时间 = datetime.fromtimestamp(开始时间戳)
|
|
结束时间 = datetime.fromtimestamp(结束时间戳 + 1)
|
|
print("卡池名称:", 卡池名称)
|
|
print("卡池类型:", 卡池类型)
|
|
if 卡池类型 == "中坚池":
|
|
print(
|
|
卡池出人["main6RarityCharId"],
|
|
卡池出人["sub6RarityCharId"],
|
|
卡池出人["rare5CharList"],
|
|
)
|
|
if self.当前时间戳 > 开始时间戳:
|
|
print("正在进行")
|
|
print("卡池结束时间:", 结束时间)
|
|
else:
|
|
print("卡池开始时间:", 开始时间)
|
|
print("卡池结束时间:", 结束时间)
|
|
print(卡池类型代码)
|
|
print()
|
|
|
|
def 输出_活动关卡和掉落(self):
|
|
"""读取活动关卡及掉落物并写入./ui/src/pages/stage_data/event_data.json"""
|
|
关卡 = self.关卡表["stageValidInfo"]
|
|
还未结束的非常驻关卡 = {
|
|
键: 值
|
|
for 键, 值 in 关卡.items()
|
|
if 值["endTs"] != -1 and 值["endTs"] > self.当前时间戳
|
|
}
|
|
还未结束的非常驻关卡 = dict(sorted(还未结束的非常驻关卡.items()))
|
|
for 键, _ in 还未结束的非常驻关卡.items():
|
|
关卡代码 = self.关卡表["stages"][键]["code"]
|
|
if 键.endswith("#f#"):
|
|
关卡代码 += " 突袭"
|
|
关卡名称 = self.关卡表["stages"][键]["name"]
|
|
关卡结束时间戳 = 还未结束的非常驻关卡[键]["endTs"]
|
|
关卡消耗理智 = self.关卡表["stages"][键]["apCost"]
|
|
# 关卡结束时间 = datetime.fromtimestamp(还未结束的非常驻关卡[键]["endTs"] + 1)
|
|
关卡掉落表 = self.关卡表["stages"][键]["stageDropInfo"][
|
|
"displayDetailRewards"
|
|
]
|
|
self.总掉落表.extend(关卡掉落表)
|
|
关卡掉落 = {}
|
|
突袭首次掉落 = [
|
|
self.物品表.get("items", {}).get(item["id"], {}).get("name", item["id"])
|
|
for item in 关卡掉落表
|
|
if item["dropType"] == 1
|
|
]
|
|
常规掉落 = [
|
|
self.物品表.get("items", {}).get(item["id"], {}).get("name", item["id"])
|
|
for item in 关卡掉落表
|
|
if item["dropType"] == 2
|
|
]
|
|
特殊掉落 = [
|
|
self.物品表.get("items", {}).get(item["id"], {}).get("name", item["id"])
|
|
for item in 关卡掉落表
|
|
if item["dropType"] == 3
|
|
]
|
|
额外物资 = [
|
|
self.物品表.get("items", {}).get(item["id"], {}).get("name", item["id"])
|
|
for item in 关卡掉落表
|
|
if item["dropType"] == 4
|
|
]
|
|
首次掉落 = [
|
|
self.物品表.get("items", {}).get(item["id"], {}).get("name", item["id"])
|
|
for item in 关卡掉落表
|
|
if item["dropType"] == 8
|
|
]
|
|
关卡掉落 = {
|
|
"突袭首次掉落": 突袭首次掉落,
|
|
"常规掉落": 常规掉落,
|
|
"首次掉落": 首次掉落,
|
|
"特殊掉落": 特殊掉落,
|
|
"额外物资": 额外物资,
|
|
}
|
|
|
|
self.常驻关卡.append(
|
|
{
|
|
"id": 关卡代码,
|
|
"id_key": 键,
|
|
"name": 关卡名称,
|
|
"drop": 关卡掉落,
|
|
"end": 关卡结束时间戳,
|
|
"理智消耗": 关卡消耗理智,
|
|
"周一": 1,
|
|
"周二": 1,
|
|
"周三": 1,
|
|
"周四": 1,
|
|
"周五": 1,
|
|
"周六": 1,
|
|
"周日": 1,
|
|
}
|
|
)
|
|
unkey = 0
|
|
for item in self.常驻关卡:
|
|
item["key"] = unkey
|
|
unkey += 1
|
|
with open(
|
|
"./ui/src/pages/stage_data/event_data.json", "w", encoding="utf-8"
|
|
) as f:
|
|
json.dump(self.常驻关卡, f, ensure_ascii=False, indent=4)
|
|
|
|
def load_recruit_data(self):
|
|
recruit_data = {}
|
|
recruit_result_data = {
|
|
4: [],
|
|
3: [],
|
|
2: [],
|
|
1: [],
|
|
-1: [],
|
|
}
|
|
# for 干员代码, 干员数据 in self.干员表.items():
|
|
# print(干员代码,干员数据)
|
|
recruit_list = self.抽卡表["recruitDetail"].replace("\\n<@rc.eml>", "")
|
|
recruit_list = recruit_list.replace("\\n", "")
|
|
recruit_list = recruit_list.replace("\r", "")
|
|
recruit_list = recruit_list.replace("★", "")
|
|
recruit_list = recruit_list.replace("<@rc.eml>", "")
|
|
recruit_list = recruit_list.replace("</>", "")
|
|
recruit_list = recruit_list.replace("/", "")
|
|
recruit_list = recruit_list.replace(" ", "\n")
|
|
recruit_list = recruit_list.replace("--------------------", "")
|
|
recruit_list = recruit_list.replace("<@rc.title>公开招募说明", "")
|
|
recruit_list = recruit_list.replace("<@rc.em>※稀有职业需求招募说明※", "")
|
|
recruit_list = recruit_list.replace(
|
|
"<@rc.em>当职业需求包含高级资深干员,且招募时限为9小时时,招募必得6星干员",
|
|
"",
|
|
)
|
|
recruit_list = recruit_list.replace(
|
|
"<@rc.em>当职业需求包含资深干员同时不包含高级资深干员,且招募时限为9小时,则该次招募必得5星干员",
|
|
"",
|
|
)
|
|
recruit_list = recruit_list.replace("<@rc.subtitle>※全部可能出现的干员※", "")
|
|
recruit_list = recruit_list.replace("绿色高亮的不可寻访干员,可以在此招募", "")
|
|
recruit_list = recruit_list.split("\n")
|
|
|
|
profession = {
|
|
"MEDIC": "医疗干员",
|
|
"WARRIOR": "近卫干员",
|
|
"SPECIAL": "特种干员",
|
|
"SNIPER": "狙击干员",
|
|
"CASTER": "术师干员",
|
|
"TANK": "重装干员",
|
|
"SUPPORT": "辅助干员",
|
|
"PIONEER": "先锋干员",
|
|
}
|
|
|
|
for 干员代码, 干员数据 in self.干员表.items():
|
|
干员名 = 干员数据["name"]
|
|
|
|
if 干员数据["profession"] not in profession:
|
|
continue
|
|
|
|
if 干员名 in recruit_list:
|
|
tag = 干员数据["tagList"]
|
|
# 数据中稀有度从0-5
|
|
if 干员数据["rarity"].startswith("TIER_"):
|
|
干员数据["rarity"] = int(干员数据["rarity"][-1]) - 1
|
|
干员数据["rarity"] = 干员数据["rarity"] + 1
|
|
if len(干员名) <= 4:
|
|
recruit_result_data[len(干员名)].append(干员代码)
|
|
else:
|
|
recruit_result_data[-1].append(干员代码)
|
|
if 干员数据["rarity"] == 5:
|
|
tag.append("资深干员")
|
|
elif 干员数据["rarity"] == 6:
|
|
tag.append("高级资深干员")
|
|
|
|
if 干员数据["position"] == "MELEE":
|
|
tag.append("近战位")
|
|
elif 干员数据["position"] == "RANGED":
|
|
tag.append("远程位")
|
|
|
|
tag.append(profession[干员数据["profession"]])
|
|
|
|
recruit_data[干员代码] = {
|
|
"name": 干员名,
|
|
"stars": 干员数据["rarity"],
|
|
"tags": 干员数据["tagList"],
|
|
}
|
|
print(
|
|
"{} stars:{} tags:{}".format(
|
|
干员名, 干员数据["rarity"], 干员数据["tagList"]
|
|
)
|
|
)
|
|
print("载入公招干员数据{}个".format(len(recruit_data)))
|
|
with open("./mower/data/recruit.json", "w", encoding="utf-8") as f:
|
|
json.dump(recruit_data, f, ensure_ascii=False, indent=4)
|
|
|
|
with open("./mower/data/recruit_result.json", "w", encoding="utf-8") as f:
|
|
json.dump(recruit_result_data, f, ensure_ascii=False, indent=4)
|
|
|
|
def load_recruit_template(self):
|
|
# !/usr/bin/env python3
|
|
template = {}
|
|
with open("./mower/data/recruit.json", "r", encoding="utf-8") as f:
|
|
recruit_operators = json.load(f)
|
|
|
|
font = ImageFont.truetype("FZDYSK.TTF", 120)
|
|
print(len(recruit_operators))
|
|
for operator in recruit_operators:
|
|
im = Image.new(mode="RGBA", size=(1920, 1080))
|
|
draw = ImageDraw.Draw(im)
|
|
draw.text((0, 0), recruit_operators[operator]["name"], font=font)
|
|
im = im.crop(im.getbbox())
|
|
im = cv2.cvtColor(np.asarray(im), cv2.COLOR_RGB2GRAY)
|
|
im = cv2.erode(im, np.ones((5, 5)))
|
|
template[operator] = im
|
|
|
|
with lzma.open("mower/static/recruit_result.pkl", "wb") as f:
|
|
pickle.dump(template, f)
|
|
|
|
def load_recruit_tag(self):
|
|
with open("./mower/data/recruit.json", "r", encoding="utf-8") as f:
|
|
recruit_agent = json.load(f)
|
|
|
|
font = ImageFont.truetype("mower/fonts/SourceHanSansCN-Medium.otf", 30)
|
|
recruit_tag = ["资深干员", "高级资深干员"]
|
|
recruit_tag_template = {}
|
|
for x in recruit_agent.values():
|
|
recruit_tag += x["tags"]
|
|
recruit_tag = list(set(recruit_tag))
|
|
for tag in sorted(recruit_tag):
|
|
im = Image.new(mode="RGBA", color=(49, 49, 49), size=(215, 70))
|
|
W, H = im.size
|
|
draw = ImageDraw.Draw(im)
|
|
_, _, w, h = draw.textbbox((0, 0), tag, font=font)
|
|
draw.text(((W - w) / 2, (H - h) / 2 - 5), tag, font=font)
|
|
recruit_tag_template[tag] = cv2.cvtColor(
|
|
np.array(im.crop(im.getbbox())), cv2.COLOR_RGB2BGR
|
|
)
|
|
with lzma.open("./mower/static/recruit.pkl", "wb") as f:
|
|
pickle.dump(recruit_tag_template, f)
|
|
|
|
def 输出_公招资源(self):
|
|
self.load_recruit_data()
|
|
self.load_recruit_template()
|
|
self.load_recruit_tag()
|
|
|
|
def 训练仓库的knn模型(self, 模板文件夹, 模型保存路径):
|
|
def 提取特征点(模板):
|
|
模板 = 模板[40:173, 40:173]
|
|
hog_features = hog(
|
|
模板,
|
|
orientations=18,
|
|
pixels_per_cell=(8, 8),
|
|
cells_per_block=(2, 2),
|
|
block_norm="L2-Hys",
|
|
transform_sqrt=True,
|
|
channel_axis=2,
|
|
)
|
|
|
|
return hog_features
|
|
|
|
def 加载图片特征点_标签(模板类型):
|
|
特征点列表 = []
|
|
标签列表 = []
|
|
for [目标文件路径, 源文件路径] in self.装仓库物品的字典[模板类型]:
|
|
模板 = cv2.imread(源文件路径)
|
|
模板 = cv2.resize(模板, (213, 213))
|
|
特征点 = 提取特征点(模板)
|
|
特征点列表.append(特征点)
|
|
标签列表.append(self.物品_名称_模型用[目标文件路径[18:-5]][2])
|
|
return 特征点列表, 标签列表
|
|
|
|
def 训练knn模型(images, labels):
|
|
knn_classifier = KNeighborsClassifier(
|
|
weights="distance", n_neighbors=1, n_jobs=1
|
|
)
|
|
knn_classifier.fit(images, labels)
|
|
return knn_classifier
|
|
|
|
def 保存knn模型(classifier, filename):
|
|
with lzma.open(filename, "wb") as f:
|
|
pickle.dump(classifier, f)
|
|
|
|
模板特征点, 模板标签 = 加载图片特征点_标签(模板文件夹)
|
|
knn模型 = 训练knn模型(模板特征点, 模板标签)
|
|
保存knn模型(knn模型, 模型保存路径)
|
|
|
|
def 输出_扫仓库模型(self):
|
|
"""输出扫描仓库的Knn模型
|
|
|
|
和添加物品至前端文件() 有联动 , 添加物品提供了分类的图片位置"""
|
|
|
|
self.训练仓库的knn模型("NORMAL", "./mower/static/NORMAL.pkl")
|
|
self.训练仓库的knn模型("CONSUME", "./mower/static/CONSUME.pkl")
|
|
self.训练仓库的knn模型("MATERIAL", "./mower/static/MATERIAL.pkl")
|
|
|
|
def 输出_在房间内的干员名的模型(self):
|
|
font = ImageFont.truetype("mower/fonts/SourceHanSansCN-Medium.otf", 37)
|
|
|
|
data = {}
|
|
|
|
kernel = np.ones((12, 12), np.uint8)
|
|
|
|
with open("./mower/data/agent.json", "r", encoding="utf-8") as f:
|
|
agent_list = json.load(f)
|
|
for operator in sorted(agent_list, key=lambda x: len(x), reverse=True):
|
|
img = Image.new(mode="L", size=(400, 100))
|
|
draw = ImageDraw.Draw(img)
|
|
draw.text((50, 20), operator, fill=(255,), font=font)
|
|
img = np.array(img, dtype=np.uint8)
|
|
img = thres2(img, 200)
|
|
dilation = cv2.dilate(img, kernel, iterations=1)
|
|
contours, _ = cv2.findContours(
|
|
dilation, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE
|
|
)
|
|
rect = map(lambda c: cv2.boundingRect(c), contours)
|
|
x, y, w, h = sorted(rect, key=lambda c: c[0])[0]
|
|
img = img[y : y + h, x : x + w]
|
|
tpl = np.zeros((46, 265), dtype=np.uint8)
|
|
tpl[: img.shape[0], : img.shape[1]] = img
|
|
# cv2.imwrite(f"/home/zhao/Desktop/data/{operator}.png", tpl)
|
|
data[operator] = tpl
|
|
|
|
with lzma.open("mower/static/operator_room.model", "wb") as f:
|
|
pickle.dump(data, f)
|
|
|
|
def avatar_and_portrait(self, save_img=False):
|
|
mapping = {} # char_285_medic2 -> Lancet-2
|
|
for name, data in self.干员表.items():
|
|
mapping[name] = data["name"]
|
|
for name in self.阿米娅表["infos"]["char_002_amiya"]["tmplIds"]:
|
|
mapping[name] = "阿米娅"
|
|
|
|
def extract(name, scope):
|
|
data_path = f"./ArknightsGameResource/{name}"
|
|
file_list = os.listdir(data_path)
|
|
h, w = loadimg(os.path.join(data_path, file_list[0]), True).shape
|
|
total = len(file_list)
|
|
col = math.ceil(math.sqrt(total * h / w))
|
|
row = math.ceil(total / col)
|
|
full = np.zeros((row * h, col * w), dtype=np.uint8)
|
|
mask = full.copy()
|
|
name_list = []
|
|
i = 0
|
|
for filename in file_list:
|
|
x = (i % col) * w
|
|
y = (i // col) * h
|
|
mx, my = sa(scope, (x, y))
|
|
# filename: char_285_medic2_1.png
|
|
for j, k in mapping.items():
|
|
# j: char_285_medic2
|
|
# k: Lancet-2
|
|
if filename.startswith(j):
|
|
full[y : y + h, x : x + w] = loadimg(
|
|
os.path.join(data_path, filename), True
|
|
)
|
|
cv2.rectangle(mask, mx, my, (255,), -1)
|
|
name_list.append(k)
|
|
i += 1
|
|
break
|
|
|
|
if save_img:
|
|
disp = cv2.bitwise_and(full, mask)
|
|
cv2.imwrite(f"{name}.png", disp)
|
|
|
|
kp, des = fast_keypoints(full, mask)
|
|
pt = [p.pt for p in kp]
|
|
data = {"w": w, "h": h, "col": col, "name": name_list, "pt": pt, "des": des}
|
|
with lzma.open(f"./mower/static/{name}.pkl", "wb") as f:
|
|
pickle.dump(data, f)
|
|
|
|
extract("avatar", ((20, 51), (160, 146)))
|
|
extract("portrait", ((20, 115), (160, 190)))
|
|
|
|
def 获得干员基建描述(self):
|
|
buff描述 = self.基建表["buffs"]
|
|
buff_table = {}
|
|
for buff名称, 相关buff in buff描述.items():
|
|
buff_table[buff名称] = [
|
|
相关buff["buffName"],
|
|
相关buff["description"],
|
|
相关buff["roomType"],
|
|
相关buff["buffCategory"],
|
|
相关buff["skillIcon"],
|
|
相关buff["buffColor"],
|
|
相关buff["textColor"],
|
|
]
|
|
|
|
干员技能列表 = []
|
|
|
|
name_key = 0
|
|
for 角色id, 相关buff in self.基建表["chars"].items():
|
|
干员技能字典 = {
|
|
"key": 0,
|
|
"name": "",
|
|
"span": 0,
|
|
"child_skill": [],
|
|
}
|
|
|
|
干员技能字典["name"] = self.干员表[角色id]["name"]
|
|
|
|
skill_key = 0
|
|
name_key += 1
|
|
干员技能字典["key"] = name_key
|
|
for item in 相关buff["buffChar"]:
|
|
skill_level = 0
|
|
|
|
if item["buffData"] != []:
|
|
for item2 in item["buffData"]:
|
|
干员技能详情 = {}
|
|
|
|
干员技能详情["skill_key"] = skill_key
|
|
干员技能详情["skill_level"] = skill_level
|
|
skill_level += 1
|
|
干员技能详情["phase_level"] = (
|
|
f'精{item2["cond"]["phase"][-1]} {item2["cond"]["level"]}级'
|
|
)
|
|
干员技能详情["skillname"] = buff_table[item2["buffId"]][0]
|
|
text = buff_table[item2["buffId"]][1]
|
|
pattern = r"<\$(.*?)>"
|
|
matches = re.findall(pattern, text)
|
|
ex_string = []
|
|
干员技能详情["buffer"] = False
|
|
干员技能详情["buffer_des"] = []
|
|
if matches:
|
|
干员技能详情["buffer"] = True
|
|
ex_string = list(
|
|
set([match.replace(".", "_") for match in matches])
|
|
)
|
|
ex_string.sort()
|
|
干员技能详情["buffer_des"] = ex_string
|
|
self.所有buff.extend(ex_string)
|
|
|
|
干员技能详情["des"] = text
|
|
干员技能详情["roomType"] = roomType[
|
|
buff_table[item2["buffId"]][2]
|
|
]
|
|
干员技能详情["buffCategory"] = buff_table[item2["buffId"]][3]
|
|
干员技能详情["skillIcon"] = buff_table[item2["buffId"]][4]
|
|
干员技能详情["buffColor"] = buff_table[item2["buffId"]][5]
|
|
干员技能详情["textColor"] = buff_table[item2["buffId"]][6]
|
|
|
|
干员技能字典["child_skill"].append(干员技能详情)
|
|
|
|
干员技能详情 = []
|
|
干员技能字典["span"] = len(干员技能字典["child_skill"])
|
|
skill_key += 1
|
|
干员技能列表.append(干员技能字典.copy())
|
|
干员技能列表 = sorted(干员技能列表, key=lambda x: (-x["key"]))
|
|
# print(干员技能列表)
|
|
with open(
|
|
"./ui/src/pages/basement_skill/skill.json", "w", encoding="utf-8"
|
|
) as f:
|
|
json.dump(干员技能列表, f, ensure_ascii=False, indent=4)
|
|
|
|
def 转换输出基建buff(self):
|
|
buff_table = {}
|
|
pattern = r"<\$(.*?)>"
|
|
|
|
for item in self.游戏变量["termDescriptionDict"]:
|
|
matches = re.findall(
|
|
pattern, self.游戏变量["termDescriptionDict"][item]["description"]
|
|
)
|
|
matches = [match.replace(".", "_") for match in matches]
|
|
dict1 = self.游戏变量["termDescriptionDict"][item]
|
|
dict1["buffer"] = []
|
|
if item.startswith("cc") and matches:
|
|
dict1["buffer"] = matches
|
|
buff_table[item.replace(".", "_")] = dict1
|
|
|
|
with open(
|
|
"./ui/src/pages/basement_skill/buffer.json", "w", encoding="utf-8"
|
|
) as f:
|
|
json.dump(buff_table, f, ensure_ascii=False, indent=4)
|
|
|
|
def 添加基建技能图标(self):
|
|
# 源目录和目标目录
|
|
source_dir = "./ArknightsGameResource/building_skill"
|
|
destination_dir = "./ui/public/building_skill"
|
|
|
|
# 创建目标目录(如果不存在)
|
|
os.makedirs(destination_dir, exist_ok=True)
|
|
# 遍历源目录中的所有文件
|
|
for root, dirs, files in os.walk(source_dir):
|
|
for file in files:
|
|
if file.endswith(".png"):
|
|
src_file_path = os.path.join(root, file)
|
|
# 修改文件扩展名为 .webp
|
|
dest_file_name = os.path.splitext(file)[0] + ".webp"
|
|
dest_file_path = os.path.join(destination_dir, dest_file_name)
|
|
if not os.path.exists(dest_file_path):
|
|
with Image.open(src_file_path) as img:
|
|
img.save(dest_file_path, "webp")
|
|
print(f"转换: {src_file_path} 到 {dest_file_path}")
|
|
else:
|
|
print(f"跳过: {dest_file_path} 已存在")
|
|
|
|
def 输出_前端基建资源(self):
|
|
self.获得干员基建描述()
|
|
self.转换输出基建buff()
|
|
self.添加基建技能图标()
|
|
|
|
def levels(self):
|
|
levels_json = 加载json("./ArknightsGameResource/levels.json")
|
|
with lzma.open("mower/static/levels.pkl", "wb") as f:
|
|
pickle.dump(levels_json, f)
|
|
|
|
def 读取模组(self):
|
|
_ = []
|
|
for item in self.模组["missionList"]:
|
|
_.append(self.模组["missionList"][item]["template"])
|
|
template_list = list({}.fromkeys(_).keys())
|
|
print(template_list)
|
|
|
|
def 输出_干员战斗技能图标(self):
|
|
for 干员代码, 干员数据 in self.干员表.items():
|
|
if not 干员数据["itemObtainApproach"]:
|
|
continue
|
|
干员名 = 干员数据["name"]
|
|
print(干员名)
|
|
for 技能数, item in enumerate(干员数据["skills"]):
|
|
技能图标名 = self.战斗技能[item["skillId"]]["iconId"] or item["skillId"]
|
|
干员技能路径 = (
|
|
f"./ArknightsGameResource/skill/skill_icon_{技能图标名}.png"
|
|
)
|
|
os.makedirs(
|
|
f"./mower/static/avatar_skill/{干员数据['name']}", exist_ok=True
|
|
)
|
|
目标路径 = (
|
|
f"./mower/static/avatar_skill/{干员数据['name']}/{技能数+1}.png"
|
|
)
|
|
shutil.copy(干员技能路径, 目标路径)
|
|
print(目标路径)
|
|
|
|
|
|
roomType = {
|
|
"POWER": "发电站",
|
|
"DORMITORY": "宿舍",
|
|
"MANUFACTURE": "制造站",
|
|
"MEETING": "会客室",
|
|
"WORKSHOP": "加工站",
|
|
"TRADING": "贸易站",
|
|
"HIRE": "人力办公室",
|
|
"TRAINING": "训练室",
|
|
"CONTROL": "中枢",
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
数据处理器 = Arknights数据处理器()
|
|
|
|
数据处理器.干员列表()
|
|
|
|
数据处理器.读取卡池()
|
|
|
|
数据处理器.输出_活动关卡和掉落()
|
|
|
|
数据处理器.添加物品至前端文件() # 显示在仓库里的物品
|
|
|
|
数据处理器.输出_扫仓库模型()
|
|
|
|
数据处理器.输出_在房间内的干员名的模型()
|
|
|
|
数据处理器.avatar_and_portrait()
|
|
|
|
数据处理器.输出_前端基建资源()
|
|
|
|
数据处理器.输出_干员战斗技能图标()
|
|
|
|
数据处理器.输出_公招资源()
|
|
|
|
数据处理器.levels()
|
|
|
|
# 数据处理器.读取模组()#不好用
|