From 729e08046d64abc081487b3391b9ac8366733bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A5=BF=E7=93=9C=C2=B0?= Date: Fri, 12 Jun 2026 13:22:09 +0800 Subject: [PATCH] =?UTF-8?q?new:MCP=E5=8F=8Aopenapi=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=8A=80=E8=83=BD=E7=89=B9=E6=AE=8A=E5=B1=9E=E6=80=A7=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/core/RedisPreheat.py | 5 +-- backend/api/routes/openapi.py | 19 +++++++----- backend/api/types/open.py | 2 ++ backend/api/utils/skill_tree.py | 39 ++++++++++++++++++++++++ backend/go/internal/httpserver/router.go | 6 +++- backend/go/internal/service/openapi.go | 33 ++++++++++++++++++-- backend/openapi | 2 +- 7 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 backend/api/utils/skill_tree.py diff --git a/backend/api/core/RedisPreheat.py b/backend/api/core/RedisPreheat.py index 3c1b7f8a..f37220ea 100644 --- a/backend/api/core/RedisPreheat.py +++ b/backend/api/core/RedisPreheat.py @@ -8,6 +8,7 @@ import redis from api.core.Gzip import gzip_zip from api.utils.skill_detail import SKILL_DETAIL_NORMALIZE_VERSION, normalize_skill_detail +from api.utils.skill_tree import SKILL_TREE_WITH_DESC_SPECIAL_VERSION, load_skill_tree_with_desc_special from core.basic.character import createCharacter from core.basic.equipment import get_equipment from core.character.adventure import adv, get_adv_list @@ -146,8 +147,8 @@ def _build_skill_tree_preheat_tasks() -> list[PreheatTask]: job_grow_id = relative.parts[1] tasks.append( ( - f'openapi:{job_id}:{job_grow_id}:skills', - lambda path=path: json.loads(path.read_text(encoding='utf-8')), + f'openapi:{SKILL_TREE_WITH_DESC_SPECIAL_VERSION}:{job_id}:{job_grow_id}:skills', + lambda job_id=job_id, job_grow_id=job_grow_id: load_skill_tree_with_desc_special(job_id, job_grow_id), ) ) return tasks diff --git a/backend/api/routes/openapi.py b/backend/api/routes/openapi.py index 275b6c50..8abcc711 100644 --- a/backend/api/routes/openapi.py +++ b/backend/api/routes/openapi.py @@ -5,6 +5,11 @@ 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.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 @@ -89,25 +94,23 @@ async 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:{jobId}:{jobGrowId}:skills' + key = f'openapi:{SKILL_TREE_WITH_DESC_SPECIAL_VERSION}:{jobId}:{jobGrowId}:skills' def get_skills_by_job(): - # This function should retrieve the skills by job and jobGrow - # For now, we return a placeholder list - with open(f'./openapi/data/{jobId}/{jobGrowId}/cn/skill_tree.json', encoding='utf-8') as f: - skills_data = json.load(f) - return skills_data + return load_skill_tree_with_desc_special(jobId, jobGrowId) skills_list = get_redis_info(redis, key, get_skills_by_job) - return response(data=skills_list) + return response(data=filter_skill_tree_by_desc_special(skills_list, descSpecial)) @router.get('/{jobId}/{jobGrowId}/{skillId}/', operation_id='skillDetail', response_model=SkillDetailResponse) diff --git a/backend/api/types/open.py b/backend/api/types/open.py index 72d8d7c1..2b4a40cc 100644 --- a/backend/api/types/open.py +++ b/backend/api/types/open.py @@ -140,6 +140,8 @@ class SkillListItem(BaseModel): """学习等级""" type: SkillType = Field(..., description='技能类型') """技能类型""" + descSpecial: list[str] | None = Field(None, description='特殊功能') + """特殊功能""" class SkillSummaryItem(BaseModel): diff --git a/backend/api/utils/skill_tree.py b/backend/api/utils/skill_tree.py new file mode 100644 index 00000000..5f801ba5 --- /dev/null +++ b/backend/api/utils/skill_tree.py @@ -0,0 +1,39 @@ +import json +from pathlib import Path + +from database.connect import BACKEND_DIR + + +SKILL_TREE_WITH_DESC_SPECIAL_VERSION = 'skillTreeWithDescSpecial:v1' + + +def load_skill_tree_with_desc_special(job_id: str, job_grow_id: str) -> list[dict]: + skill_tree_path = BACKEND_DIR / 'openapi' / 'data' / job_id / job_grow_id / 'cn' / 'skill_tree.json' + detail_dir = skill_tree_path.parent / 'skillDetail' + + with skill_tree_path.open(encoding='utf-8') as file: + skills_data = json.load(file) + + for skill in skills_data: + skill_id = skill.get('skillId') + desc_special = None + if skill_id: + detail_path = detail_dir / f'{skill_id}.json' + if detail_path.exists(): + with detail_path.open(encoding='utf-8') as file: + desc_special = json.load(file).get('descSpecial') + skill['descSpecial'] = desc_special + + return skills_data + + +def filter_skill_tree_by_desc_special(skills_data: list[dict], desc_special: str) -> list[dict]: + if not desc_special: + return skills_data + print(f'Filtering skills by descSpecial: {desc_special}') + print(skills_data) + return [ + skill + for skill in skills_data + if any(desc_special in item for item in (skill.get('descSpecial') or [])) + ] diff --git a/backend/go/internal/httpserver/router.go b/backend/go/internal/httpserver/router.go index 22312201..37f4bf6e 100644 --- a/backend/go/internal/httpserver/router.go +++ b/backend/go/internal/httpserver/router.go @@ -213,7 +213,11 @@ func NewRouter(dep Dependencies) http.Handler { }) r.Get("/{jobId}/{jobGrowId}/skills/", func(w http.ResponseWriter, r *http.Request) { - data, err := dep.OpenAPIService.SkillsByJob(chi.URLParam(r, "jobId"), chi.URLParam(r, "jobGrowId")) + data, err := dep.OpenAPIService.SkillsByJob( + chi.URLParam(r, "jobId"), + chi.URLParam(r, "jobGrowId"), + r.URL.Query().Get("descSpecial"), + ) if err != nil { writeError(w, http.StatusNotFound, err) return diff --git a/backend/go/internal/service/openapi.go b/backend/go/internal/service/openapi.go index 3db1a75b..ea42cd82 100644 --- a/backend/go/internal/service/openapi.go +++ b/backend/go/internal/service/openapi.go @@ -68,18 +68,45 @@ func (s *OpenAPIService) JobsInfo(jobName string) ([]map[string]string, error) { return result, nil } -func (s *OpenAPIService) SkillsByJob(jobID string, jobGrowID string) (any, error) { +func (s *OpenAPIService) SkillsByJob(jobID string, jobGrowID string, descSpecial string) (any, error) { jobDir, jobGrowDir, err := s.adventure.ResolveDirectories(jobID, jobGrowID) if err != nil { return nil, err } - var data any + var data []map[string]any path := filepath.Join(s.projectRoot, "openapi", "data", jobDir, jobGrowDir, "cn", "skill_tree.json") if err := s.readJSON(path, &data); err != nil { return nil, err } - return data, nil + detailDir := filepath.Join(s.projectRoot, "openapi", "data", jobDir, jobGrowDir, "cn", "skillDetail") + for _, skill := range data { + skillID, _ := skill["skillId"].(string) + var detail map[string]any + if skillID != "" { + err := s.readJSON(filepath.Join(detailDir, skillID+".json"), &detail) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + } + skill["descSpecial"] = detail["descSpecial"] + } + if descSpecial == "" { + return data, nil + } + + filtered := make([]map[string]any, 0) + for _, skill := range data { + items, _ := skill["descSpecial"].([]any) + for _, item := range items { + text, _ := item.(string) + if strings.Contains(text, descSpecial) { + filtered = append(filtered, skill) + break + } + } + } + return filtered, nil } func (s *OpenAPIService) SkillDetail(jobID string, jobGrowID string, skillID string, level *int) (any, error) { diff --git a/backend/openapi b/backend/openapi index 221e8171..6ad19358 160000 --- a/backend/openapi +++ b/backend/openapi @@ -1 +1 @@ -Subproject commit 221e81715a799c4ad79694db8f2106fa88455342 +Subproject commit 6ad19358139e19b42e8773f8aacffc3caf196619