From b6bedaf41edab47627b85d7d69d7d1185ec41cc7 Mon Sep 17 00:00:00 2001 From: L1Z0 <2grif484d@mozmail.com> Date: Thu, 1 Oct 2026 21:39:11 +0200 Subject: [PATCH] fixed clip lengths not syncing --- AnimationDirector.js | 21 ++++++++++++++------- test/animdef-generator.test.js | 13 +++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/AnimationDirector.js b/AnimationDirector.js index 4d8635d..3161bcd 100644 --- a/AnimationDirector.js +++ b/AnimationDirector.js @@ -3612,10 +3612,14 @@ return actor; } - function readStageDefinitionFromForm(result, stage, isLastStage) { + function readStageDefinitionFromForm(result, stage, isLastStage, syncCycleSeconds = true) { const base = `stub_stage_${stage.stageNumber}`; const loop = !!result?.[`${base}_loop`]; - const cycleSeconds = parseRequiredPositiveNumber(result?.[`${base}_cycle_seconds`], `Stage p${stage.stageNumber} cycle seconds`); + // Newly created definitions follow the authored GeckoLib clip length. Imported + // definitions may retain their explicitly authored cycle_seconds metadata. + const cycleSeconds = syncCycleSeconds + ? parseRequiredPositiveNumber(stage.cycleSeconds, `Stage p${stage.stageNumber} cycle seconds`) + : parseRequiredPositiveNumber(result?.[`${base}_cycle_seconds`], `Stage p${stage.stageNumber} cycle seconds`); const speed = parseOptionalNumber(result?.[`${base}_speed`], `Stage p${stage.stageNumber} speed`, (value) => value > 0); const midpointOffset = parseOptionalNumber( loop ? result?.[`${base}_midpoint_offset`] : '', @@ -3829,7 +3833,7 @@ if (props.warnings.length) Blockbench.showQuickMessage(`Item props: ${props.warnings.join(' ')}`, 6000); void refreshPropPreviews(true); if (blockRequirementPanel?.vue) blockRequirementPanel.vue.load(group.id); - showAnimationDefinitionReviewDialog(group, analysis); + showAnimationDefinitionReviewDialog(group, analysis, { syncCycleSeconds: false }); } function importAnimationDefinition() { @@ -3867,7 +3871,8 @@ }); } - function showAnimationDefinitionReviewDialog(group, analysis) { + function showAnimationDefinitionReviewDialog(group, analysis, options = {}) { + const syncCycleSeconds = options.syncCycleSeconds !== false; const savedMetadata = getProjectActorAnimdefMetadata(); const saved = getSavedAnimdef(group.id); const savedActors = new Map((Array.isArray(saved.actors) ? saved.actors : []).map((actor) => [actor.label, actor])); @@ -4137,10 +4142,12 @@ form[`${base}_cycle_seconds`] = { label: 'Cycle seconds', type: 'number', - value: savedStage.cycle_seconds ?? stage.cycleSeconds, + value: syncCycleSeconds ? stage.cycleSeconds : savedStage.cycle_seconds ?? stage.cycleSeconds, min: 0.001, step: 0.001, - description: 'Detected from the compiled GeckoLib animation_length.', + description: syncCycleSeconds + ? 'Automatically synced from the current compiled GeckoLib animation_length.' + : 'Imported from the animation definition.', }; form[`${base}_allow_join`] = { label: 'Allow joins', @@ -4230,7 +4237,7 @@ const stages = analysis.stages.map((stage, index) => ({ ...unmanagedAnimdefFields(savedStages.get(stage.stageNumber), STAGE_GENERATOR_KEYS), - ...readStageDefinitionFromForm(result, stage, index === analysis.stages.length - 1), + ...readStageDefinitionFromForm(result, stage, index === analysis.stages.length - 1, syncCycleSeconds), })); const actorsByLabel = new Map(actors.map((actor) => [actor.label, actor])); const explicitReceivers = actors.some((actor) => actor.receiver); diff --git a/test/animdef-generator.test.js b/test/animdef-generator.test.js index 69a7574..ce22cf4 100644 --- a/test/animdef-generator.test.js +++ b/test/animdef-generator.test.js @@ -167,6 +167,19 @@ test('Save retains definition fields in the project without exporting and restor assert.equal(h.exports[0].display_name, result.display_name); }); +test('cycle seconds always follow the current stage lengths', () => { + const h = createHarness(), dialog = h.open(), result = defaults(dialog.form); + result.stub_stage_1_cycle_seconds = 99; + result.stub_stage_2_cycle_seconds = 88; + h.setFormResult(result); + assert.equal(dialog.onConfirm(result), true); + assert.deepEqual(h.exports[0].stages.map((stage) => stage.cycle_seconds), [1, 2]); + + const reopened = h.open(); + assert.equal(reopened.form.stub_stage_1_cycle_seconds.value, 1); + assert.equal(reopened.form.stub_stage_2_cycle_seconds.value, 2); +}); + test('invalid Save leaves previously saved fields intact', () => { const h = createHarness(), dialog = h.open(), result = defaults(dialog.form); result.display_name = 'Original';