diff --git a/module/actor/actor.js b/module/actor/actor.js index 2b01fb0..d4f7826 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -5037,13 +5037,19 @@ export class MothershipActor extends Actor { }; await this.update(updateData); const validIds = restrictedIds.filter(id => this.items.get(id) !== undefined); + let removed = 0; if (validIds.length) { - await this.deleteEmbeddedDocuments("Item", validIds); + try { + await this.deleteEmbeddedDocuments("Item", validIds); + removed = validIds.length; + } catch (err) { + // Concurrent enforcement calls may have already deleted these items — safe to ignore + } } - if (notify && validIds.length) { + if (notify && removed) { ui.notifications.warn(`${this.name} is not an Ebb user. Restricted Ebb skills and abilities were removed.`); } - return { removed: validIds.length }; + return { removed }; } const currentMax = Math.max(0, Number(this.system?.sla?.flux?.max ?? 0) || 0); diff --git a/module/mosh.js b/module/mosh.js index a554c46..4867f1e 100644 --- a/module/mosh.js +++ b/module/mosh.js @@ -144,11 +144,20 @@ Hooks.once('init', async function () { await SLADrugSystem.handleEffectDeleted(effect, options); }); - Hooks.on("createItem", async (item) => { + // Debounce map: actorId → pending timeout handle. + // Prevents enforceSlaEbbEligibility from being called once per item when the + // character generator creates many items in rapid succession (each createItem + // hook call would otherwise race to delete the same Ebb items concurrently). + const _pendingEbbEnforcement = new Map(); + Hooks.on("createItem", (item) => { const actor = item.parent; if (!actor || actor.type !== "character" || typeof actor.enforceSlaEbbEligibility !== "function") return; if (actor.isSlaEbbUser?.()) return; - await actor.enforceSlaEbbEligibility({ notify: true, refillFlux: false }); + if (_pendingEbbEnforcement.has(actor.id)) clearTimeout(_pendingEbbEnforcement.get(actor.id)); + _pendingEbbEnforcement.set(actor.id, setTimeout(async () => { + _pendingEbbEnforcement.delete(actor.id); + await actor.enforceSlaEbbEligibility({ notify: true, refillFlux: false }); + }, 300)); }); Hooks.on("updateActor", async (actor, changes, options) => {