From edd1819c868187ea508342fd9c4099443939a229 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Sun, 9 Aug 2026 08:31:09 +0200 Subject: [PATCH] =?UTF-8?q?fix(chat):=20relance=20des=20d=C3=A9s=20accessi?= =?UTF-8?q?ble=20aux=20joueurs=20sur=20Foundry=20v14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Correction du check d'autorisation : message.user -> message.author (champ renommé en v12+, message.user est undefined sur v14) - Les joueurs ne peuvent plus mettre à jour les ChatMessages (permission OWNER, option Modifier retirée du menu contextuel en v12+) : la relance (dé et effort) est relayée via le socket system.vermine2047 et appliquée par le client MJ (registerRerollSocket), avec vérification de l'auteur - Ajout de la déclaration "socket": true au system.json (requise par le serveur pour écouter le namespace system.) --- module/system/hooks.mjs | 6 ++-- module/system/roll.mjs | 72 ++++++++++++++++++++++++++++++++++------- system.json | 1 + 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/module/system/hooks.mjs b/module/system/hooks.mjs index a3662d4..e4c6b16 100644 --- a/module/system/hooks.mjs +++ b/module/system/hooks.mjs @@ -67,9 +67,9 @@ export const registerHooks = function () { } }) Hooks.once("ready", async () => { - // System initialized - //await registerTours(); - + // Relays player rerolls to the GM client (Foundry v14 ChatMessage + // updates are GM-only). + VermineUtils.registerRerollSocket(); }); // changement de la pause diff --git a/module/system/roll.mjs b/module/system/roll.mjs index 03b14bb..57a6e39 100644 --- a/module/system/roll.mjs +++ b/module/system/roll.mjs @@ -204,9 +204,10 @@ export class VermineUtils { * @returns {Promise} Whether the reroll was successful */ static async onReroll(message, target) { - // Verify user permissions - const msgUserId = message.user?.id ?? message.user; - if (msgUserId !== game.user?.id && !game.user?.isGM) { + // Verify user permissions. Foundry v14 renamed the ChatMessage field + // `user` to `author`, so `message.user` is undefined on this core. + const msgAuthorId = message.author?.id ?? message.user?.id ?? message.user; + if (msgAuthorId !== game.user?.id && !game.user?.isGM) { ui.notifications.warn(game.i18n.localize('VERMINE.error_cannot_reroll')); return false; } @@ -231,9 +232,6 @@ export class VermineUtils { target.classList.add('rerolled'); - // Set reroll flag - await message.setFlag("world", "reroll", true); - // Get difficulty and dice type const ulElement = target.closest('ul'); const difficulty = ulElement?.dataset.difficulty ?? 7; @@ -331,14 +329,55 @@ export class VermineUtils { + mk('adapted', stats.adapted.count, stats.adapted.success); } - await message.update({ - content: messageContent.outerHTML - }); + // Persist the reroll. The GM writes the message directly ; players + // cannot update ChatMessages on Foundry v14 (permission "OWNER"), so + // their reroll is relayed through the system socket and applied by the + // GM client (see registerRerollSocket). + if (game.user?.isGM) { + await message.setFlag("world", "reroll", true); + await message.update({ + content: messageContent.outerHTML + }); + } else { + game.socket?.emit(`system.${game.system.id}`, { + type: "reroll", + messageId: message.id, + requestId: foundry.utils.randomID(8), + content: messageContent.outerHTML + }); + } } return true; } + /** + * Registers the system socket listener which applies rerolls requested by + * players. Foundry v14 only allows GMs to update ChatMessages, so player + * rerolls are relayed to the GM client through `system.` (see onReroll). + * Call once after the world is ready; re-registration replaces the handler. + */ + static registerRerollSocket() { + const eventName = `system.${game.system.id}`; + const handler = async (payload, userId) => { + if (!game.user?.isGM) return; + if (payload?.type !== "reroll") return; + const message = game.messages.get(payload.messageId); + if (!message) return; + // Security: only the message author may request the reroll update. + if (message.author?.id !== userId) return; + await message.setFlag("world", "reroll", true); + await message.update({ content: payload.content }); + }; + if (VermineUtils.#rerollSocketHandler) { + game.socket?.off(eventName, VermineUtils.#rerollSocketHandler); + } + VermineUtils.#rerollSocketHandler = handler; + game.socket?.on(eventName, handler); + } + + static #rerollSocketHandler; + /** * Sets up event listeners for chat messages. * @param {HTMLElement} html - The HTML element containing chat events. @@ -396,8 +435,19 @@ export class VermineUtils { const rollMessage = btn.closest(".vermine-roll-message"); if (rollMessage) { const content = rollMessage.outerHTML; - const message = await game.messages.get(messageId); - await message.update({ content: content }); + // GM applies the update directly ; players relay through the + // system socket (Foundry v14 ChatMessage updates are GM-only). + if (game.user?.isGM) { + const message = await game.messages.get(messageId); + await message.update({ content: content }); + } else { + game.socket?.emit(`system.${game.system.id}`, { + type: "reroll", + messageId: messageId, + requestId: foundry.utils.randomID(8), + content: content + }); + } } } }); diff --git a/system.json b/system.json index f1ebd3f..383dd4a 100644 --- a/system.json +++ b/system.json @@ -168,6 +168,7 @@ "distance": 1, "units": "m" }, + "socket": true, "primaryTokenAttribute": "health", "secondaryTokenAttribute": "power", "url": "https://www.uberwald.me/gitea/uberwald/vermine2047",