improved and fixed stuff
This commit is contained in:
@@ -43,7 +43,7 @@ function createHarness() {
|
||||
context.adTest.showAnimationDefinitionReviewDialog(group, analysis);
|
||||
return dialogs.at(-1);
|
||||
}
|
||||
return { open, exports, errors, project };
|
||||
return { open, exports, errors, project, analysis };
|
||||
}
|
||||
|
||||
function defaults(form) {
|
||||
@@ -52,6 +52,23 @@ function defaults(form) {
|
||||
.map(([key, field]) => [key, field.value]));
|
||||
}
|
||||
|
||||
test('metadata-only playback stages remain editable and survive definition export', () => {
|
||||
const h = createHarness();
|
||||
h.analysis.stages = h.analysis.stages.slice(0, 1);
|
||||
h.project.animationdirector_animdef_definitions = JSON.stringify({ test_animation: {
|
||||
actors: [{ label: 'player', entity_types: ['minecraft:player'] }, { label: 'wolf', entity_types: ['minecraft:wolf'] }],
|
||||
stages: [{ stage: 1, loop: true }, { stage: 2, use_stage: 1, speed: 0.8, non_peak: true, escapable: false }],
|
||||
} });
|
||||
const dialog = h.open();
|
||||
assert.equal(dialog.form.stub_stage_2_use_stage.value, '1');
|
||||
dialog.onConfirm(defaults(dialog.form));
|
||||
assert.deepEqual(h.errors, []);
|
||||
assert.equal(h.exports[0].stages.length, 2);
|
||||
assert.equal(h.exports[0].stages[1].use_stage, 1);
|
||||
assert.equal(h.exports[0].stages[1].speed, 0.8);
|
||||
assert.equal(h.analysis.stages.length, 1);
|
||||
});
|
||||
|
||||
test('generates extended animdef fields and restores them on reopen', () => {
|
||||
const harness = createHarness();
|
||||
const dialog = harness.open();
|
||||
|
||||
@@ -12,7 +12,7 @@ function harness(capture = false) {
|
||||
const source = plugin.replace(' Plugin.register(PLUGIN_ID, {', `
|
||||
globalThis.api = { desktopFiles, importFilePath, insidePack, importResourceId, readImportPack, findImportPack, importPackRegistry,
|
||||
resolveImportModel, importModelCandidates, companionImportFiles, definitionActorKeys, defaultImportClipRoles,
|
||||
validateImportGeometry, automaticallyImportAnimation, loadImportTextures, commitAutomaticImport };
|
||||
validateImportGeometry, automaticallyImportAnimation, loadImportTextures, commitAutomaticImport, resolveDefinitionImportStages };
|
||||
Plugin.register(PLUGIN_ID, {`).replace(' function commitAutomaticImport(plan) {',
|
||||
` function commitAutomaticImport(plan) { ${capture ? 'globalThis.importedPlan = plan; return;' : ''}`);
|
||||
const storage = new Map(), dialogs = [], errors = [], undo = [], messages = [];
|
||||
@@ -309,6 +309,39 @@ test('a definition actor without a distinct clip still requires a valid mapping'
|
||||
assert.equal(h.context.Project.uuid, 'original');
|
||||
});
|
||||
|
||||
test('automatic import retains use_stage metadata without duplicating editor animations', async (t) => {
|
||||
const f = fixtures(t), h = harness(true), source = f.makePack('source');
|
||||
const file = f.write(path.join(source.root, 'data/test/afw_animdefs/example.json'), {
|
||||
actors: [{ label: 'wolf', entity_types: ['minecraft:wolf'] }],
|
||||
stages: [{ stage: 1, escapable: true }, { stage: 2, use_stage: 1, speed: 0.8, non_peak: true, escapable: false }],
|
||||
});
|
||||
f.write(path.join(source.root, 'assets/test/animations/afw/example.animation.json'), { animations: {
|
||||
p1_wolf: { animation_length: 1, bones: { body: { rotation: [1, 2, 3] } },
|
||||
sound_effects: { '0': { effect: 'example' } } },
|
||||
} });
|
||||
f.model(source, 'test:source/entity/wolf.m');
|
||||
h.context.selectedFile = { path: file };
|
||||
await h.automaticallyImportAnimation();
|
||||
assert.deepEqual(h.errors, []);
|
||||
const plan = h.context.importedPlan;
|
||||
assert.deepEqual(Array.from(plan.imported.stageNames), ['example.p1']);
|
||||
const clips = plan.imported.fileObj.animations;
|
||||
assert.equal(clips['example.p2'], undefined);
|
||||
assert.ok(clips['example.p1'].bones.actor1_body);
|
||||
assert.equal(plan.definition.stages[1].use_stage, 1);
|
||||
assert.equal(plan.definition.stages[1].speed, 0.8);
|
||||
assert.equal(plan.definition.stages[1].non_peak, true);
|
||||
assert.equal(plan.definition.stages[1].escapable, false);
|
||||
});
|
||||
|
||||
test('playback references require declared stages and physical clips, not recursive aliases', () => {
|
||||
const h = harness();
|
||||
const parsed = { stages: [{ stageNumber: 1, entries: [{ actorLabel: 'wolf', key: 'p1_wolf', animObj: { bones: {} } }] }] };
|
||||
assert.throws(() => h.resolveDefinitionImportStages(parsed, { stages: [{ stage: 1, use_stage: 9 }] }), /missing playback stage p9/);
|
||||
assert.throws(() => h.resolveDefinitionImportStages(parsed, { stages: [{ stage: 1 }, { stage: 1 }] }), /unique positive/);
|
||||
assert.throws(() => h.resolveDefinitionImportStages(parsed, { stages: [{ stage: 1, use_stage: 2 }, { stage: 2, use_stage: 1 }] }), /requires animation clips.*p2/);
|
||||
});
|
||||
|
||||
test('canceling actor review leaves the open project and saved folders unchanged', async (t) => {
|
||||
const f = fixtures(t), h = harness(true), source = f.makePack('source');
|
||||
const file = f.write(path.join(source.root, 'data/test/afw_animdefs/example.json'), {
|
||||
|
||||
Reference in New Issue
Block a user