Skip to content

Commit

Permalink
Possible Performance Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ChasarooniZ committed Nov 21, 2024
1 parent 2af51e6 commit 5158b19
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 39 deletions.
4 changes: 2 additions & 2 deletions languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"include-canvas": {
"enabled": {
"name": "Include Canvas Tokens On Timebased Refreshed",
"hint": "When enabled will not just check the party, but also all tokens on the canvas to see to refresh their uses"
"hint": "When enabled will not just check the party, but also all tokens on the canvas to see to refresh their uses. Note this will have performance implications if you have a large number of actors"
}
},
"automate-item": {
Expand Down Expand Up @@ -45,4 +45,4 @@
}
}
}
}
}
29 changes: 15 additions & 14 deletions scripts/hooks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MODULE_ID } from "./helper/const.js";
import { getCanvasActors } from "./lib/helpers.js";
import { getCoolDownTime, updateFrequencyOfActors } from "./module.js";
import { cooldownCache, getCoolDownTime, updateFrequencyOfActors } from "./module.js";
import { showCooldownsOnSheet } from "./styling.js";

/**
Expand All @@ -14,14 +14,15 @@ import { showCooldownsOnSheet } from "./styling.js";
export async function updateItem(item, changes, _diff, _userID) {
const usesChange = changes?.system?.frequency?.value;
const maxUses = item?.system?.frequency?.max;
if (!maxUses) return;

// If uses are less than max, update or set cooldown flag
if (usesChange < maxUses) {
updateCooldownFlag(item);
}
// If uses are at or above max, remove cooldown flag
else if (usesChange && usesChange >= maxUses) {
} else if (usesChange && usesChange >= maxUses) {
// If uses are at or above max, remove cooldown flag
item.unsetFlag(MODULE_ID, "cooldown");
cooldownCache.delete(item.uuid);
}
}

Expand All @@ -31,8 +32,8 @@ export async function updateItem(item, changes, _diff, _userID) {
* @param {Object} item - The item to update the cooldown flag for.
*/
function updateCooldownFlag(item) {
const currentFlag = item.getFlag(MODULE_ID, "cooldown");
const frequencyPer = item?.system?.frequency?.per;
const currentFlag = cooldownCache.get(item.uuid) || item.getFlag(MODULE_ID, "cooldown");

const shouldUpdateFlag = !currentFlag ||
currentFlag.per !== frequencyPer ||
Expand All @@ -42,34 +43,34 @@ function updateCooldownFlag(item) {
if (shouldUpdateFlag) {
const cooldown = getCoolDownTime(item?.system?.frequency);
if (cooldown) {
item.setFlag(MODULE_ID, "cooldown", {
const newFlag = {
cooldown,
per: frequencyPer,
version: game.modules?.get(MODULE_ID)?.version
});
};
item.setFlag(MODULE_ID, "cooldown", newFlag);
cooldownCache.set(item.uuid, newFlag);
}
}
}


/**
* Updates the world time and refreshes frequency-based abilities for actors.
*
* @param {number} total - The total amount of time passed.
* @param {number} diff - The difference in time since the last update.
*/
export async function updateWorldTime(total, diff) {
// Get party members
let actors = game.actors.party.members;
if (!game.user.isGM) return;

// Include canvas tokens if the setting is enabled
if (game.settings.get(MODULE_ID, "include-canvas.enabled")) {
const canvasActors = getCanvasActors();
actors = actors.concat(canvasActors);
}
const actors = game.settings.get(MODULE_ID, "include-canvas.enabled")
? [...game.actors.party.members, ...getCanvasActors()]
: game.actors.party.members;

// Determine the update type based on combat status
const updateType = game.combat ? "default" : "updateTime";

// Update frequency-based abilities for all relevant actors
await updateFrequencyOfActors(actors, total, diff, updateType);
}
Expand Down
85 changes: 62 additions & 23 deletions scripts/module.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { DAY, HOUR, MINUTE, MODULE_ID, MONTH, WEEK, YEAR } from "./helper/const.js";
import { combatRound, updateItem, updateWorldTime } from "./hooks.js";

export const cooldownCache = new Map();

Hooks.once("ready", function () {
console.log("PF2E Uses Updater is Active");
if (!game.user.isGM) return;
Expand All @@ -21,15 +23,22 @@ Hooks.once("ready", function () {
* @param {string} [situation="default"] - The situation context.
* @returns {Promise<void>}
*/
export async function updateFrequencyOfActors(
party,
total,
diff,
situation = "default"
) {
export async function updateFrequencyOfActors(party, total, diff, situation = "default") {
const updates = [];
const specialCaseUpdates = [];

for (const character of party) {
await updateFrequency(character, total, diff, situation);
const { itemUpdates } = await processCharacterItems(character, total, diff, situation);
updates.push(...itemUpdates);
//specialCaseUpdates.push(...specialCases);
}

if (updates.length > 0) {
await Item.updateDocuments(updates);
}

// Handle special cases asynchronously
//specialCaseUpdates.forEach(update => update());
}

/**
Expand All @@ -43,7 +52,7 @@ export async function updateFrequencyOfActors(
export async function updateFrequency(character, total, diff, situation = "default") {
const items = character.items.contents;
const relevantItems = items.filter((it) =>
isItemRelevant(it, total, diff, situation)
['action', 'equipment'].includes(it.type) && isItemRelevant(it, total, diff, situation)
);
relevantItems.forEach((it) => {
it.unsetFlag(MODULE_ID, "cooldown");
Expand All @@ -59,6 +68,31 @@ export async function updateFrequency(character, total, diff, situation = "defau
}
}

async function processCharacterItems(character, total, diff, situation) {
const itemUpdates = [];
const specialCases = [];
const relevantItems = character.items.contents.filter(it => checkSpecialCases(it) || isItemRelevant(it, total, diff, situation));

for (const item of relevantItems) {
if (checkSpecialCases(it)) {
//specialCases.push(() => handleSpecialCase(item, total, diff, situation));
specialCases.push(item)
await handleSpecialCase(item, total, diff, situation)
} else {

item.unsetFlag(MODULE_ID, "cooldown");
itemUpdates.push({
_id: item.id,
"system.frequency.value": item.system.frequency?.max ?? 1
});


}
}

return { itemUpdates, specialCases };
}

/**
* Checks if an item is relevant for updating based on cooldown and situation.
* @param {Object} item - The item to check.
Expand All @@ -67,24 +101,25 @@ export async function updateFrequency(character, total, diff, situation = "defau
* @param {string} situation - The situation context.
* @returns {Promise<boolean>}
*/
export function isItemRelevant(item, total, diff, situation) {
if (!item?.getFlag(MODULE_ID, "cooldown")) updateItem(item, item, diff, null);
const { cooldown } = item?.getFlag(MODULE_ID, "cooldown") || {};
const isSpecialCase = checkAndHandleSpecialCase(item, total, diff, situation);
if (!cooldown && !isSpecialCase) return false;
function isItemRelevant(item, total, diff, situation) {
if (!cooldownCache.has(item.uuid)) {
const cooldown = item.getFlag(MODULE_ID, "cooldown")?.cooldown;
cooldownCache.set(item.uuid, cooldown);
}

const cooldown = cooldownCache.get(item.uuid);
if (!cooldown) return false;

const frequency = item.system.frequency;
if (!frequency || frequency.value >= frequency.max) return false;

switch (situation) {
case "updateTime":
return (
item?.system?.frequency?.value < item?.system?.frequency?.max &&
(cooldown <= total || ["turn", "round"].includes(cooldown))
);
return cooldown <= total || ["turn", "round"].includes(cooldown);
case "endRound":
return false; // TODO replace me with code for possibly handling longer cooldowns coming up mid combat?
return false; // TODO: Implement logic for handling longer cooldowns in combat
default:
return (
item?.system?.frequency?.value < item?.system?.frequency?.max &&
cooldown <= total
);
return cooldown <= total;
}
}

Expand Down Expand Up @@ -135,7 +170,7 @@ export function getCombatActor() {
* @param {string} _situation - The situation context (unused).
* @returns {Promise<boolean>}
*/
export async function checkAndHandleSpecialCase(item, _total, diff, _situation) {
export async function handleSpecialCase(item, _total, diff, _situation) {
const slug = item.system.slug;
const actor = item.actor;
switch (slug) {
Expand Down Expand Up @@ -170,3 +205,7 @@ export async function checkAndHandleSpecialCase(item, _total, diff, _situation)
}
return false;
}

export function checkSpecialCases(item) {
return ['aeon-stone-pearly-white-spindle'].includes(item.slug);
}

0 comments on commit 5158b19

Please sign in to comment.