feat: update for v10

This commit is contained in:
Johannes Loher 2022-11-21 03:00:46 +01:00
parent 6277e27056
commit f25b46a226
63 changed files with 41349 additions and 24332 deletions

View file

@ -20,7 +20,7 @@ async function migrate() {
/** @type {import("./migrationHelpers").ActorUpdateDataGetter} */
function getActorUpdateData() {
const updateData = {
data: {
system: {
combatValues: [
"hitPoints",
"defense",

View file

@ -24,7 +24,7 @@ async function migrate() {
function getItemUpdateData(itemData) {
if (!["loot"].includes(itemData.type ?? "")) return undefined;
return {
data: {
system: {
"-=equipped": null,
},
};

View file

@ -23,10 +23,10 @@ async function migrate() {
/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return;
const cooldownDurationUnit = itemData.data?.cooldownDuration.unit;
const cooldownDurationUnit = itemData.system?.cooldownDuration.unit;
const updateData = {
data: {
system: {
"-=scrollPrice": null,
minimumLevels: { healer: null, wizard: null, sorcerer: null },
cooldownDuration: {

View file

@ -32,12 +32,12 @@ async function migrate() {
/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return;
const cooldownDurationUnit = itemData.data?.cooldownDuration.unit;
const cooldownDurationValue = itemData.data?.cooldownDuration.value;
const cooldownDurationUnit = itemData.system?.cooldownDuration.unit;
const cooldownDurationValue = itemData.system?.cooldownDuration.value;
const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit);
const updateData = {
data: {
system: {
cooldownDuration,
},
};

View file

@ -23,15 +23,15 @@ async function migrate() {
/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return;
const spellCategory = itemData.data?.spellCategory;
const spellCategory = itemData.system?.spellCategory;
const spellGroups = migrateSpellCategory(spellCategory);
// @ts-expect-error bonus is removed with this migration
const bonus = itemData.data?.bonus;
const bonus = itemData.system?.bonus;
const spellModifier = migrateBonus(bonus);
const updateData = {
data: {
system: {
spellGroups,
"-=spellCategory": null,
spellModifier,

View file

@ -25,7 +25,7 @@ function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return;
return {
data: {
system: {
allowsDefense: false,
},
};

61
src/migration/008.js Normal file
View file

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import {
getActorUpdateDataGetter,
getCompendiumMigrator,
getItemUpdateDataGetter,
getSceneUpdateDataGetter,
migrateActors,
migrateCompendiums,
migrateItems,
migrateScenes,
} from "./migrationHelpers";
/** @type {import("./migration").Migration["migrate"]} */
async function migrate() {
await migrateItems(getItemUpdateData);
await migrateActors(getActorUpdateData);
await migrateScenes(getSceneUpdateData);
await migrateCompendiums(migrateCompendium);
}
/** @type {import("./migrationHelpers").EffectUpdateDataGetter} */
function getEffectUpdateData(effectData) {
const data = foundry.utils.deepClone(effectData);
let hasUpdates = false;
if ("changes" in data) {
for (const change of data.changes) {
const newValue = change.value.replaceAll(/@data\./g, "@system.");
if (newValue !== change.value) {
hasUpdates = true;
change.value = newValue;
}
}
}
/** @type {string | undefined} */
const condition = data.flags?.ds4?.itemEffectConfig?.condition;
if (condition !== undefined) {
const newCondition = condition.replaceAll(/(@actor|@item|@effect)\.data/g, "$1.system");
if (newCondition !== condition) {
hasUpdates = true;
data.flags.ds4.itemEffectConfig.condition = newCondition;
}
}
if (hasUpdates) {
return data;
}
}
const getItemUpdateData = getItemUpdateDataGetter(getEffectUpdateData);
const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData, getEffectUpdateData);
const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
/** @type {import("./migration").Migration} */
export const migration = {
migrate,
migrateCompendium,
};

View file

@ -12,6 +12,7 @@ import { migration as migration004 } from "./004";
import { migration as migration005 } from "./005";
import { migration as migration006 } from "./006";
import { migration as migration007 } from "./007";
import { migration as migration008 } from "./008";
/**
* Perform migrations.
@ -166,7 +167,16 @@ function getTargetMigrationVersion() {
/**
* @type {Migration[]}
*/
const migrations = [migration001, migration002, migration003, migration004, migration005, migration006, migration007];
const migrations = [
migration001,
migration002,
migration003,
migration004,
migration005,
migration006,
migration007,
migration008,
];
/**
* DOes the migration version indicate the world is being started for the first time?

View file

@ -7,7 +7,9 @@ import { DS4Item } from "../documents/item/item";
import { logger } from "../utils/logger";
import { getGame } from "../utils/utils";
/** @typedef {(itemData: Partial<foundry.data.ItemData["_source"]>) => DeepPartial<foundry.data.ItemData["_source"]> | Record<string, unknown> | undefined} ItemUpdateDataGetter */
/** @typedef {(effectData: object) => Record<string, unknown> | undefined} EffectUpdateDataGetter */
/** @typedef {(itemData: object) => Record<string, unknown> | undefined} ItemUpdateDataGetter */
/**
* Migrate world items.
@ -28,7 +30,7 @@ export async function migrateItems(getItemUpdateData) {
}
}
/** @typedef {(actorData: Partial<foundry.data.ActorData["_source"]>) => DeepPartial<foundry.data.ActorData["_source"]> | undefined} ActorUpdateDataGetter */
/** @typedef {(actorData: object>) => Record<string, unknown> | undefined} ActorUpdateDataGetter */
/**
* Migrate world actors.
@ -52,7 +54,7 @@ export async function migrateActors(getActorUpdateData) {
}
}
/** @typedef {(aceneData: foundry.data.SceneData) => DeepPartial<foundry.data.SceneData["_source"]> | undefined} SceneUpdateDataGetter */
/** @typedef {(scene: Scene) => Record<string, unknown> | undefined} SceneUpdateDataGetter */
/**
* Migrate world scenes.
@ -62,10 +64,12 @@ export async function migrateActors(getActorUpdateData) {
export async function migrateScenes(getSceneUpdateData) {
for (const scene of getGame().scenes ?? []) {
try {
const updateData = getSceneUpdateData(scene.data);
const updateData = getSceneUpdateData(scene);
if (updateData) {
logger.info(`Migrating Scene document ${scene.name} (${scene.id})`);
await scene.update(updateData);
// We need to clear the old syntehtic actors from the cache
scene.tokens.forEach((t) => (t._actor = null));
}
} catch (err) {
logger.error(
@ -76,7 +80,7 @@ export async function migrateScenes(getSceneUpdateData) {
}
}
/** @typedef {(pack: CompendiumCollection) => Promise<void>} CompendiumMigrator*/
/** @typedef {(pack: CompendiumCollection) => Promise<void>} CompendiumMigrator */
/**
* Migrate world compendium packs.
@ -92,34 +96,70 @@ export async function migrateCompendiums(migrateCompendium) {
}
/**
* Get a function to create actor update data that adjusts the owned items of the actor according to the given function.
* @param {ItemUpdateDataGetter} getItemUpdateData The function to generate item update data
* Get a function to create item update data based on the given function to update embedded documents.
* @param {EffectUpdateDataGetter} [getEffectUpdateData] A function to generate effect update data
* @returns {ItemUpdateDataGetter} A function to get item update data
*/
export function getItemUpdateDataGetter(getEffectUpdateData) {
return (itemData) => {
let hasEffectUpdates = false;
const effects = itemData.effects?.map((effectData) => {
const update = getEffectUpdateData(effectData);
if (update) {
hasEffectUpdates = true;
return foundry.utils.mergeObject(effectData, update, { inplace: false, performDeletions: true });
} else {
return effectData;
}
});
return hasEffectUpdates ? { effects } : undefined;
};
}
/**
* Get a function to create actor update data based on the given function to update embedded documents.
* @param {ItemUpdateDataGetter} [getItemUpdateData] A function to generate item update data
* @param {EffectUpdateDataGetter} [getEffectUpdateData] A function to generate effect update data
* @returns {ActorUpdateDataGetter} A function to get actor update data
*/
export function getActorUpdateDataGetter(getItemUpdateData) {
export function getActorUpdateDataGetter(getItemUpdateData, getEffectUpdateData) {
return (actorData) => {
let hasItemUpdates = false;
const items = actorData.items?.map((itemData) => {
const update = getItemUpdateData(itemData);
const update = getItemUpdateData?.(itemData);
if (update) {
hasItemUpdates = true;
return { ...itemData, ...update };
return foundry.utils.mergeObject(itemData, update, { inplace: false, performDeletions: true });
} else {
return itemData;
}
});
return hasItemUpdates ? { items } : undefined;
let hasEffectUpdates = false;
const effects = actorData.effects?.map((effectData) => {
const update = getEffectUpdateData?.(effectData);
if (update) {
hasEffectUpdates = true;
return foundry.utils.mergeObject(effectData, update, { inplace: false, performDeletions: true });
} else {
return effectData;
}
});
const result = {
items: hasItemUpdates ? items : undefined,
effects: hasEffectUpdates ? effects : undefined,
};
return hasItemUpdates | hasEffectUpdates ? result : undefined;
};
}
/**
* Get a function to create scene update data that adjusts the actors of the tokens of the scene according to the given function.
* @param {ActorUpdateDataGetter} getItemUpdateData The function to generate actor update data
* @param {ActorUpdateDataGetter} [getItemUpdateData] The function to generate actor update data
* @returns {SceneUpdateDataGetter} A function to get scene update data
*/
export function getSceneUpdateDataGetter(getActorUpdateData) {
return (sceneData) => {
const tokens = sceneData.tokens.map((token) => {
return (scene) => {
const tokens = scene.tokens.map((token) => {
const t = token.toObject();
if (!t.actorId || t.actorLink) {
t.actorData = {};
@ -129,18 +169,18 @@ export function getSceneUpdateDataGetter(getActorUpdateData) {
} else if (!t.actorLink) {
const actorData = foundry.utils.deepClone(t.actorData);
actorData.type = token.actor?.type;
const update = getActorUpdateData(actorData);
const update = getActorUpdateData?.(actorData);
if (update !== undefined) {
["items", "effects"].forEach((embeddedName) => {
const embeddedUpdates = update[embeddedName];
if (embeddedUpdates === undefined || !embeddedUpdates.length) return;
if (!embeddedUpdates?.length) return;
const updates = new Map(embeddedUpdates.flatMap((u) => (u && u._id ? [[u._id, u]] : [])));
const originals = t.actorData[embeddedName];
if (!originals) return;
originals.forEach((original) => {
if (!original._id) return;
const update = updates.get(original._id);
if (update) foundry.utils.mergeObject(original, update);
if (update) foundry.utils.mergeObject(original, update, { performDeletions: true });
});
delete update[embeddedName];
});
@ -191,7 +231,7 @@ export function getCompendiumMigrator(
const updateData = getActorUpdateData(doc.toObject());
updateData && (await doc.update(updateData));
} else if (doc instanceof Scene && getSceneUpdateData) {
const updateData = getSceneUpdateData(doc.data);
const updateData = getSceneUpdateData(doc);
updateData && (await doc.update(updateData));
}
} catch (err) {