From 0e5897c33d33f44e77e3f1953c1a468e1d92380b Mon Sep 17 00:00:00 2001 From: Guan <821143943@qq.com> Date: Sun, 25 May 2025 07:13:05 +0800 Subject: [PATCH 01/17] fix(editor2): difficulty picker not showing the selected value --- src/components/editor2/InfoEditor.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/editor2/InfoEditor.tsx b/src/components/editor2/InfoEditor.tsx index 702b15ad..9ed1459e 100644 --- a/src/components/editor2/InfoEditor.tsx +++ b/src/components/editor2/InfoEditor.tsx @@ -120,6 +120,7 @@ export const InfoEditor = memo(({ className }: InfoEditorProps) => { > { edit((get, set, skip) => { setInfo((prev) => { From b71a8b2e3b096fe68aed5ce15e23787e7ca06d91 Mon Sep 17 00:00:00 2001 From: Guan <821143943@qq.com> Date: Sun, 25 May 2025 09:37:47 +0800 Subject: [PATCH 02/17] feat: sort professions by in-game order and use correct EN names --- scripts/shared.ts | 116 ++++++++++++-------- src/models/generated/operators.json | 162 ++++++++++++++-------------- 2 files changed, 154 insertions(+), 124 deletions(-) diff --git a/scripts/shared.ts b/scripts/shared.ts index ccaa6aa8..06d53798 100644 --- a/scripts/shared.ts +++ b/scripts/shared.ts @@ -62,15 +62,47 @@ const CHARACTER_BLOCKLIST = [ 'token_10012_rosmon_shield', // 迷迭香的战术装备:It's just not gonna be there. ] -const PROFESSION_NAMES = { - MEDIC: '医疗', - WARRIOR: '近卫', - SPECIAL: '特种', - SNIPER: '狙击', - PIONEER: '先锋', - TANK: '重装', - CASTER: '术师', - SUPPORT: '辅助', +const PROFESSIONS = { + PIONEER: { + name: '先锋', + name_en: 'Vanguard', + code: 512, + }, + WARRIOR: { + name: '近卫', + name_en: 'Guard', + code: 1, + }, + TANK: { + name: '重装', + name_en: 'Defender', + code: 4, + }, + SNIPER: { + name: '狙击', + name_en: 'Sniper', + code: 2, + }, + CASTER: { + name: '术师', + name_en: 'Caster', + code: 32, + }, + MEDIC: { + name: '医疗', + name_en: 'Medic', + code: 8, + }, + SUPPORT: { + name: '辅助', + name_en: 'Supporter', + code: 16, + }, + SPECIAL: { + name: '特种', + name_en: 'Specialist', + code: 64, + }, } async function json(url: string) { @@ -86,7 +118,11 @@ export async function getOperators() { json(UNIEQUIP_TABLE_JSON_URL_EN), ]) - const { subProfDict: subProfDictCN, equipDict } = uniequipTableCN + const { + subProfDict: subProfDictCN, + subProfToProfDict, + equipDict, + } = uniequipTableCN const { subProfDict: subProfDictEN } = uniequipTableEN const equipsByOperatorId = Object.values(equipDict).reduce( (acc: Record, equip: any) => { @@ -97,8 +133,34 @@ export async function getOperators() { {}, ) + const professions: Professions = Object.entries(PROFESSIONS).map( + ([id, { name, name_en, code }]) => { + const subProfessions = ( + Object.values(subProfDictCN) as { + subProfessionId: string + subProfessionName: string + subProfessionCatagory: number + }[] + ) + .filter((x) => subProfToProfDict[x.subProfessionId] === code) + .sort((a, b) => a.subProfessionCatagory - b.subProfessionCatagory) + .map(({ subProfessionId, subProfessionName }) => ({ + id: subProfessionId, + name: subProfessionName, + name_en: + subProfDictEN[subProfessionId]?.subProfessionName || + capitalize(subProfessionId), + })) + return { + id, + name, + name_en, + sub: subProfessions, + } + }, + ) + const opIds = Object.keys(charTableCN) - const professions: Professions = [] const result = uniqBy( opIds.flatMap((id) => { const op = charTableCN[id] @@ -106,38 +168,6 @@ export async function getOperators() { if (['TRAP'].includes(op.profession)) return [] - if (!['TOKEN'].includes(op.profession)) { - const prof = professions.find((p) => p.id === op.profession) - if (!prof) { - const enSubProfName = - subProfDictEN?.[op.subProfessionId]?.subProfessionName || - capitalize(op.subProfessionId) - - professions.push({ - id: op.profession, - name: PROFESSION_NAMES[op.profession], - name_en: - op.profession.charAt(0) + op.profession.slice(1).toLowerCase(), - sub: [ - { - id: op.subProfessionId, - name: subProfDictCN[op.subProfessionId].subProfessionName, - name_en: enSubProfName, - }, - ], - }) - } else if (!prof.sub.find((p) => p.id === op.subProfessionId)) { - const enSubProfName = - subProfDictEN?.[op.subProfessionId]?.subProfessionName || - capitalize(op.subProfessionId) - - prof.sub.push({ - id: op.subProfessionId, - name: subProfDictCN[op.subProfessionId].subProfessionName, - name_en: enSubProfName, - }) - } - } const modules = equipsByOperatorId[id] ?.sort((a, b) => a.charEquipOrder - b.charEquipOrder) .map(({ typeName1, typeName2 }) => { diff --git a/src/models/generated/operators.json b/src/models/generated/operators.json index a5c86804..740e2e73 100644 --- a/src/models/generated/operators.json +++ b/src/models/generated/operators.json @@ -4831,97 +4831,41 @@ ], "PROFESSIONS": [ { - "id": "MEDIC", - "name": "医疗", - "name_en": "Medic", + "id": "PIONEER", + "name": "先锋", + "name_en": "Vanguard", "sub": [ - { "id": "physician", "name": "医师", "name_en": "Medic" }, - { - "id": "ringhealer", - "name": "群愈师", - "name_en": "Multi-target Medic" - }, - { "id": "healer", "name": "疗养师", "name_en": "Therapist" }, - { "id": "wandermedic", "name": "行医", "name_en": "Wandering Medic" }, - { - "id": "incantationmedic", - "name": "咒愈师", - "name_en": "Incantation Medic" - }, - { "id": "chainhealer", "name": "链愈师", "name_en": "Chain Medic" } + { "id": "pioneer", "name": "尖兵", "name_en": "Pioneer" }, + { "id": "charger", "name": "冲锋手", "name_en": "Charger" }, + { "id": "tactician", "name": "战术家", "name_en": "Tactician" }, + { "id": "bearer", "name": "执旗手", "name_en": "Standard Bearer" }, + { "id": "agent", "name": "情报官", "name_en": "Agent" } ] }, { "id": "WARRIOR", "name": "近卫", - "name_en": "Warrior", + "name_en": "Guard", "sub": [ - { "id": "fearless", "name": "无畏者", "name_en": "Dreadnought" }, { "id": "centurion", "name": "强攻手", "name_en": "Centurion" }, + { "id": "fighter", "name": "斗士", "name_en": "Fighter" }, + { "id": "artsfghter", "name": "术战者", "name_en": "Arts Fighter" }, { "id": "instructor", "name": "教官", "name_en": "Instructor" }, { "id": "lord", "name": "领主", "name_en": "Lord" }, - { "id": "artsfghter", "name": "术战者", "name_en": "Arts Fighter" }, { "id": "sword", "name": "剑豪", "name_en": "Swordmaster" }, { "id": "musha", "name": "武者", "name_en": "Soloblade" }, - { "id": "crusher", "name": "重剑手", "name_en": "Crusher" }, + { "id": "fearless", "name": "无畏者", "name_en": "Dreadnought" }, { "id": "reaper", "name": "收割者", "name_en": "Reaper" }, { "id": "librator", "name": "解放者", "name_en": "Liberator" }, - { "id": "fighter", "name": "斗士", "name_en": "Fighter" }, + { "id": "crusher", "name": "重剑手", "name_en": "Crusher" }, { "id": "hammer", "name": "撼地者", "name_en": "Earthshaker" }, { "id": "primguard", "name": "本源近卫", "name_en": "Primguard" } ] }, - { - "id": "SPECIAL", - "name": "特种", - "name_en": "Special", - "sub": [ - { "id": "executor", "name": "处决者", "name_en": "Executor" }, - { "id": "merchant", "name": "行商", "name_en": "Merchant" }, - { "id": "hookmaster", "name": "钩索师", "name_en": "Hookmaster" }, - { "id": "stalker", "name": "伏击客", "name_en": "Ambusher" }, - { "id": "pusher", "name": "推击手", "name_en": "Push Stroker" }, - { "id": "dollkeeper", "name": "傀儡师", "name_en": "Dollkeeper" }, - { "id": "skywalker", "name": "巡空者", "name_en": "Skyranger" }, - { "id": "geek", "name": "怪杰", "name_en": "Geek" }, - { "id": "traper", "name": "陷阱师", "name_en": "Trapmaster" }, - { "id": "alchemist", "name": "炼金师", "name_en": "Alchemist" } - ] - }, - { - "id": "SNIPER", - "name": "狙击", - "name_en": "Sniper", - "sub": [ - { "id": "fastshot", "name": "速射手", "name_en": "Marksman" }, - { "id": "bombarder", "name": "投掷手", "name_en": "Flinger" }, - { "id": "aoesniper", "name": "炮手", "name_en": "Artilleryman" }, - { "id": "reaperrange", "name": "散射手", "name_en": "Spreadshooter" }, - { "id": "longrange", "name": "神射手", "name_en": "Deadeye" }, - { "id": "closerange", "name": "重射手", "name_en": "Heavyshooter" }, - { "id": "siegesniper", "name": "攻城手", "name_en": "Besieger" }, - { "id": "loopshooter", "name": "回环射手", "name_en": "Loopshooter" }, - { "id": "hunter", "name": "猎手", "name_en": "Hunter" } - ] - }, - { - "id": "SUPPORT", - "name": "辅助", - "name_en": "Support", - "sub": [ - { "id": "bard", "name": "吟游者", "name_en": "Bard" }, - { "id": "ritualist", "name": "巫役", "name_en": "Ritualist" }, - { "id": "slower", "name": "凝滞师", "name_en": "Decel Binder" }, - { "id": "summoner", "name": "召唤师", "name_en": "Summoner" }, - { "id": "craftsman", "name": "工匠", "name_en": "Artificer" }, - { "id": "underminer", "name": "削弱者", "name_en": "Hexer" }, - { "id": "blessing", "name": "护佑者", "name_en": "Abjurer" } - ] - }, { "id": "TANK", "name": "重装", - "name_en": "Tank", + "name_en": "Defender", "sub": [ { "id": "protector", "name": "铁卫", "name_en": "Protector" }, { "id": "guardian", "name": "守护者", "name_en": "Guardian" }, @@ -4931,13 +4875,13 @@ "name": "驭法铁卫", "name_en": "Arts Protector" }, + { "id": "duelist", "name": "决战者", "name_en": "Duelist" }, + { "id": "fortress", "name": "要塞", "name_en": "Fortress" }, { "id": "shotprotector", "name": "哨戒铁卫", "name_en": "Sentry Protector" }, - { "id": "fortress", "name": "要塞", "name_en": "Fortress" }, - { "id": "duelist", "name": "决战者", "name_en": "Duelist" }, { "id": "primprotector", "name": "本源铁卫", @@ -4946,15 +4890,19 @@ ] }, { - "id": "PIONEER", - "name": "先锋", - "name_en": "Pioneer", + "id": "SNIPER", + "name": "狙击", + "name_en": "Sniper", "sub": [ - { "id": "pioneer", "name": "尖兵", "name_en": "Pioneer" }, - { "id": "charger", "name": "冲锋手", "name_en": "Charger" }, - { "id": "bearer", "name": "执旗手", "name_en": "Standard Bearer" }, - { "id": "tactician", "name": "战术家", "name_en": "Tactician" }, - { "id": "agent", "name": "情报官", "name_en": "Agent" } + { "id": "fastshot", "name": "速射手", "name_en": "Marksman" }, + { "id": "closerange", "name": "重射手", "name_en": "Heavyshooter" }, + { "id": "aoesniper", "name": "炮手", "name_en": "Artilleryman" }, + { "id": "longrange", "name": "神射手", "name_en": "Deadeye" }, + { "id": "reaperrange", "name": "散射手", "name_en": "Spreadshooter" }, + { "id": "siegesniper", "name": "攻城手", "name_en": "Besieger" }, + { "id": "bombarder", "name": "投掷手", "name_en": "Flinger" }, + { "id": "hunter", "name": "猎手", "name_en": "Hunter" }, + { "id": "loopshooter", "name": "回环射手", "name_en": "Loopshooter" } ] }, { @@ -4969,13 +4917,65 @@ "name_en": "Splash Caster" }, { "id": "funnel", "name": "驭械术师", "name_en": "Mech-accord Caster" }, + { "id": "phalanx", "name": "阵法术师", "name_en": "Phalanx Caster" }, { "id": "mystic", "name": "秘术师", "name_en": "Mystic Caster" }, { "id": "chain", "name": "链术师", "name_en": "Chain Caster" }, - { "id": "phalanx", "name": "阵法术师", "name_en": "Phalanx Caster" }, { "id": "blastcaster", "name": "轰击术师", "name_en": "Blast Caster" }, { "id": "primcaster", "name": "本源术师", "name_en": "Primal Caster" }, { "id": "soulcaster", "name": "塑灵术师", "name_en": "Soulcaster" } ] + }, + { + "id": "MEDIC", + "name": "医疗", + "name_en": "Medic", + "sub": [ + { "id": "physician", "name": "医师", "name_en": "Medic" }, + { + "id": "ringhealer", + "name": "群愈师", + "name_en": "Multi-target Medic" + }, + { "id": "healer", "name": "疗养师", "name_en": "Therapist" }, + { "id": "wandermedic", "name": "行医", "name_en": "Wandering Medic" }, + { + "id": "incantationmedic", + "name": "咒愈师", + "name_en": "Incantation Medic" + }, + { "id": "chainhealer", "name": "链愈师", "name_en": "Chain Medic" } + ] + }, + { + "id": "SUPPORT", + "name": "辅助", + "name_en": "Supporter", + "sub": [ + { "id": "slower", "name": "凝滞师", "name_en": "Decel Binder" }, + { "id": "underminer", "name": "削弱者", "name_en": "Hexer" }, + { "id": "bard", "name": "吟游者", "name_en": "Bard" }, + { "id": "blessing", "name": "护佑者", "name_en": "Abjurer" }, + { "id": "summoner", "name": "召唤师", "name_en": "Summoner" }, + { "id": "craftsman", "name": "工匠", "name_en": "Artificer" }, + { "id": "ritualist", "name": "巫役", "name_en": "Ritualist" } + ] + }, + { + "id": "SPECIAL", + "name": "特种", + "name_en": "Specialist", + "sub": [ + { "id": "executor", "name": "处决者", "name_en": "Executor" }, + { "id": "pusher", "name": "推击手", "name_en": "Push Stroker" }, + { "id": "stalker", "name": "伏击客", "name_en": "Ambusher" }, + { "id": "hookmaster", "name": "钩索师", "name_en": "Hookmaster" }, + { "id": "geek", "name": "怪杰", "name_en": "Geek" }, + { "id": "merchant", "name": "行商", "name_en": "Merchant" }, + { "id": "traper", "name": "陷阱师", "name_en": "Trapmaster" }, + { "id": "dollkeeper", "name": "傀儡师", "name_en": "Dollkeeper" }, + { "id": "alchemist", "name": "炼金师", "name_en": "Alchemist" }, + { "id": "skywalker", "name": "巡空者", "name_en": "Skyranger" } + ] } ] } From b460f1601ef8f64ad43c2e8e241fd36f362c5f36 Mon Sep 17 00:00:00 2001 From: Guan <821143943@qq.com> Date: Sun, 25 May 2025 11:26:03 +0800 Subject: [PATCH 03/17] feat(editor2): UI improvements --- src/components/editor2/DifficultyPicker.tsx | 2 +- src/components/editor2/EditorToolbar.tsx | 2 ++ src/components/editor2/action/LevelMap.tsx | 8 ++++---- src/components/editor2/operator/OperatorItem.tsx | 2 +- src/styles/global.css | 8 +++++++- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/editor2/DifficultyPicker.tsx b/src/components/editor2/DifficultyPicker.tsx index cab118a8..41efd1d8 100644 --- a/src/components/editor2/DifficultyPicker.tsx +++ b/src/components/editor2/DifficultyPicker.tsx @@ -68,7 +68,7 @@ export const DifficultyPicker: FC = ({ }, [isValidLevel, value, onChange]) return ( -
+
{