feedback6 R21F: enemy animation states, the client part of PR #275 by @xcdoge re-implemented — the resolver gives an enemy every numbered skill clip (anims.skills; the caller's first index stays the primary, operators unchanged, 宴's PREFAB_SPINE_ROLES fix kept), the stun spellings Stun_1 and Dizzy_Begin/Loop/End, a separate run role (Run_Begin/Loop/End); the renderer walks an enemy faster than moveSpeed 1 on its Run cycle (猎狗pro, 深池侦察犬 ×2; [ASSUMED] threshold), swaps an enemy's skill clip on a cast event (UnitView.setSkillSlot; a form in force is kept), and plays the 重生 of 巨大的丑东西 (Revive, then the fleeing 大祭司 Idle_2 / Move_2 / Stun_2) and 自在 (Revive_01); data/assets.json regenerated offline: 18 enemies gain anims.skills, 6 anims.run, 3 a stun clip (巨大的丑东西, 斩胄之剑, 破胄之锤), nothing else; the sim's cast slot (a new event) is not part of it; golden: unchanged
This commit is contained in:
1 parent
14df10a5a3
commit
76a2db7dd0
11 files changed
+315
-19
No files matched your search
@@ -166,7 +166,8 @@ export function applyRoleFix(roles, fix, durations) {
|
||||
/**
|
||||
* Spine metadata of extracted models (findLocalEnemyModels / findLocalTokenModels), parsed like processModels does — but
|
||||
* read only: the atlas is sized / pma-normalized in memory (extract.py already writes it so), nothing on disk changes.
|
||||
* Roles are resolved for skill index 0, like the web enemy and token models, then LOCAL_SPINE_ROLES applied.
|
||||
* Roles are resolved for skill index 0 (an enemy also for its numbered skill clips), like the web enemy and token models,
|
||||
* then LOCAL_SPINE_ROLES applied.
|
||||
* @param {string} root absolute public/assets directory
|
||||
* @param {Record<string, { dir: string, skel: string, atlas: string, pngs: string[] }>} found
|
||||
* @returns {Promise<{ meta: Record<string, LocalSpineMeta>, problems: string[] }>}
|
||||
@@ -192,7 +193,7 @@ export async function localSpineMeta(root, found) {
|
||||
const sk = parseSkel(await readFile(join(root, m.skel)), info.regions);
|
||||
if (!sk.animations.length) throw new Error('skeleton has no animations');
|
||||
if (sk.missingRegions?.length) problems.push(`${id}: ${sk.missingRegions.length} attachment(s) not in atlas (e.g. ${sk.missingRegions[0]})`);
|
||||
const fixed = applyRoleFix(resolveRoles(sk.animations, { skillIndices: [0], durations: sk.durations }), LOCAL_SPINE_ROLES[id], sk.durations);
|
||||
const fixed = applyRoleFix(resolveRoles(sk.animations, { skillIndices: [0], numberedSkills: id.startsWith('enemy_'), durations: sk.durations }), LOCAL_SPINE_ROLES[id], sk.durations);
|
||||
if (fixed.missing.length) problems.push(`${id}: role fix not applied (clip missing) for ${fixed.missing.join(', ')}`);
|
||||
meta[id] = {
|
||||
skel: base(m.skel), atlas: base(m.atlas), textures: info.pages, pma: true,
|
||||
@@ -330,7 +331,9 @@ export async function processModels(models, { root, dl, cachePath, download = tr
|
||||
if (!sk.animations.length) { problems.push(`${m.key}: skeleton has no animations`); continue; }
|
||||
const key = String(m.key);
|
||||
const id = key.startsWith('enemy:') ? key.slice('enemy:'.length) : key.startsWith('op:') ? key.split(':')[1] : null; // op:<char>:front|back
|
||||
const fixed = applyRoleFix(resolveRoles(sk.animations, { skillIndices: m.skillIndices, durations: sk.durations }), id ? PREFAB_SPINE_ROLES[id] : undefined, sk.durations);
|
||||
// an enemy's numbered skill clips are resolved too (anims.skills: the clip of each skill slot it casts, PR #275);
|
||||
// operators keep the pool's indices (their equipped skill picks among them)
|
||||
const fixed = applyRoleFix(resolveRoles(sk.animations, { skillIndices: m.skillIndices, numberedSkills: key.startsWith('enemy:'), durations: sk.durations }), id ? PREFAB_SPINE_ROLES[id] : undefined, sk.durations);
|
||||
if (fixed.missing.length) problems.push(`${m.key}: role fix not applied (clip missing) for ${fixed.missing.join(', ')}`);
|
||||
const anims = fixed.roles;
|
||||
entries.set(m.key, {
|
||||
|
||||
Reference in new issue
Block a user