This commit is contained in:
antecanis8 2024-09-28 02:33:02 +08:00 committed by GitHub
commit 0c03280403
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
83 changed files with 679 additions and 1 deletions

3
.gitignore vendored
View File

@ -256,3 +256,6 @@ adb_port.ini
!popup.exe
*.zip
.vscode/*
#Typeface
*.ttf

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 956 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -111,7 +111,9 @@ class AssetsImage:
def parse(self):
image = load_image(self.file)
if self.module=='relics/name':
self.valid = False
return None
size = image_size(image)
if size != AzurLaneConfig.ASSETS_RESOLUTION:
logger.warning(f'{self.file} has wrong resolution: {size}')

View File

@ -583,6 +583,61 @@ class KeywordExtract:
visited.add(name)
yield hash_
def generate_relics(self):
relicSetConfigs = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RelicSetConfig.json'))
relic_id = [deep_get(data, 'SetID') for data in relicSetConfigs]
relicSetConfigs = {
str(data["SetID"]): data
for data in relicSetConfigs
}
ItemComefroms = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'ItemComefrom.json'))
ItemComefroms = {
str(deep_get(data, 'ID')): data
for data in ItemComefroms
}
GotoConfigs = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'GotoConfig.json'))
GotoConfigs = {
str(deep_get(data, 'ID')): data
for data in GotoConfigs
}
def get_relics_infos(id_list):
_relics_hash = [deep_get(relicSetConfigs, f"{relics_id}.SetName.Hash")
for relics_id in id_list]
_DisplayItemID = [deep_get(relicSetConfigs, f"{relics_id}.DisplayItemID")
for relics_id in id_list]
_GotoID = [deep_get(ItemComefroms, f"{DisplayItemID}.GotoID")
for DisplayItemID in _DisplayItemID]
_dungeon_id = [deep_get(GotoConfigs, f"{GotoID}.ParamIntList")[0]
for GotoID in _GotoID]
_plane_id = [deep_get(GotoConfigs, f"{GotoID}.ParamIntList")[1]
for GotoID in _GotoID]
combined_info_plane_id = {}
combined_info_dungeon_id = {}
for i in range(len(_relics_hash)):
relic_hash = _relics_hash[i]
dungeon_id = _dungeon_id[i]
plane_id = _plane_id[i]
info_plane_id = {
relic_hash: plane_id
}
info_dungeon_id = {
relic_hash: dungeon_id
}
combined_info_plane_id.update(info_plane_id)
combined_info_dungeon_id.update(info_dungeon_id)
return _relics_hash,{'plane_id':combined_info_plane_id,'dungeon_id':combined_info_dungeon_id}
self.load_keywords(list(self.iter_without_duplication(
read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RelicSetConfig.json')), 'SetName.Hash')))
hash_list, extra_attrs = get_relics_infos(relic_id)
self.keywords_id = hash_list
self.write_keywords(keyword_class='RelicSet', output_file='./tasks/relics/keywords/relics.py',extra_attrs=extra_attrs)
def generate(self):
self.load_keywords(['饰品提取', '差分宇宙', '模拟宇宙',
'拟造花萼(金)', '拟造花萼(赤)', '凝滞虚影', '侵蚀隧洞', '历战余响',
@ -627,6 +682,7 @@ class KeywordExtract:
read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'RogueBonus.json')), 'BonusTitle.Hash')))
self.write_keywords(keyword_class='RogueBonus', output_file='./tasks/rogue/keywords/bonus.py')
self.generate_rogue_events()
self.generate_relics()
if __name__ == '__main__':

View File

@ -0,0 +1,120 @@
import cv2
import numpy as np
import os
"""Find text rect
"""
template_folder = 'D:/Code_Work/antec/StarRailCopilot/assets/cn/relics/name'
class DetectText:
@classmethod
def detect_text_areas(cls, image_path):
imagea = cv2.imread(image_path)
hsv = cv2.cvtColor(imagea, cv2.COLOR_BGR2HSV)
# 定义白色的 HSV 范围,并生成白色掩膜
lower_white = np.array([0, 0, 200])
upper_white = np.array([180, 30, 255])
white_mask = cv2.inRange(hsv, lower_white, upper_white)
# 定义橙色的 HSV 范围,并生成橙色掩膜
lower_orange = np.array([10, 100, 100])
upper_orange = np.array([25, 255, 255])
orange_mask = cv2.inRange(hsv, lower_orange, upper_orange)
# 将两个掩膜进行结合
combined_mask = cv2.bitwise_or(white_mask, orange_mask)
result = cv2.bitwise_not(combined_mask)
# cv2.imshow("result", result)
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# blurred = cv2.GaussianBlur(image, (9, 9), 0)
# subtracted = cv2.subtract(image, blurred)
#
# _, binary = cv2.threshold(
# subtracted, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU
# )
result_inv=cv2.bitwise_not(result)
kernel = np.ones((9, 9), np.uint8)
closed = cv2.morphologyEx(result_inv, cv2.MORPH_CLOSE, kernel)
dilated = cv2.dilate(closed, kernel, iterations=2)
# cv2.RETR_EXTERNAL
contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
text_areas = []
output_image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
point=(887,500)
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
# 过滤掉太小的区域
if w > 5 and h > 13:
text_areas.append((x, y, w, h))
cv2.rectangle(output_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
if cv2.pointPolygonTest(contour, point, measureDist=False) >= 0:
roi = result[y:y + h, x:x + w]
# cv2.imshow("binary_roi", binary_roi)
# 模板匹配
best_match_score = 0
best_match_name = None
for filename in os.listdir(template_folder):
if filename.endswith(('.png', '.jpg', '.jpeg')):
template = cv2.imread(os.path.join(template_folder, filename), 0)
w, h = template.shape[::-1]
if roi.shape[0] < template.shape[0] or roi.shape[1] < template.shape[1]:
continue
# cv2.imshow("template", template)
# cv2.imshow("roi", roi)
res = cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.75 # 你可以根据需要调整这个阈值
loc = np.where(res >= threshold)
if loc[0].size > 0:
# 如果找到至少一个匹配项,取最大值的索引
max_val = np.max(res)
if max_val > best_match_score:
best_match_score = max_val
best_match_name = filename
# 如果找到了最佳匹配,则在原图上绘制匹配的图片名字
if best_match_name:
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(output_image, best_match_name, (x, y - 15), font, 0.8, (0, 0, 255), 2)
# text_areas, weights = cv2.groupRectangles(text_areas, groupThreshold=1, eps=0.5)
# for x, y, w, h in text_areas:
# cv2.rectangle(output_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("Detected Text Areas", output_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
return text_areas
def process_images_in_folder(folder_path):
# 确保文件夹路径以斜杠结束,以便正确拼接文件路径
if not folder_path.endswith(os.sep):
folder_path += os.sep
# 遍历文件夹中的所有文件
for filename in os.listdir(folder_path):
# 检查文件扩展名,确保只处理图片文件
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
# 拼接完整的文件路径
image_path = os.path.join(folder_path, filename)
# 调用DetectText的detect_text_areas函数处理图片
DetectText.detect_text_areas(image_path)
if __name__ == "__main__":
# 指定包含图片的文件夹路径
folder_path = "D:/Code_Work/antec/StarRailCopilot/dev_tools/"
# 调用函数处理文件夹中的所有图片
process_images_in_folder(folder_path)

64
dev_tools/text_draw.py Normal file
View File

@ -0,0 +1,64 @@
import cv2
import re
import numpy as np
import os
from PIL import ImageFont, ImageDraw, Image
from module.config.utils import read_file
from module.logger import logger
from module.base.utils import get_bbox_reversed,crop
import inspect
from tasks.relics.keywords import relics as relics_module
class TextImageGenerator:
def __init__(self, keyword ,font_path="./dev_tools/zh-cn.ttf", font_size=20):
self.font = ImageFont.truetype(font_path, font_size)
self.keyword=keyword
@staticmethod
def split_string_at_last_space(input_string):
if all(ord(char) < 128 for char in input_string) and len(input_string) > 35:
last_space_index = input_string.rfind(' ')
if last_space_index == -1:
return input_string, ""
part1 = input_string[:last_space_index]
part2 = input_string[last_space_index + 1:]
return part1
else:
return input_string
def text_image_generator(self, chars, names, font, output_path='./'):
for char, name in zip(chars, names):
image_path = os.path.join(output_path, name + '.png')
part = self.split_string_at_last_space(char)
image = np.ones((50, 370), dtype=np.uint8) * 255
image_pil = Image.fromarray(image)
draw = ImageDraw.Draw(image_pil)
draw.text((2, 0.5), part, font=font, fill=0)
image = np.array(image_pil)
crop_image = crop(image, get_bbox_reversed(image, 70))
image_pil = Image.fromarray(crop_image)
image_pil.save(image_path)
logger.info(f'{name} generated')
def delete_files(self,folder_path):
with os.scandir(folder_path) as entries:
for entry in entries:
if entry.is_file():
os.remove(entry.path)
logger.info(f'{entry.name} is cleaned')
def relics_name_image_generator(self, output_path ,file_module):
self.delete_files(output_path)
content = inspect.getsource(file_module)
text_patten= re.compile(r'' + self.keyword + r"='([^']*)'")
name_pattern = re.compile(r"name='([^']*)'")
text_values = text_patten.findall(content)
name_values = name_pattern.findall(content)
self.text_image_generator(text_values, name_values, font=self.font, output_path=output_path)
if __name__ == '__main__':
TextImageGenerator("cn").relics_name_image_generator(output_path="./assets/cn/relics/name/",file_module=relics_module)
TextImageGenerator("en").relics_name_image_generator(output_path="./assets/en/relics/name/",file_module=relics_module)

View File

@ -0,0 +1,10 @@
from dataclasses import dataclass
from typing import ClassVar
from module.ocr.keyword import Keyword
@dataclass(repr=False)
class RelicSet(Keyword):
instances: ClassVar = {}
dungeon_id: int
plane_id: int

View File

@ -0,0 +1,423 @@
from .classes import RelicSet
# This file was auto-generated, do not modify it manually. To generate:
# ``` python -m dev_tools.keyword_extract ```
Passerby_of_Wandering_Cloud = RelicSet(
id=1,
name='Passerby_of_Wandering_Cloud',
cn='云无留迹的过客',
cht='雲無留跡的過客',
en='Passerby of Wandering Cloud',
jp='流雲無痕の過客',
es='Transeúnte de la nube pasajera',
plane_id=1203,
dungeon_id=2013201,
)
Musketeer_of_Wild_Wheat = RelicSet(
id=2,
name='Musketeer_of_Wild_Wheat',
cn='野穗伴行的快枪手',
cht='野穗伴行的快槍手',
en='Musketeer of Wild Wheat',
jp='草の穂ガンマン',
es='Pistolera de la espiga silvestre',
plane_id=1203,
dungeon_id=2013201,
)
Knight_of_Purity_Palace = RelicSet(
id=3,
name='Knight_of_Purity_Palace',
cn='净庭教宗的圣骑士',
cht='淨庭教宗的聖騎士',
en='Knight of Purity Palace',
jp='純庭教会の聖騎士',
es='Paladina de la Iglesia de la Corte Inmaculada',
plane_id=1205,
dungeon_id=2021101,
)
Hunter_of_Glacial_Forest = RelicSet(
id=4,
name='Hunter_of_Glacial_Forest',
cn='密林卧雪的猎人',
cht='密林臥雪的獵人',
en='Hunter of Glacial Forest',
jp='雪の密林の狩人',
es='Cazador del bosque glacial',
plane_id=1201,
dungeon_id=2000201,
)
Champion_of_Streetwise_Boxing = RelicSet(
id=5,
name='Champion_of_Streetwise_Boxing',
cn='街头出身的拳王',
cht='街頭出身的拳王',
en='Champion of Streetwise Boxing',
jp='成り上がりチャンピオン',
es='Campeona de boxeo callejero',
plane_id=1202,
dungeon_id=2013101,
)
Guard_of_Wuthering_Snow = RelicSet(
id=6,
name='Guard_of_Wuthering_Snow',
cn='戍卫风雪的铁卫',
cht='戍衛風雪的鐵衛',
en='Guard of Wuthering Snow',
jp='吹雪と対峙する兵士',
es='Guardia de la nieve borrascosa',
plane_id=1204,
dungeon_id=2013401,
)
Firesmith_of_Lava_Forging = RelicSet(
id=7,
name='Firesmith_of_Lava_Forging',
cn='熔岩锻铸的火匠',
cht='熔岩鍛鑄的火匠',
en='Firesmith of Lava-Forging',
jp='溶岩で鍛造する火匠',
es='Forjador de lava',
plane_id=1206,
dungeon_id=2021201,
)
Genius_of_Brilliant_Stars = RelicSet(
id=8,
name='Genius_of_Brilliant_Stars',
cn='繁星璀璨的天才',
cht='繁星璀璨的天才',
en='Genius of Brilliant Stars',
jp='星の如く輝く天才',
es='Genio de las estrellas relucientes',
plane_id=1204,
dungeon_id=2013401,
)
Band_of_Sizzling_Thunder = RelicSet(
id=9,
name='Band_of_Sizzling_Thunder',
cn='激奏雷电的乐队',
cht='激奏雷電的樂團',
en='Band of Sizzling Thunder',
jp='雷鳴轟くバンド',
es='Banda del trueno crepitante',
plane_id=1205,
dungeon_id=2021101,
)
Eagle_of_Twilight_Line = RelicSet(
id=10,
name='Eagle_of_Twilight_Line',
cn='晨昏交界的翔鹰',
cht='晨昏交界的翔鷹',
en='Eagle of Twilight Line',
jp='昼夜の狭間を翔ける鷹',
es='Águila del crepúsculo',
plane_id=1201,
dungeon_id=2000201,
)
Thief_of_Shooting_Meteor = RelicSet(
id=11,
name='Thief_of_Shooting_Meteor',
cn='流星追迹的怪盗',
cht='流星追跡的怪盜',
en='Thief of Shooting Meteor',
jp='流星の跡を追う怪盗',
es='Ladrón del rastro meteórico',
plane_id=1202,
dungeon_id=2013101,
)
Wastelander_of_Banditry_Desert = RelicSet(
id=12,
name='Wastelander_of_Banditry_Desert',
cn='盗匪荒漠的废土客',
cht='盜匪荒漠的廢土客',
en='Wastelander of Banditry Desert',
jp='荒地で盗みを働く廃土客',
es='Habitante del yermo de los bandidos',
plane_id=1206,
dungeon_id=2021201,
)
Longevous_Disciple = RelicSet(
id=13,
name='Longevous_Disciple',
cn='宝命长存的莳者',
cht='寶命長存的蒔者',
en='Longevous Disciple',
jp='宝命長存の蒔者',
es='Discípula longeva',
plane_id=1207,
dungeon_id=2023101,
)
Messenger_Traversing_Hackerspace = RelicSet(
id=14,
name='Messenger_Traversing_Hackerspace',
cn='骇域漫游的信使',
cht='駭域漫遊的信使',
en='Messenger Traversing Hackerspace',
jp='仮想空間を漫遊するメッセンジャー',
es='Mensajero del espacio hackeado',
plane_id=1207,
dungeon_id=2023101,
)
The_Ashblazing_Grand_Duke = RelicSet(
id=15,
name='The_Ashblazing_Grand_Duke',
cn='毁烬焚骨的大公',
cht='毀燼焚骨的大公',
en='The Ashblazing Grand Duke',
jp='灰燼を燃やし尽くす大公',
es='Gran duque incinerador',
plane_id=1208,
dungeon_id=2022301,
)
Prisoner_in_Deep_Confinement = RelicSet(
id=16,
name='Prisoner_in_Deep_Confinement',
cn='幽锁深牢的系囚',
cht='幽鎖深牢的繫囚',
en='Prisoner in Deep Confinement',
jp='深い牢獄の囚人',
es='Prisionero aislado',
plane_id=1208,
dungeon_id=2022301,
)
Pioneer_Diver_of_Dead_Waters = RelicSet(
id=17,
name='Pioneer_Diver_of_Dead_Waters',
cn='死水深潜的先驱',
cht='死水深潛的先驅',
en='Pioneer Diver of Dead Waters',
jp='死水に潜る先駆者',
es='Buceadora pionera del agua muerta',
plane_id=1209,
dungeon_id=2031101,
)
Watchmaker_Master_of_Dream_Machinations = RelicSet(
id=18,
name='Watchmaker_Master_of_Dream_Machinations',
cn='机心戏梦的钟表匠',
cht='機心戲夢的鐘錶匠',
en='Watchmaker, Master of Dream Machinations',
jp='夢を弄ぶ時計屋',
es='Relojero de maquinaciones oníricas',
plane_id=1209,
dungeon_id=2031101,
)
Iron_Cavalry_Against_the_Scourge = RelicSet(
id=19,
name='Iron_Cavalry_Against_the_Scourge',
cn='荡除蠹灾的铁骑',
cht='蕩除蠹災的鐵騎',
en='Iron Cavalry Against the Scourge',
jp='蝗害を一掃せし鉄騎',
es='Caballería de hierro plaguicida',
plane_id=1210,
dungeon_id=2033201,
)
The_Wind_Soaring_Valorous = RelicSet(
id=20,
name='The_Wind_Soaring_Valorous',
cn='风举云飞的勇烈',
cht='風舉雲飛的勇烈',
en='The Wind-Soaring Valorous',
jp='風雲を薙ぎ払う勇烈',
es='Intrépida cabalgavientos',
plane_id=1210,
dungeon_id=2033201,
)
Space_Sealing_Station = RelicSet(
id=21,
name='Space_Sealing_Station',
cn='太空封印站',
cht='太空封印站',
en='Space Sealing Station',
jp='宇宙封印ステーション',
es='Estación sellaespacios',
plane_id=1008,
dungeon_id=3,
)
Fleet_of_the_Ageless = RelicSet(
id=22,
name='Fleet_of_the_Ageless',
cn='不老者的仙舟',
cht='不老者的仙舟',
en='Fleet of the Ageless',
jp='老いぬ者の仙舟',
es='Flota de los eternos',
plane_id=1008,
dungeon_id=3,
)
Pan_Cosmic_Commercial_Enterprise = RelicSet(
id=23,
name='Pan_Cosmic_Commercial_Enterprise',
cn='泛银河商业公司',
cht='泛銀河商業公司',
en='Pan-Cosmic Commercial Enterprise',
jp='汎銀河商事会社',
es='Entidad comercial pangaláctica',
plane_id=1008,
dungeon_id=3,
)
Belobog_of_the_Architects = RelicSet(
id=24,
name='Belobog_of_the_Architects',
cn='筑城者的贝洛伯格',
cht='築城者的貝洛伯格',
en='Belobog of the Architects',
jp='建創者のベロブルグ',
es='La Belobog de los Arquitectos',
plane_id=1008,
dungeon_id=3,
)
Celestial_Differentiator = RelicSet(
id=25,
name='Celestial_Differentiator',
cn='星体差分机',
cht='星體差分機',
en='Celestial Differentiator',
jp='天体階差機関',
es='Diferenciador celestial',
plane_id=1008,
dungeon_id=3,
)
Inert_Salsotto = RelicSet(
id=26,
name='Inert_Salsotto',
cn='停转的萨尔索图',
cht='停轉的薩爾索圖',
en='Inert Salsotto',
jp='自転が止まったサルソット',
es='Salsotto inerte',
plane_id=1008,
dungeon_id=3,
)
Talia_Kingdom_of_Banditry = RelicSet(
id=27,
name='Talia_Kingdom_of_Banditry',
cn='盗贼公国塔利亚',
cht='盜賊公國塔利亞',
en='Talia: Kingdom of Banditry',
jp='盗賊公国タリア',
es='Talia, paraíso de los forajidos',
plane_id=1008,
dungeon_id=3,
)
Sprightly_Vonwacq = RelicSet(
id=28,
name='Sprightly_Vonwacq',
cn='生命的翁瓦克',
cht='生命的翁瓦克',
en='Sprightly Vonwacq',
jp='生命のウェンワーク',
es='Vonwacq el vivaz',
plane_id=1008,
dungeon_id=3,
)
Rutilant_Arena = RelicSet(
id=29,
name='Rutilant_Arena',
cn='繁星竞技场',
cht='繁星競技場',
en='Rutilant Arena',
jp='星々の競技場',
es='Arena rutilante',
plane_id=1008,
dungeon_id=3,
)
Broken_Keel = RelicSet(
id=30,
name='Broken_Keel',
cn='折断的龙骨',
cht='折斷的龍骨',
en='Broken Keel',
jp='折れた竜骨',
es='Quilla rota',
plane_id=1008,
dungeon_id=3,
)
Firmament_Frontline_Glamoth = RelicSet(
id=31,
name='Firmament_Frontline_Glamoth',
cn='苍穹战线格拉默',
cht='蒼穹戰線格拉默',
en='Firmament Frontline: Glamoth',
jp='蒼穹戦線グラモス',
es='Glamoth, frente del firmamento',
plane_id=1008,
dungeon_id=3,
)
Penacony_Land_of_the_Dreams = RelicSet(
id=32,
name='Penacony_Land_of_the_Dreams',
cn='梦想之地匹诺康尼',
cht='夢想之地匹諾康尼',
en='Penacony, Land of the Dreams',
jp='夢の地ピノコニー',
es='Colonipenal, la tierra de los sueños',
plane_id=1008,
dungeon_id=3,
)
Sigonia_the_Unclaimed_Desolation = RelicSet(
id=33,
name='Sigonia_the_Unclaimed_Desolation',
cn='无主荒星茨冈尼亚',
cht='無主荒星茨岡尼亞',
en='Sigonia, the Unclaimed Desolation',
jp='荒涼の惑星ツガンニヤ',
es='Sigonia, desolación sin dueño',
plane_id=1008,
dungeon_id=3,
)
Izumo_Gensei_and_Takama_Divine_Realm = RelicSet(
id=34,
name='Izumo_Gensei_and_Takama_Divine_Realm',
cn='出云显世与高天神国',
cht='出雲顯世與高天神國',
en='Izumo Gensei and Takama Divine Realm',
jp='顕世の出雲と高天の神国',
es='Izumo gensei y reino divino de Takama',
plane_id=1008,
dungeon_id=3,
)
Duran_Dynasty_of_Running_Wolves = RelicSet(
id=35,
name='Duran_Dynasty_of_Running_Wolves',
cn='奔狼的都蓝王朝',
cht='奔狼的都藍王朝',
en='Duran, Dynasty of Running Wolves',
jp='奔狼の都藍王朝',
es='Duran, dinastía de lobos raudos',
plane_id=1008,
dungeon_id=3,
)
Forge_of_the_Kalpagni_Lantern = RelicSet(
id=36,
name='Forge_of_the_Kalpagni_Lantern',
cn='劫火莲灯铸炼宫',
cht='劫火蓮燈鑄煉宮',
en='Forge of the Kalpagni Lantern',
jp='劫火と蓮灯の鋳煉宮',
es='Fragua de la linterna Kalpagni',
plane_id=1008,
dungeon_id=3,
)
Lushaka_the_Sunken_Seas = RelicSet(
id=37,
name='Lushaka_the_Sunken_Seas',
cn='沉陆海域露莎卡',
cht='沉陸海域露莎卡',
en='Lushaka, the Sunken Seas',
jp='海に沈んだルサカ',
es='Lushaka, sumergido bajo el mar',
plane_id=1008,
dungeon_id=3,
)
The_Wondrous_BananAmusement_Park = RelicSet(
id=38,
name='The_Wondrous_BananAmusement_Park',
cn='奇想蕉乐园',
cht='奇想蕉樂園',
en='The Wondrous BananAmusement Park',
jp='奇想天外のバナダイス',
es='Parque de Platanolandia',
plane_id=1008,
dungeon_id=3,
)