diff --git a/langs/en-ca.json b/langs/en-ca.json index 2600103..819956c 100644 --- a/langs/en-ca.json +++ b/langs/en-ca.json @@ -133,10 +133,13 @@ "missing-id": "An ID must be provided", "invalid-socket": "Invalid socket data received, this means a module or system bug is present.", "unknown-socket-event": "An unknown socket event was received: {event}", - "malformed-socket-payload": "Socket event \"{event}\" received with malformed payload. Details: {details}" + }, + "warn": { + "migration-in-progress": "Applying data migrations for version {version}. Please do NOT refresh the window while this warning is present." }, "success": { - "saved-default-attributes": "Successfully saved default Actor attributes" + "saved-default-attributes": "Successfully saved default Actor attributes", + "migration-successful": "Data migrations for version {version} were successful." } } } diff --git a/module/documents/Actor.mjs b/module/documents/Actor.mjs index 9969f7a..0c97cea 100644 --- a/module/documents/Actor.mjs +++ b/module/documents/Actor.mjs @@ -34,10 +34,14 @@ export class TAFActor extends Actor { this.#sortedTypes = null; }; - static migrateData(data, ...args) { + static migrateData(data, options) { + if (options.partial) { return } + console.log(`Actor#migrateData`, foundry.utils.deepClone(data), options); if (Object.keys(data.system?.attr ?? {}).length > 0) { + console.log(`attributes exist`) setProperty(data, `flags.${__ID__}.convertAttributesIntoItems`, true); }; + return data; }; // #endregion Lifecycle diff --git a/module/migrations/utils.mjs b/module/migrations/utils.mjs index 807e69a..6950cc2 100644 --- a/module/migrations/utils.mjs +++ b/module/migrations/utils.mjs @@ -23,10 +23,7 @@ export async function migrateCollection( options = {} ) { const toMigrate = collection - .filter(doc => { - console.log(`toMigrate.filter doc`, doc); - return doc.getFlag(__ID__, flag) - }) + .filter(doc => doc.getFlag(__ID__, flag)) .map(doc => { const update = convertor(doc) ?? {}; update[`_id`] = doc._id; @@ -41,8 +38,20 @@ export async function migrateCollection( return update; }) .filter(data => !!data); - // update in increments of 100 - // TODO: optionally return an array of DB operations for modifyBatch + + if (!options.update) { + return [{ + action: `update`, + broadcast: true, + documentName: collection.documentName, + updates: toMigrate, + noHook: true, + pack: options.pack, + parent: options.parent, + }]; + }; + + // Modify in batches of 100 const batches = Math.ceil(toMigrate.length / 100); for (let i = 0; i < batches; i++) { const updateData = toMigrate.slice(i * 100, (i + 1) * 100); @@ -65,9 +74,9 @@ export async function migrateCollection( * @param pack The CompendiumPack document * @returns {boolean} Whether or not the pack should be migrated */ -export function shouldMigrateCompendium(pack) { +export function shouldMigrateCompendium(pack, types = [`Actor`, `Item`]) { // We only care about actor and item migrations - if (!["Actor", "Item"].includes(pack.documentName)) return false; + if (!types.includes(pack.documentName)) return false; // World compendiums should all be migrated, system ones should never by migrated if (pack.metadata.packageType === "world") return true; diff --git a/module/migrations/v3.0.0.mjs b/module/migrations/v3.0.0.mjs index 9754b27..0aa7f35 100644 --- a/module/migrations/v3.0.0.mjs +++ b/module/migrations/v3.0.0.mjs @@ -3,9 +3,24 @@ import { migrateCollection, shouldMigrateCompendium } from "./utils.mjs"; const flag = `convertAttributesIntoItems`; const operations = []; +let compendiumOperations = []; export async function migrateTo3_0_0() { Logger.debug(`Starting v3.0.0 data migration`); + const packsToMigrate = game.packs.filter( + (pack) => shouldMigrateCompendium(pack, [`Actor`]), + ); + const intervalSize = 1 / (packsToMigrate.length + 1); + + const warning = ui.notifications.warn( + "taf.notifs.warn.migration-in-progress", + { + format: { version: `v3.0.0` }, + progress: true, + permanent: true, + console: false, + }, + ); operations.push( ...await migrateCollection( @@ -15,30 +30,41 @@ export async function migrateTo3_0_0() { { update: false, }, ), ); + warning.update({ pct: warning.pct + intervalSize }); - // for (const pack of game.packs) { - // if ( - // pack.metadata.type !== "Actor" - // || !shouldMigrateCompendium(pack) - // ) { - // continue; - // }; + for (const pack of packsToMigrate) { + await pack.getDocuments(); - // await pack.getDocuments(); + const wasLocked = pack.config.locked; + if (wasLocked) pack.configure({ locked: false }); - // // TODO: unlock compendium if required then re-lock after finishing - // await migrateCollection( - // pack, - // flag, - // handleMigratingActor, - // { pack }, - // ); - // }; + compendiumOperations.push( + ...await migrateCollection( + pack, + flag, + handleMigratingActor, + { pack, update: false, }, + ), + ); + + // foundry.documents.modifyBatch(compendiumOperations); + console.log(`compendiumOperations`, compendiumOperations); + + if (wasLocked) await pack.configure({ locked: true }); + + compendiumOperations = []; + warning.update({ pct: warning.pct + intervalSize }); + }; + + // TODO: re-lock packs here? + + warning.update({ pct: 1 }); // TODO: create the item documents (batch them if possible) Logger.debug(`Finished v3.0.0 migration, resulting operations:`); console.log(operations); // Use: foundry.documents.modifyBatch + // await foundry.documents.modifyBatch(operations); }; function handleMigratingActor(actor) { @@ -48,16 +74,27 @@ function handleMigratingActor(actor) { action: `create`, documentName: `Item`, parent: actor, + noHook: true, data: [], }; - const attrs = actor.system.attr; + const attrs = actor.system?.attr ?? {}; for (const [ key, attr ] of Object.entries(attrs)) { operation.data.push(convertToItem(key, attr)); }; - operations.push(operation); - return null; + // No items to create, don't queue the operation + if (operation.data.length > 0) { + if (actor.inCompendium) { + compendiumOperations.push(operation); + } else { + operations.push(operation); + }; + }; + + return { + "system.attr": _del, + }; }; function convertToItem(key, attr) { @@ -68,6 +105,7 @@ function convertToItem(key, attr) { key, value: attr.value, max: attr.isRange ? attr.max : null, + aboveTheFold: true, }, }; };