sound library
This commit is contained in:
@@ -31,7 +31,7 @@ function harness(capture = false) {
|
||||
add(undo) { assert.equal(undo, false); Texture.all.push(this); }
|
||||
}
|
||||
const context = {
|
||||
Buffer, Timeline: { animation: null },
|
||||
Buffer, Blob, URL: { createObjectURL() { return 'blob:import-preview'; }, revokeObjectURL() {} }, Timeline: { animation: null },
|
||||
Project: { uuid: 'original' }, Group, Cube: { all: [] }, Texture, Outliner: { elements: [] },
|
||||
Plugin: { register() {} }, requireNativeModule: require,
|
||||
localStorage: { getItem: (key) => storage.get(key), setItem: (key, value) => storage.set(key, value) },
|
||||
@@ -49,7 +49,10 @@ function harness(capture = false) {
|
||||
Animator: {
|
||||
loadFile(file, names) {
|
||||
context.loadedAnimation = JSON.parse(file.content);
|
||||
context.Animation.all = names.map((name) => ({ name, select() {} }));
|
||||
context.Animation.all = names.map((name) => ({ name, select() {}, animators: { effects: { sound:
|
||||
Object.entries(context.loadedAnimation.animations[name]?.sound_effects || {}).map(([time, cues]) => ({
|
||||
time: Number(time), data_points: Array.isArray(cues) ? cues : [cues],
|
||||
})) } } }));
|
||||
},
|
||||
},
|
||||
Animation: { all: [] }, Canvas: { updateAll() {}, updateView() {} },
|
||||
@@ -313,7 +316,8 @@ test('complete import finds model texture in cached assets and uses its PNG dime
|
||||
importing.commitAutomaticImport(h.context.importedPlan);
|
||||
assert.equal(importing.context.Texture.all[0].uv_width, 32);
|
||||
assert.equal(importing.context.Texture.all[0].uv_height, 64);
|
||||
assert.equal(JSON.parse(importing.context.Project.animationdirector_actor_uv_basis)['1'].width, 32);
|
||||
assert.equal(JSON.parse(importing.context.Project.animationdirector_actor_uv_basis)['1'].width, 64,
|
||||
'The actor retains its geometry basis; each textured cube tracks its own normalization');
|
||||
assert.equal(JSON.parse(importing.context.Project.multiactor_actor_textures)['1'], row.defaultTexture);
|
||||
});
|
||||
|
||||
@@ -494,10 +498,13 @@ test('missing models can be supplied manually, and their locally supplied textur
|
||||
|
||||
test('batch import uses a new project, one undo entry, actor prefixes and texture override bindings', () => {
|
||||
const h = harness();
|
||||
h.storage.set('animationdirector_sound_source', path.resolve(__dirname, '../../NON/src/main/resources'));
|
||||
const plan = { parsed: { animationId: 'example' }, blockEntry: null,
|
||||
propEntries: { '["example","wolf","right",0]': { animation: 'example', item: 'minecraft:carrot', mode: 'item' } },
|
||||
definition: { actors: [{ label: 'wolf', entity_types: ['minecraft:wolf'] }], animators: ['Creator'], stages: [{ stage: 1 }] },
|
||||
imported: { stageNames: ['example.p1'], fileObj: { animations: { 'example.p1': { bones: { actor1_body: { rotation: [1, 2, 3] } } } } } },
|
||||
imported: { stageNames: ['example.p1'], fileObj: { animations: { 'example.p1': {
|
||||
bones: { actor1_body: { rotation: [1, 2, 3] } }, sound_effects: { '0.5': { effect: 'reactiveimpact' } },
|
||||
} } } },
|
||||
rows: [{ label: 'wolf', json: { afw_bone_textures: { body: 'test:textures/wolf.png' } },
|
||||
geo: { bones: [{ name: 'body' }] }, defaultTexture: 'test:textures/wolf.png',
|
||||
textures: new Map([['test:textures/wolf.png', { file: 'wolf.png' }]]) }] };
|
||||
@@ -511,6 +518,9 @@ test('batch import uses a new project, one undo entry, actor prefixes and textur
|
||||
assert.equal(override[h.context.Group.all[0].uuid].texture, 'test:textures/wolf.png');
|
||||
assert.ok(JSON.parse(h.context.Project.animationdirector_animdef_definitions).example);
|
||||
assert.equal(JSON.parse(h.context.Project.animationdirector_prop_previews)['["example","wolf","right",0]'].item,'minecraft:carrot');
|
||||
const cue = h.context.Animation.all[0].animators.effects.sound[0].data_points[0];
|
||||
assert.equal(cue.effect, 'reactiveimpact');
|
||||
assert.equal(cue.file, 'blob:import-preview');
|
||||
});
|
||||
|
||||
test('unexpected animation-load failures cancel the batch rather than keeping a partial import', () => {
|
||||
|
||||
@@ -107,7 +107,7 @@ test('animation menu orders import and creation actions and has no deprecated sp
|
||||
const menu = h.menus.find((entry) => entry.id === 'animationdirector_anims');
|
||||
assert.deepEqual(Array.from(menu.children, (action) => action.name), [
|
||||
'Automatically Import Animation', 'Manual Import', 'Actor Preferences',
|
||||
'Replace Actor Model', 'Block Requirements', 'Item Props', 'Create Animation Definition', 'Export Animations',
|
||||
'Replace Actor Model', 'Block Requirements', 'Item Props', 'Sound Library...', 'Create Animation Definition', 'Export Animations',
|
||||
]);
|
||||
assert.deepEqual(Array.from(menu.children[1].children, (action) => action.name), [
|
||||
'Import Actor', 'Import Animation', 'Import Animation Definition', 'Pack Folders',
|
||||
|
||||
@@ -8,7 +8,7 @@ const vm = require('node:vm');
|
||||
function harness() {
|
||||
const source = fs.readFileSync(path.join(__dirname, '..', 'AnimationDirector.js'), 'utf8').replace(
|
||||
' Plugin.register(PLUGIN_ID, {',
|
||||
' globalThis.uvTest = { normalizeActorUvs, expandProjectUvs, scaleCubeUvs, getActorUvBasis, tryLoadImportedActorTexture, applyActorTexturePreview, importGeometryIntoCurrentProject };\n Plugin.register(PLUGIN_ID, {'
|
||||
' globalThis.uvTest = { normalizeActorUvs, expandProjectUvs, scaleCubeUvs, getActorUvBasis, tryLoadImportedActorTexture, applyActorTexturePreview, importGeometryIntoCurrentProject, applyAllActorTexturePreviews, setProjectActorTextures, setProjectBoneTextureOverrides };\n Plugin.register(PLUGIN_ID, {'
|
||||
);
|
||||
class Group {
|
||||
static all = [];
|
||||
@@ -46,7 +46,7 @@ function harness() {
|
||||
setTimeout(callback) { callback(); },
|
||||
Undo: { initEdit() {}, finishEdit() {}, cancelEdit() {} },
|
||||
Project: { texture_width: 64, texture_height: 64, box_uv: true },
|
||||
Canvas: { updateAllUVs() {} }, Plugin: { register() {} },
|
||||
Canvas: { updateAllUVs() {}, updateAll() {} }, Plugin: { register() {} },
|
||||
localStorage: { getItem() { return null; } },
|
||||
};
|
||||
vm.runInNewContext(source, context);
|
||||
@@ -82,6 +82,30 @@ test('assigning a manually imported texture to an actor normalizes only that act
|
||||
assert.deepEqual(Array.from(selected.faces.north.uv), [0, 0, 32, 16]);
|
||||
});
|
||||
|
||||
test('bone texture dimensions override the base without repeated UV scaling', () => {
|
||||
const h = harness();
|
||||
const group = new h.context.Group({ name: 'actor1_wind', uuid: 'wind' });
|
||||
group.init();
|
||||
const baseCube = new h.Cube('actor1_base'), windCube = new h.Cube('actor1_wind_cube');
|
||||
windCube.addTo(group);
|
||||
h.context.Project.texture_width = h.context.Project.texture_height = 128;
|
||||
h.normalizeActorUvs(1, 128, 128);
|
||||
for (const [name, size] of [['vanilla', 32], ['wind', 128]]) {
|
||||
new h.Texture({ name, uv_width: size, uv_height: size }).add();
|
||||
}
|
||||
h.setProjectActorTextures({ 1: 'vanilla' });
|
||||
h.setProjectBoneTextureOverrides({ wind: { uuid: 'wind', name: group.name, texture: 'wind' } });
|
||||
h.applyAllActorTexturePreviews();
|
||||
assert.deepEqual(Array.from(baseCube.faces.north.uv), [0, 0, 64, 64]);
|
||||
assert.deepEqual(Array.from(windCube.faces.north.uv), [0, 0, 16, 16]);
|
||||
assert.equal(windCube.faces.north.texture, 'wind');
|
||||
h.applyAllActorTexturePreviews();
|
||||
assert.deepEqual(Array.from(windCube.faces.north.uv), [0, 0, 16, 16]);
|
||||
h.setProjectBoneTextureOverrides({});
|
||||
h.applyAllActorTexturePreviews();
|
||||
assert.deepEqual(Array.from(windCube.faces.north.uv), [0, 0, 64, 64]);
|
||||
});
|
||||
|
||||
test('importing a larger actor preserves UV mapping of the earlier model', () => {
|
||||
const h = harness();
|
||||
const geometry = (width) => ({ description: { texture_width: width, texture_height: width }, bones: [{ name: 'body', cubes: [
|
||||
|
||||
Reference in New Issue
Block a user