Skip to content

Commit

Permalink
v2.7.6
Browse files Browse the repository at this point in the history
- "Relink compendium entries" macro will no longer remove compendiums from their folders.
- "Bulk pack scenes" macro now correctly packs Scenes that are in child folders in v11.
- Updated French translation. Co-authored-by: 
  - rectulo
  • Loading branch information
sneat authored Aug 21, 2023
1 parent 8241072 commit 6b96d89
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 10 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v2.7.6

- "Relink compendium entries" macro will no longer remove compendiums from their folders.
- "Bulk pack scenes" macro now correctly packs Scenes that are in child folders in v11.
- Updated French translation. Co-authored-by:
- rectulo

## v2.7.5

- Fixed the "Bulk Pack Scenes" macro not working correctly on v11.
Expand Down
2 changes: 1 addition & 1 deletion module.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "scene-packer",
"title": "Library: Scene Packer",
"description": "A module to assist with Scene and Adventure packing and unpacking.",
"version": "2.7.5",
"version": "2.7.6",
"library": "true",
"manifestPlusVersion": "1.2.0",
"minimumCoreVersion": "0.8.6",
Expand Down
2 changes: 1 addition & 1 deletion packs/macros.db
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{"_id":"L2BGaj7HBxJHOSkM","name":"Bulk replace asset references","type":"script","author":"MRUsyvFBYyl6GZtk","img":"icons/svg/lightning.svg","scope":"global","command":"/*\n * Bulk replace asset references\n */\n(async () => {\n Dialog.prompt({\n title: 'Bulk replace asset references',\n content:\n '<p>This tool will search for asset references <strong>within your world</strong> that start with the provided value and replace that portion with the other provided value.</p>' +\n '<p><label>Find (case sensitive): <input type=\"text\" name=\"find\" placeholder=\"some/original/path/\"></label></p>' +\n '<p><label>Replace (case sensitive): <input type=\"text\" name=\"replace\" placeholder=\"your/new/path/\"></label></p>' +\n '<hr><p><label><input type=\"checkbox\"> Save changes?</label></p><p>Leaving this unchecked will operate in a \"dry run\" mode, where changes are only output to the console (F12).</p><hr>',\n label: 'Bulk replace',\n callback: async (html) => {\n const find = html.find('input[name=\"find\"]').val();\n const replace = html.find('input[name=\"replace\"]').val();\n const dryRun = !html.find('input[type=\"checkbox\"]')[0].checked;\n if (!find || !replace) {\n ui.notifications.warn('Please provide both a find and replace value.', {permanent: true});\n console.warn('Bulk replace asset references: Please provide both a find and replace value.');\n return;\n }\n\n const documentTypes = CONST.COMPENDIUM_DOCUMENT_TYPES || CONST.COMPENDIUM_ENTITY_TYPES || [];\n for (const documentType of documentTypes) {\n const collectionName = CONFIG[documentType]?.documentClass?.collectionName;\n if (!collectionName) {\n console.warn(`Bulk replace asset references: No collection name for ${documentType}`);\n continue;\n }\n\n const collection = game[collectionName];\n if (!collection) {\n continue;\n }\n\n console.groupCollapsed(`Bulk replace asset references: ${collectionName}`);\n for (const document of collection) {\n const original = document.toJSON();\n const replacementData = JSON.stringify(original).replaceAll(`\"${find}`, `\"${replace}`);\n if (original === replacementData) {\n continue;\n }\n\n const diff = diffObject(original, JSON.parse(replacementData));\n if (typeof foundry.utils.isEmpty === 'function' ? foundry.utils.isEmpty(diff) : foundry.utils.isObjectEmpty(diff)) {\n continue;\n }\n\n console.log(`Bulk replace asset references: Updating ${documentType} ${document.id} ${document.name}`);\n console.table(diff);\n if (!dryRun) {\n await document.update(diff);\n }\n }\n\n console.groupEnd();\n }\n\n ui.notifications.info('Bulk replace asset references complete. Check the console (F12) for full details.', {permanent: true});\n console.log('Bulk replace asset references complete.');\n },\n });\n})();","folder":null,"sort":0,"flags":{"core":{"sourceId":"Macro.YpZnc0IWBVWtIoJO"},"scene-packer":{"sourceId":"Macro.YpZnc0IWBVWtIoJO"}},"ownership":{"default":0,"MRUsyvFBYyl6GZtk":3},"_stats":{"systemId":"dnd5e","systemVersion":"2.2.2","coreVersion":"10.303","createdTime":null,"modifiedTime":1691045149885,"lastModifiedBy":"GmyVtlP5mAtoWJMx"}}
{"_id":"OUvevMPeaRKzQBVu","name":"Bulk Lock/Unlock compendiums","type":"script","author":"MRUsyvFBYyl6GZtk","img":"icons/svg/door-locked-outline.svg","scope":"global","command":"// This macro allows you to bulk lock or unlock compendiums\n// as a way to save time.\n(() => {\n if (!game.user.isGM) {\n return;\n }\n\n let activeModules = (isNewerVersion(game.version ?? game.data.version, '10') ? game.modules : game.data.modules)\n .filter((m) => m.active && ((m.packs ?? m.data?.packs)?.size || m.packs?.length))\n .map((m) => m.id);\n if (!activeModules.length) {\n ui.notifications.info(\n \"There are no modules with compendium packs in this world.\"\n );\n return;\n }\n let hasWorldCompendiums = !!game.packs.find(p => (p.metadata.packageName || p.metadata.package) === 'world')\n let content = `<p>Bulk Lock/Unlock compendium packs that belong to the following module:</p>`;\n content += '<select id=\"module-name\">';\n activeModules.forEach((m) => {\n content += `<option value=\"${m}\">${m}</option>`;\n });\n if (hasWorldCompendiums) {\n content += `<option value=\"world\">world</option>`;\n }\n content += \"</select>\";\n content += \"<p><hr></p>\";\n let d = new Dialog({\n title: \"Bulk Lock/Unlock compendium packs\",\n content: content,\n buttons: {\n lock: {\n icon: '<i class=\"fas fa-lock\"></i>',\n label: game.i18n.localize(\"Lock\"),\n callback: async (html) => {\n await setState(true, html.find(\"#module-name\")[0].value);\n },\n },\n unlock: {\n icon: '<i class=\"fas fa-unlock\"></i>',\n label: game.i18n.localize(\"Unlock\"),\n callback: async (html) => {\n await setState(false, html.find(\"#module-name\")[0].value);\n },\n },\n cancel: {\n icon: '<i class=\"fas fa-times\"></i>',\n label: game.i18n.localize(\"Cancel\"),\n },\n },\n });\n d.render(true);\n\n async function setState(locked, moduleName) {\n locked = !!locked;\n const compendiums = game.packs.filter(\n (p) => (p.metadata.packageName || p.metadata.package) === moduleName\n );\n const settings = {};\n compendiums.forEach((p) => {\n settings[`${(p.metadata.packageName || p.metadata.package)}.${p.metadata.name}`] = { locked };\n });\n if (Object.keys(settings).length) {\n let key = locked\n ? \"Locking compendiums: {list}\"\n : \"Unlocking compendiums: {list}\";\n ui.notifications.info(\n game.i18n.format(key, {\n list: Object.keys(settings).join(\", \"),\n locked: locked,\n })\n );\n let configSetting =\n Compendium?.CONFIG_SETTING ||\n CompendiumCollection?.CONFIG_SETTING ||\n \"compendiumConfiguration\";\n await game.settings.set(\"core\", configSetting, settings);\n }\n }\n})();","folder":null,"sort":0,"permission":{"default":0},"flags":{"scene-packer":{"hash":"9526d9354098381b75dbb4a47300957cbdf45c4b","sourceId":"Macro.cEYqc2chS1vOpIPo"},"core":{"sourceId":"Macro.cEYqc2chS1vOpIPo"}}}
{"name":"Show Scenes Worth Packing","type":"script","author":"XKmxUPdkcWMuKdfu","img":"icons/svg/eye.svg","scope":"global","command":"// This macro will check your world Scenes to see whether\n// there is any data that would benefit from being Packed.\n\nScenePacker.ShowScenesWorthPacking();","folder":null,"sort":0,"permission":{"default":0,"XKmxUPdkcWMuKdfu":3},"flags":{"core":{"sourceId":"Macro.zo5hb9xMPyiUEqrE"}},"_id":"P3UkVzGKhtwAcpRT"}
{"_id":"YsJZfzxws5UeXYJC","name":"Bulk pack scenes","type":"script","author":"FYKEkGQDWeedzh8v","img":"icons/svg/barrel.svg","scope":"global","command":"// This macro will pack/repack all scenes in the requested scene folder.\nDialog.prompt({\n title: 'Pack all Scenes in a folder',\n content: '<label>Enter folder name (case sensitive): <input type=\"text\" name=\"folder\"><hr></label>',\n label: 'Pack scenes',\n callback: async (html) => {\n let folderName = html.find('input').val();\n if (!folderName) {\n return;\n }\n let process = async (f, instance) => {\n const contents = f.documents ?? f.contents ?? f.content;\n for (const scene of (contents || [])) {\n await instance.ClearPackedData(scene);\n await instance.PackScene(scene);\n }\n for (const child of (f.children || [])) {\n await process(child, instance);\n }\n }\n const folder = game.folders.find(f => f.name === folderName && f.type === 'Scene');\n if (folder) {\n ScenePacker.PromptForInstance().then(async instance => {\n await process(folder, instance);\n ui.notifications.warn('Make sure that you export your packed scenes to your compendium. You should also run \"Relink compendium entries\" one more time after exporting your scenes.', { permanent: true });\n })\n } else {\n console.error(`Could not find a Scene folder with the name \"${folderName}\"`);\n }\n },\n});","folder":null,"sort":0,"flags":{"core":{"sourceId":"Macro.oYPUPtEzf8Dp90ZS"},"scene-packer":{"sourceId":"Macro.oYPUPtEzf8Dp90ZS"}},"ownership":{"default":0,"FYKEkGQDWeedzh8v":3},"_stats":{"systemId":"dnd5e","systemVersion":"2.2.2","coreVersion":"10.303","createdTime":null,"modifiedTime":1691036534605,"lastModifiedBy":"GmyVtlP5mAtoWJMx"}}
{"_id":"YsJZfzxws5UeXYJC","name":"Bulk pack scenes","type":"script","author":"FYKEkGQDWeedzh8v","img":"icons/svg/barrel.svg","scope":"global","command":"// This macro will pack/repack all scenes in the requested scene folder.\nDialog.prompt({\n title: 'Pack all Scenes in a folder',\n content: '<label>Enter folder name (case sensitive): <input type=\"text\" name=\"folder\"><hr></label>',\n label: 'Pack scenes',\n callback: async (html) => {\n let folderName = html.find('input').val();\n if (!folderName) {\n return;\n }\n let process = async (f, instance) => {\n const contents = f.entries ?? f.documents ?? f.contents ?? f.content ?? [];\n for (const scene of (contents || [])) {\n await instance.ClearPackedData(scene);\n await instance.PackScene(scene);\n }\n for (const child of (f.children || [])) {\n await process(child, instance);\n }\n }\n const folder = game.folders.find(f => f.name === folderName && f.type === 'Scene');\n if (folder) {\n ScenePacker.PromptForInstance().then(async instance => {\n await process(folder, instance);\n ui.notifications.warn('Make sure that you export your packed scenes to your compendium. You should also run \"Relink compendium entries\" one more time after exporting your scenes.', { permanent: true });\n })\n } else {\n console.error(`Could not find a Scene folder with the name \"${folderName}\"`);\n }\n },\n});","folder":null,"sort":0,"flags":{"core":{"sourceId":"Macro.oYPUPtEzf8Dp90ZS"},"scene-packer":{"sourceId":"Macro.oYPUPtEzf8Dp90ZS"}},"ownership":{"default":0,"FYKEkGQDWeedzh8v":3},"_stats":{"systemId":"dnd5e","systemVersion":"2.2.2","coreVersion":"10.303","createdTime":null,"modifiedTime":1691036534605,"lastModifiedBy":"GmyVtlP5mAtoWJMx"}}
{"_id":"Zj82Pme9Bzjd6MPK","name":"Clean up #[CF_tempEntity] entries","type":"script","author":"XbLObTJNibRaLZgl","img":"icons/svg/acid.svg","scope":"global","command":"// Prompt to remove \"#[CF_tempEntity]\" items from the world,\n// in the case where they have been imported when the\n// Compendium Folders module is not active.\n(async () => {\n if (!game.user.isGM) {\n return;\n }\n\n let cfTempEntity = '#[CF_tempEntity]';\n let activeModules = (isNewerVersion(game.version ?? game.data.version, '10') ? game.modules : game.data.modules)\n .filter((m) => m.active && ((m.packs ?? m.data?.packs)?.size || m.packs?.length))\n .map((m) => m.id);\n let content = `<p>Remove #[CF_tempEntity] from the following location:</p>`;\n content += '<select id=\"module-name\">';\n content += `<option value=\"world\" selected>world</option>`;\n activeModules.forEach((m) => {\n content += `<option value=\"${m}\">${m}</option>`;\n });\n content += '</select>';\n content += '<p><hr></p>';\n new Dialog({\n title: 'Remove #[CF_tempEntity]',\n content: content,\n buttons: {\n process: {\n icon: '<i class=\"fas fa-check\"></i>',\n label: game.i18n.localize('Process'),\n callback: async (html) => {\n await process(html.find('#module-name')[0].value);\n },\n },\n cancel: {\n icon: '<i class=\"fas fa-times\"></i>',\n label: game.i18n.localize('Cancel'),\n },\n },\n }).render(true);\n\n async function process(moduleName) {\n let collections = [\n {name: 'scenes', collection: game.scenes},\n {name: 'actors', collection: game.actors},\n {name: 'items', collection: game.items},\n {name: 'journals', collection: game.journal},\n {name: 'macros', collection: game.macros},\n {name: 'playlists', collection: game.playlists},\n {name: 'roll tables', collection: game.tables},\n ];\n let packs = game.packs.filter(p => (p.metadata.packageName || p.metadata.package) === moduleName)\n for (const entity of collections) {\n const found = [];\n if (moduleName === 'world') {\n found.push(...entity.collection.filter(e => e.name === cfTempEntity));\n }\n for (const pack of packs) {\n const packType = pack.documentName || pack.entity;\n if (packType !== entity.collection.documentName) {\n continue;\n }\n pack.configure({locked: false});\n const docs = await pack.getDocuments();\n found.push(...docs.filter(e => e.name === cfTempEntity));\n }\n if (found.length) {\n for (const foundElement of found) {\n console.log(`Deleting ${foundElement.id} from ${entity.name}`);\n await foundElement.delete();\n }\n } else {\n console.log(`No ${entity.name} with the name \"${cfTempEntity}\" found.`);\n }\n }\n }\n})();","folder":null,"sort":0,"flags":{"core":{"sourceId":"Macro.Vseli28UPwE5waan"},"scene-packer":{"sourceId":"Macro.mYvPx3E5TVzLprkb","hash":"dd9e25978da2a949c96605a1789e171694d2442f"}},"ownership":{"default":0,"XbLObTJNibRaLZgl":3},"_stats":{"systemId":"dnd5e","systemVersion":"1.6.1","coreVersion":"10.263","createdTime":null,"modifiedTime":1653106037269,"lastModifiedBy":"sH4kZUxETJcGJ0Zj"}}
{"name":"Show asset report","type":"script","author":"ajyvWN29UcpExc6d","img":"icons/svg/hazard.svg","scope":"global","command":"// This macro shows an asset report that details the assets\n// in this world and whether they have \"external\" dependencies.\n//\n// Use it to help determine whether your packaged module will\n// result in broken assets (images, sounds etc.).\n\nnew ScenePacker.AssetReport();","folder":null,"sort":0,"permission":{"default":0,"ajyvWN29UcpExc6d":3},"flags":{"core":{"sourceId":"Macro.CIKJ4iAmyMvhtptI"}},"_id":"mkNKay70v790Fu4h"}
{"_id":"qIQ9ehnHD47ekm1l","name":"Reset world Scene Packer prompts","type":"script","author":"Rt2brfVFebtCuVnc","img":"icons/svg/hanging-sign.svg","scope":"global","command":"// This macro will prompt you to select your module and then\n// will reset the settings values to allow retriggering of\n// the prompts when you first install a world.\n//\n// These prompts are the \"Yes import all\", \"Let me choose\" etc.\n\nlet content = '';\nlet instances = Object.keys(ScenePacker.instances);\nif (instances.length) {\n content = '<p>Select the module that you want to reset prompting for:</p>';\n content += '<select id=\"module-name\">';\n instances.forEach(m => {\n content += `<option value=\"${m}\">${m}</option>`;\n });\n content += '</select>';\n content += '<p>Refresh the world after resetting.</p>'\n} else {\n content = '<p>There are no modules registered with Scene Packer currently available.</p>';\n}\nlet d = new Dialog({\n title: 'Select instance',\n content: content,\n buttons: {\n relink: {\n icon: '<i class=\"fas fa-check\"></i>',\n label: 'Reset',\n callback: (html) => {\n let moduleName = html.find('#module-name')[0].value;\n if (!moduleName) {\n return;\n }\n game.settings.set(moduleName, 'imported', '0.0.0');\n game.settings.set(moduleName, 'prompted', '0.0.0');\n game.settings.set(moduleName, 'showWelcomePrompts', true);\n game.settings.set(moduleName, 'migrationSystemVersion', '0.0.0')\n if (canvas?.scene?.getFlag(moduleName, 'imported')) {\n canvas.scene.setFlag(moduleName, 'imported', '0.0.0')\n }\n },\n },\n cancel: {\n icon: '<i class=\"fas fa-times\"></i>',\n label: 'Cancel',\n },\n },\n});\nd.render(true);","folder":null,"sort":0,"flags":{"core":{"sourceId":"Macro.8Ed2EtweXHL8UrPq"},"scene-packer":{"sourceId":"Macro.8Ed2EtweXHL8UrPq"}},"ownership":{"default":0,"Rt2brfVFebtCuVnc":3},"_stats":{"systemId":"dnd5e","systemVersion":"2.0.2","coreVersion":"10.285","createdTime":null,"modifiedTime":1663143118043,"lastModifiedBy":"rfTqhTOpsOhdbu6t"}}
Expand Down
13 changes: 5 additions & 8 deletions scripts/scene-packer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4468,22 +4468,19 @@ export default class ScenePacker {

locked = !!locked;
const compendiums = game.packs.filter(p => (p.metadata.packageName || p.metadata.package) === moduleName);
const settings = {};
compendiums.forEach((p) => {
settings[`${(p.metadata.packageName || p.metadata.package)}.${p.metadata.name}`] = {locked};
});
if (Object.keys(settings).length) {
for (const pack of compendiums) {
await pack.configure({ locked });
}
if (compendiums.length) {
let key = locked ?
'SCENE-PACKER.world-conversion.compendiums.lock' :
'SCENE-PACKER.world-conversion.compendiums.unlock';
ui.notifications.info(
game.i18n.format(key, {
list: Object.keys(settings).join(', '),
list: compendiums.map(p => `${(p.metadata.packageName || p.metadata.package)}.${p.metadata.name}`).join(', '),
locked: locked,
}),
);
let configSetting = Compendium?.CONFIG_SETTING || CompendiumCollection?.CONFIG_SETTING || 'compendiumConfiguration';
await game.settings.set('core', configSetting, settings);
}
}

Expand Down

0 comments on commit 6b96d89

Please sign in to comment.