14 KiB
Animation Scene — Editor Tooling
This document tracks Editor-only tooling used with the runtime animation test workflow described in AnimationSceneSetup.md.
Scene docs (runtime hierarchy, managers, APIs): see Assets/PerfectWorld/Scripts/_Doc/AnimationSceneSetup.md.
How to extend this file: whenever you add or plan a new piece of Editor UI / automation for the animation scene, append a ### Feature block under Feature log using the Feature template below. Keep one feature per numbered section so history stays searchable.
Goals
| Goal | Notes |
|---|---|
| Faster iteration | Load and validate character models from Play Mode, driven by Editor menus where appropriate — no Edit Mode .ecm preview without a dedicated preview pipeline |
| Stable bootstrap | Respect the same prerequisites as runtime (NPCManager, elementdataman, CECPlayer.InitStaticRes(), etc.—see §Prerequisites below) |
| Traceability | Features and acceptance criteria live here before or while implementing the Editor scripts |
Suggested implementation locations (when you create them):
- Menu: e.g.
Tools / PerfectWorld / Animation Scene / … - Scripts: under
Assets/PerfectWorld/Scripts/Editor/(or project convention for Editor assemblies)
Prerequisites (runtime + Editor)
Anything the Editor tool drives must satisfy the same constraints as a Play Mode session:
| Prerequisite | Why |
|---|---|
AutoInitializer in the open scene |
Bootstraps IAutoInitialize types including ElementDataManProvider; runs EC_Game.Init(), SkillStubs.Init() |
elementdataman loaded |
CECPlayer.InitStaticRes() → BuildActionList() uses ElementDataManProvider.GetElementDataMan() |
CECPlayer.InitStaticRes() called once after element data is usable |
InitializePlayer does not register IAutoInitialize (interface commented); not invoked by CECGameRun.Init() alone. Normal login hits it via CECGameRun.InitCharacter. Animation scene tooling must arrange this explicitly if you rely on skill / action maps |
NPCManager in scene |
SetPlayerModel → NPCManager.Instance.GetModelPlayer(profession, gender) |
CECAttacksMan in scene |
PlayAttackEffect, SkillGfxMan.InstanceSub.Tick path (see AnimationSceneSetup.md §12) |
EC_ManMessageMono in scene |
SkillGfxMan resolves EC_ManMessageMono.Instance references |
CECHostPlayer reference (selection or serialized) |
await player.SetPlayerModel(byte profession, byte gender) is CECPlayer API; host implementation is CECHostPlayer |
InGameGraphicOption in scene (optional) |
EC_Game.InitSetting() adjusts render scale / MSAA via InGameGraphicOption. If omitted, MonoSingleton auto-creates a host component; InGameGraphicOption resolves URP from GraphicsSettings.defaultRenderPipeline. Fully custom scenes should still assign URP (+ optional Cinemachine) on InGameGraphicOption for predictable behavior. |
Editor caveat: CECHostPlayer.LoadResources uses UnityGameSession.Instance.GetRoleInfo(). For offline Editor-driven loads, prefer calling SetPlayerModel directly (and/or setting m_iProfession, m_iGender on the player instance as your tool requires) rather than invoking full InitCharacter unless session is mocked.
Feature log
Feature 1 — Editor / Play Mode: bootstrap player model
Status: Planned (spec captured here; implementation optional).
Problem: In the animation test scene you need a repeatable way to load the .ecm player model by profession and gender without going through the server login flow.
Proposed behavior:
- User opens the animation test scene (or any scene that contains the required managers + a
CECHostPlayerinstance). - Play Mode required for real
SetPlayerModel/ Addressables — Editor UI only queues work once Unity is playing (same constraint as Feature 2–3). - Tool or scene
MonoBehaviourexposesProfession/Gendermapped toCECPlayer.SetPlayerModel(byte, byte). - Sequence (recommended): wait until
elementdatamanload has succeeded →CECPlayer.InitStaticRes()once →await SetPlayerModel(profession, gender). - Success: visible
.ecmunderPlayerperparentModelrules (CECPlayer.SetPlayerModel— first child if present, else root); Console filterAnimSceneBootstrapshowsSetPlayerModelBEGIN/END when those logs exist.
Out of scope: Full InitCharacter / UnityGameSession parity unless explicitly mocked elsewhere.
Acceptance criteria:
- Model appears after bootstrap when
NPCManager, Addressables, and element data are healthy. - Failures are visible (
NPCManagernull,GetModelPlayernull,InvalidOperationExceptionfromSetPlayerModel). InitStaticReseither runs before skill/action-dependent tests or is intentionally skipped with a clear warning.
Primary APIs: CECPlayer.SetPlayerModel, CECPlayer.InitStaticRes — see AnimationSceneSetup.md §1, §10–11.
Feature 2 — Editor: trigger Play Action (animation probe)
Status: Planned.
Problem: Quickly verify CECPlayerActionController / Animancer wiring without hunting hotkeys or server-driven triggers.
Proposed behavior:
- Menu entry e.g.
Tools / PerfectWorld / Animation Scene / …opens a small EditorWindow (or equivalent). - Window active only in Play Mode; references
CECHostPlayer(object field or auto-find). - User enters
PLAYER_ACTION_TYPEindex (sameintasCECPlayer.PlayAction(int iAction, bool bRestart)—ACT_STAND = 0, etc.; seeCECPlayerenum). - Button Play action invokes
host.PlayAction(index, true)on the live instance.
Out of scope: Driving PlaySkillCastAction / PlayAttackEffect from this panel (those belong to combat/skill tooling or separate Feature entries).
Acceptance criteria:
- With model loaded and action maps built (
InitStaticRes),ACT_STAND/ACT_RUN-class actions behave like runtime calls. ACT_ATTACK_1..4may still refusePlayActionby design (CECPlayer.PlayActionWithConfigblocks normal melee slots — use documented skill APIs instead).
Primary API: CECPlayer.PlayAction(int iAction, bool bRestart) on CECHostPlayer.
Feature 3 — Offline host init: god stats + synthetic skills (below character level 80, human form)
Status: Planned.
Problem: OnMsgHstSkillData never runs offline, so m_aPtSkills / SkillWrapper stay empty — GetNormalSkill / cast checks cannot mirror a real character. You still want most combat skills usable for VFX/animation testing without shape-change prerequisites.
Design summary: After InitStaticRes and SetPlayerModel, synthesize a cmd_skill_data-equivalent payload in memory and apply the same conceptual pipeline as CECHostPlayer.OnMsgHstSkillData: ElementSkill.LoadSkillData → SkillWrapper.Instance.LoadData → instantiate CECSkill rows into m_aPtSkills / m_aPsSkills by skill type (positive vs passive/production/life). Optionally align m_iProfession / m_iGender with the loaded model before filtering.
Simulated character limits:
| Constraint | Intent |
|---|---|
| Player level ceiling below 80 | Treat maximum simulated level as 79 (or equivalent) when choosing skill rank: for each skill id, pick the highest rank whose SkillStub.GetRequiredLevel(skill) is ≤ that simulated level (exact comparison uses live Skill instance at each candidate rank). |
| Realm | Set m_RealmLevel (and any extend props you rely on) high enough so GetRequiredRealmLevel does not fail for included ranks. |
| SP / Mana / AP / Vigour / HP | Raise ROLEBASICPROP (iCurMP, iCurAP, iSP, iVigour, iCurHP, etc.) and matching ROLEEXTPROP caps (max_hp, max_mp, max_ap) so CheckSkillCastCondition resource checks succeed for typical casts. |
| Exclude transform-shape-only skills | ElementSkill.Condition tests (allow_forms & (1 << form_type)) where form_type comes from m_iShape high bits (FORM_MASK_HIGH). Base human m_iShape = 0 ⇒ form_type = 0 ⇒ skill must allow bit 0 in SkillStub.allow_forms. Exclude stubs where (allow_forms & 1) == 0 (human/base form disallowed). Also exclude stubs flagged restrict_change when they denote transformation-only restrictions in data. |
| Exclude combo-chain prerequisites | Skip stubs with combosk_preskill != 0 unless you also simulate combo state (CECComboSkillState). |
| Exclude item / ammo gated skills | Skip itemcost > 0 or arrowcost > 0 unless you populate inventory accordingly. |
| Exclude goblin line | Skip cls == 258. |
| Profession filter | Include stub.cls == playerProfession or cls == 255 (general skills). |
Caveats (document in tooltips):
restrict_weapons: skills may still return condition invalid weapon if no matching weapon sits inm_pEquipPack— either equip a dummy weapon per profession or accept skipped casts.cmd_skill_data.SKILL.id_skillis ashortinGPDataType: skill ids > 32767 cannot be represented; skip or warn.- Passive / prerequisite graphs are imperfectly simulated — goal is animation/VFX iteration, not authoritative balance.
Acceptance criteria:
GetPositiveSkillByID/GetNormalSkillresolve for a large subset of profession skills after injection.CheckSkillCastConditionreturns 0 for a sampled skill without shape-change, assuming weapon/item caveats addressed.- Transform-only skills (
allow_formsmissing human bit orrestrict_change) do not appear in the injected list.
Primary references: CECHostPlayer.OnMsgHstSkillData (CECHostPlayer.Skill.cs), ElementSkill.Condition, SkillStub.allow_forms, ROLEBASICPROP, SkillWrapper.
Feature 4 — AnimScenePlayerBootstrap inspector: play action + weapon slots (action_type index)
Status: Done.
Problem: Drive PlayAction and test weapon-mesh + action_weapon_suffix alignment without a separate EditorWindow; GetShowingWeaponType ignores attached meshes when m_uAttackType == DEFAULT_ACTION_TYPE, so animation tests must set m_uAttackType the same way as CECPlayer_Inventory.ShowEquipments (from WEAPON_SUB_TYPE.action_type).
Implemented behavior:
AnimScenePlayerBootstrapEditor(Play Mode): Play action (int+ Restart →CECHostPlayer.PlayAction), Re-apply active weapon slot.AnimScenePlayerBootstrap:AnimSceneWeaponSlot[15](rightHandModelPrefab/leftHandModelPrefabper rowi === action_type),activeWeaponActionTypeIndex,applyWeaponAfterModelLoad; afterSetPlayerModel,ApplyWeaponForActiveSlot()runs when enabled.CECPlayer.AnimSceneAttachWeaponPrefabs: clears_currentRightHandWeapon/_currentLeftHandWeapon, parents instances underHH_righthandweapon/HH_lefthandweapon(same asCECPlayer_Inventory.ShowEquipments), setsm_uAttackTypewhen any side attaches; empty slot →DEFAULT_ACTION_TYPEandAttachWeapon().
Primary API / hooks: CECPlayer.AnimSceneAttachWeaponPrefabs, AnimScenePlayerBootstrap.ApplyWeaponForActiveSlot, Assets/PerfectWorld/Scripts/Editor/AnimScenePlayerBootstrapEditor.cs
Feature 1 legacy API snippet (reference only)
Use when implementing Feature 1 bootstrap:
await player.SetPlayerModel((byte)profession, (byte)gender);
CECPlayer.InitStaticRes();
Related runtime doc sections: AnimationSceneSetup.md §1 (model loading), §9–11 (scene objects / init order).
Feature template (copy for Feature 4, 5, …)
Paste and fill whenever you scope a new Editor capability:
### Feature N — <short title>
**Status:** Planned | In progress | Done
**Problem:** <what pain this removes>
**Proposed behavior:**
1. <step>
2. <step>
**Out of scope:** <explicit non-goals>
**Acceptance criteria:**
- <testable criterion>
- <…>
**Primary API / hooks:** `<class.method or menu path>`
**Related docs / code paths:** `<links to markdown or scripts>`
Maintaining this doc
| When | Do |
|---|---|
| You start designing an Editor capability | Add a ### Feature N section with Status: Planned and acceptance criteria |
| You implement or change behavior | Update Status, Primary API, and point to concrete script paths under Assets/.../Editor/ |
| Behaviour diverges from runtime | Refresh Prerequisites and cross-check AnimationSceneSetup.md |
Play Mode — Bootstrap log tag [AnimSceneBootstrap]
Scripts log a shared prefix [AnimSceneBootstrap] so you can filter the Unity Console while verifying initialization order:
| Typical order | Location |
|---|---|
Scene Awake boot |
AutoInitializer: BEGIN → IAutoInitialize count → EC_Game.Init → SkillStubs.Init → END |
| Element data finished (async after above) | ElementDataManProvider: SUCCESS or FAILED after load_data |
| Attacks/GFX composers | CECAttacksMan: Awake → Start → SetupAttacksMan → optional GFX preload kick |
| Action/skill tables (when you call it) | CECPlayer.InitStaticRes: BEGIN / END |
SetPlayerModel also logs BEGIN / END with the same prefix when loading the player .ecm.
Filter: Console search AnimSceneBootstrap.