tweak
This commit is contained in:
+25
-1
@@ -426,6 +426,7 @@
|
||||
type: 'select',
|
||||
options: { '': 'None', V: 'V', A: 'A', M: 'M' },
|
||||
value: metadata.injector || '',
|
||||
description: 'Selecting an injector adds gender.male to required actor tags. You can remove that tag afterward.',
|
||||
condition: fieldCondition,
|
||||
};
|
||||
form[`${base}_injects_into`] = {
|
||||
@@ -486,6 +487,25 @@
|
||||
});
|
||||
}
|
||||
|
||||
function createInjectorGenderDefaultHandler(form) {
|
||||
const roles = new Map(Object.entries(form).filter(([key]) => key.endsWith('_injector'))
|
||||
.map(([key, field]) => [key, field.value || '']));
|
||||
return (dialog, result) => {
|
||||
const updates = {};
|
||||
for (const [key, previous] of roles) {
|
||||
if (!result || !(key in result)) continue;
|
||||
const role = result[key];
|
||||
roles.set(key, role);
|
||||
if (role === previous || !['V', 'A', 'M'].includes(role)) continue;
|
||||
const tagsKey = key.replace(/_injector$/, '_actor_tags');
|
||||
const tags = uniqueTrimmedStrings(parseCommaSeparatedStrings(result[tagsKey]));
|
||||
if (tags.includes('gender.male')) continue;
|
||||
result[tagsKey] = updates[tagsKey] = [...tags, 'gender.male'].join(', ');
|
||||
}
|
||||
if (Object.keys(updates).length) dialog.form.setValues(updates, false);
|
||||
};
|
||||
}
|
||||
|
||||
function validateActorAnimdefMetadata(metadata, actorLabel) {
|
||||
for (const entityType of metadata.entity_types || []) {
|
||||
if (!RESOURCE_ID_PATTERN.test(entityType)) {
|
||||
@@ -1650,6 +1670,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
const updateInjectorGenderDefault = createInjectorGenderDefaultHandler(form);
|
||||
const dialog = new Dialog({
|
||||
id: 'edit_actor_preferences',
|
||||
title: 'Actor Preferences',
|
||||
@@ -1658,9 +1679,10 @@
|
||||
buttons: ['Cancel', 'Save & Apply'],
|
||||
cancelIndex: 0,
|
||||
confirmIndex: 1,
|
||||
onFormChange: (result) => {
|
||||
onFormChange(result) {
|
||||
showBoneTextureOverrides = !!result?.show_bone_texture_overrides;
|
||||
showAnimdefMetadata = !!result?.show_animdef_metadata;
|
||||
updateInjectorGenderDefault(this, result);
|
||||
},
|
||||
onConfirm: (result) => {
|
||||
let editing = false;
|
||||
@@ -4088,11 +4110,13 @@
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const updateInjectorGenderDefault = createInjectorGenderDefaultHandler(form);
|
||||
const dialog = new Dialog({
|
||||
id: 'create_afw_animation_definition_review',
|
||||
title: `Animation Definition: ${group.id}`,
|
||||
width: 760,
|
||||
form,
|
||||
onFormChange(result) { updateInjectorGenderDefault(this, result); },
|
||||
buttons: ['Cancel', 'Save', 'Create Animdef'],
|
||||
cancelIndex: 0,
|
||||
confirmIndex: 2,
|
||||
|
||||
@@ -8,7 +8,7 @@ function createHarness() {
|
||||
const file = path.join(__dirname, '..', 'AnimationDirector.js');
|
||||
const source = fs.readFileSync(file, 'utf8').replace(
|
||||
' Plugin.register(PLUGIN_ID, {',
|
||||
' globalThis.adTest = { showAnimationDefinitionReviewDialog };\n Plugin.register(PLUGIN_ID, {'
|
||||
' globalThis.adTest = { showAnimationDefinitionReviewDialog, createInjectorGenderDefaultHandler };\n Plugin.register(PLUGIN_ID, {'
|
||||
);
|
||||
const dialogs = [];
|
||||
const exports = [];
|
||||
@@ -45,7 +45,8 @@ function createHarness() {
|
||||
context.adTest.showAnimationDefinitionReviewDialog(group, analysis);
|
||||
return dialogs.at(-1);
|
||||
}
|
||||
return { open, exports, errors, project, analysis, setFormResult(result) { formResult = result; } };
|
||||
return { open, exports, errors, project, analysis, createInjectorGenderDefaultHandler: context.adTest.createInjectorGenderDefaultHandler,
|
||||
setFormResult(result) { formResult = result; } };
|
||||
}
|
||||
|
||||
function defaults(form) {
|
||||
@@ -54,6 +55,50 @@ function defaults(form) {
|
||||
.map(([key, field]) => [key, field.value]));
|
||||
}
|
||||
|
||||
test('selecting an injector adds an editable male tag without enforcing it on export', () => {
|
||||
for (const role of ['V', 'A', 'M']) {
|
||||
const h = createHarness(), dialog = h.open(), result = defaults(dialog.form), updates = [];
|
||||
const instance = { form: { setValues(values, notify) { updates.push(values); assert.equal(notify, false); } } };
|
||||
result.stub_actor_1_actor_tags = 'custom.tag';
|
||||
result.stub_actor_1_injector = role;
|
||||
dialog.onFormChange.call(instance, result);
|
||||
assert.equal(result.stub_actor_1_actor_tags, 'custom.tag, gender.male');
|
||||
assert.equal(updates.length, 1);
|
||||
result.stub_actor_1_actor_tags = 'custom.tag';
|
||||
dialog.onFormChange.call(instance, result);
|
||||
result.display_name = 'Unrelated edit';
|
||||
dialog.onFormChange.call(instance, result);
|
||||
assert.equal(updates.length, 1, 'Manual removal survives unrelated changes');
|
||||
result.stub_actor_2_entity_types = 'minecraft:wolf';
|
||||
dialog.onConfirm(result);
|
||||
assert.equal(h.errors.length, 0);
|
||||
assert.equal(h.exports[0].actors[0].injector, role);
|
||||
assert.deepEqual(h.exports[0].actors[0].actor_tags, ['custom.tag']);
|
||||
}
|
||||
});
|
||||
|
||||
test('injector defaults preserve loaded roles, existing tags, and actor preferences edits', () => {
|
||||
const h = createHarness();
|
||||
const form = {
|
||||
preferences_animdef_1_injector: { value: 'V' },
|
||||
preferences_animdef_2_injector: { value: '' },
|
||||
};
|
||||
const update = h.createInjectorGenderDefaultHandler(form), writes = [];
|
||||
const dialog = { form: { setValues(values) { writes.push(values); } } };
|
||||
const result = { preferences_animdef_1_injector: 'V', preferences_animdef_1_actor_tags: 'custom.tag',
|
||||
preferences_animdef_2_injector: '', preferences_animdef_2_actor_tags: 'gender.male, other.tag' };
|
||||
update(dialog, result);
|
||||
assert.equal(writes.length, 0, 'Opening an imported/saved role does not add a tag');
|
||||
result.preferences_animdef_2_injector = 'A'; update(dialog, result);
|
||||
assert.equal(writes.length, 0, 'Existing male tags are not duplicated');
|
||||
result.preferences_animdef_2_injector = ''; update(dialog, result);
|
||||
assert.equal(result.preferences_animdef_2_actor_tags, 'gender.male, other.tag', 'Deselecting a role does not remove explicit tags');
|
||||
result.preferences_animdef_2_actor_tags = 'other.tag';
|
||||
result.preferences_animdef_2_injector = 'M'; update(dialog, result);
|
||||
assert.equal(result.preferences_animdef_2_actor_tags, 'other.tag, gender.male');
|
||||
assert.equal(result.preferences_animdef_1_actor_tags, 'custom.tag', 'Only the changed actor is affected');
|
||||
});
|
||||
|
||||
test('Save retains definition fields in the project without exporting and restores them on reopen', () => {
|
||||
const h = createHarness(), dialog = h.open(), result = defaults(dialog.form);
|
||||
assert.deepEqual(Array.from(dialog.buttons), ['Cancel', 'Save', 'Create Animdef']);
|
||||
|
||||
Reference in New Issue
Block a user