Files
2026-08-18 16:13:07 +08:00

252 lines
9.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from api.core.Gzip import register_gzip_request
import json
from fastapi import APIRouter, Path, Query
from api.core.Response import response
from api.core.Redis import get_redis_info
from api.dp import RedisDep
from api.utils.skill_detail import SKILL_DETAIL_NORMALIZE_VERSION, normalize_skill_detail, skill_detail_for_level
from api.utils.openapi_data import OPENAPI_SKILLS_PATH, OPENAPI_SUMMARY_DIR, openapi_locale_path
from api.utils.skill_tree import (
SKILL_TREE_WITH_DESC_SPECIAL_VERSION,
filter_skill_tree_by_desc_special,
load_skill_tree_with_desc_special,
)
import re
from typing import Annotated
from api.types.open import (
JobInfoResponse,
SkillDataSummaryResponse,
SkillDetailResponse,
SkillsListResponse,
SearchSkillResponse,
)
import os
from core.character.adventure import get_adv_list
router = APIRouter()
register_gzip_request(router)
@router.get('/skills/', operation_id='skillsList', response_model=SearchSkillResponse)
def get_skills_list(
redis: RedisDep,
skillName: Annotated[str | None, Query(description='技能名称,支持模糊查询')] = None,
) -> SearchSkillResponse:
"""
根据技能名称,获取对应的技能列表信息
"""
key = 'openapi:skills'
def get_skills():
# This function should retrieve the skills list from the data source
# For now, we return a placeholder list
with OPENAPI_SKILLS_PATH.open(encoding='utf-8') as f:
skills_data = json.load(f)
return skills_data
skills_list = get_redis_info(redis, key, get_skills)
data = (
list(
filter(
lambda x: re.sub(r'\s+', '', skillName) in re.sub(r'\s+', '', x['skillName']),
skills_list,
)
)
if skillName
else skills_list
)
return response(data=data)
@router.get('/jobInfo/', operation_id='jobsInfo', response_model=JobInfoResponse)
def get_jobs_info(
redis: RedisDep,
jobName: Annotated[str, Query(..., description='职业名称,支持模糊查询')] = None,
) -> JobInfoResponse:
"""
根据职业名称,获取对应的职业转职信息
"""
adventure_info = get_redis_info(redis, 'dcalc:adventure', get_adv_list)
jobName = jobName.replace('(', '(').replace(')', ')')
result = []
for adv in adventure_info:
if '(男)' in jobName or '(女)' in jobName:
gender = jobName[-3:]
toSearch = jobName[:-3]
if gender not in adv.get('title', ''):
continue
matched_children = [child for child in adv.get('children', []) if (toSearch in child.get('title', '') or toSearch in child.get('name', ''))]
else:
matched_children = [child for child in adv.get('children', []) if jobName in child.get('title', '') or jobName in child.get('name', '')]
if matched_children:
parent = {k: v for k, v in adv.items() if k != 'children'}
for child in matched_children:
entry = parent.copy()
entry['child'] = child
result.append(
{
'jobId': entry.get('name', ''),
'jobName': entry.get('title', ''),
'jobGrowId': child.get('name', ''),
'jobGrowName': child.get('title', ''),
}
)
return response(data=result)
@router.get('/{jobId}/{jobGrowId}/skills/', operation_id='skillsByJob', response_model=SkillsListResponse)
def get_cn_skills_by_job(
redis: RedisDep,
jobId: Annotated[str, Path(..., description='职业')],
jobGrowId: Annotated[str, Path(..., description='转职')],
descSpecial: Annotated[str, Query(description='技能特殊功能')] = '',
) -> SkillsListResponse:
"""
获取职业技能列表,职业ID和转职ID可通过jobsInfo获取
Args:
jobId (str): 职业ID,必填参数
jobGrowId (str): 转职ID,必填参数
descSpecial (str, optional): 技能特殊功能,默认为'',可选参数,支持传入以下功能关键词以过滤技能列表:压制、无敌、追踪、聚集敌人、强控敌人
"""
key = f'openapi:{SKILL_TREE_WITH_DESC_SPECIAL_VERSION}:{jobId}:{jobGrowId}:skills'
def get_skills_by_job():
return load_skill_tree_with_desc_special(jobId, jobGrowId)
skills_list = get_redis_info(redis, key, get_skills_by_job)
return response(data=filter_skill_tree_by_desc_special(skills_list, descSpecial))
@router.get('/{jobId}/{jobGrowId}/{skillId}/', operation_id='skillDetail', response_model=SkillDetailResponse)
def get_cn_skill_info(
redis: RedisDep,
jobId: Annotated[str, Path(..., description='职业')],
jobGrowId: Annotated[str, Path(..., description='转职')],
skillId: Annotated[str, Path(..., description='技能')],
level: Annotated[int | None, Query(description='技能等级')] = None,
) -> SkillDetailResponse:
"""
获取技能详细信息
Args:
jobId (str): 职业ID,必填参数
jobGrowId (str): 转职ID,必填参数
skillId (str): 技能ID,必填参数
level (int, optional): 技能等级,默认为None
"""
skill_info = {}
key = f'openapi:{SKILL_DETAIL_NORMALIZE_VERSION}:{jobId}:{jobGrowId}:{skillId}'
try:
def get_skill_info():
# This function should retrieve the skill info based on job and jobGrow
# For now, we return a placeholder dictionary
with open(
openapi_locale_path('cn', jobId, jobGrowId, 'skillDetail', f'{skillId}.json'),
encoding='utf-8',
) as f:
skill_data = json.load(f)
return normalize_skill_detail(skill_data)
skill_info = get_redis_info(redis, key, get_skill_info)
skill_info = skill_detail_for_level(skill_info, level)
except FileNotFoundError:
return response(
code=404,
message=f'技能信息未找到: {jobId} {jobGrowId} {skillId}',
data=None,
)
return response(data=skill_info)
@router.get('/skillData/summary/', operation_id='skillDataSummary', response_model=SkillDataSummaryResponse)
def get_skill_data_summary(
redis: RedisDep,
job: Annotated[str, Query(description='职业')],
skills: Annotated[
str,
Query(
description='技能列表字符串,逗号拼接技能名称,不传递或者传递为空时,查询所有',
),
] = '',
weapons: Annotated[
str,
Query(
description='武器类型列表字符串,逗号拼接武器类型名称,不传递或者传递为空时,查询所有',
),
] = '',
) -> SkillDataSummaryResponse:
"""
获取技能数据汇总信息
Args:
job (str): 职业名称,必填参数
skills (str, optional): 技能列表字符串,逗号拼接技能名称,不传递或者传递为空时,查询所有技能,默认为''
weapons (str, optional): 武器类型列表字符串,逗号拼接武器类型名称,不传递或者传递为空时,查询所有武器类型,默认为''
Response:
{
"code": int,
"message": str,
"data": [
{
"技能名称": str,
"武器类型": str,
"职业": str,
"技能描述": str,
"技能等级": int,
"冷却时间": float,
"消耗": str,
"伤害": float,
# 已学等级
"learnedLevel": int | str,
"基础百分比": float | str,
"等效百分比": float | str,
"原始冷却": float | str,
"实际冷却": float | str,
"理论秒伤": float | str,
"SP": float | None | str,
# 所在等级
"unlockAtRoleLevel": str | None,
}
]
}
"""
job = job.replace('(', '(').replace(')', ')')
key = f'openapi:skillData:summary:{job}'
data = []
skills = skills.split(',') if skills else []
weapons = weapons.split(',') if weapons else []
try:
def get_skill_data_summary():
# This function should retrieve the skill data summary based on job
# For now, we return a placeholder dictionary
json_files = [f for f in os.listdir(OPENAPI_SUMMARY_DIR) if f.endswith('.json')]
res = []
for i in json_files:
if job in i:
k = re.search(r'^\d+(?:-\d+)?(.*?)_', i)
with (OPENAPI_SUMMARY_DIR / i).open(encoding='utf-8') as f:
skill_data = json.load(f)
weapon = i.split('_')[-1].replace('.json', '')
res.append({'weapon': weapon if weapon else '通用', 'skills': skill_data, 'job': k.group(1) if k else ''})
return res
job_summary = get_redis_info(redis, key, get_skill_data_summary)
for item in job_summary:
if len(weapons) == 0 or item['weapon'] in weapons:
items = list(filter(lambda x: x['技能名称'] in skills, item['skills'])) if len(skills) > 0 else item['skills']
for skill in items:
skill['武器类型'] = item['weapon']
skill['职业'] = item['job']
data.extend(items or [])
except FileNotFoundError as e:
print(f'File not found: {e}')
return response(data=[])
return response(data=data)