From 7c88abf1860549912f4552062aa2dd354e1ec3a6 Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 12:17:54 -0600 Subject: [PATCH 01/10] Socket Implementation Created a socket handler --- module.json | 1 + scripts/helpers/SocketHandler.js | 21 +++++++++++++++++++++ scripts/helpers/global.js | 8 ++++++++ scripts/helpers/settings.js | 11 +++++++++++ scripts/init.js | 4 ++++ scripts/ui/questeditor.js | 28 ++++++++++++++++++++-------- scripts/ui/questtracker.js | 4 +++- 7 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 scripts/helpers/SocketHandler.js diff --git a/module.json b/module.json index 86bed0f..2b7bc92 100644 --- a/module.json +++ b/module.json @@ -33,6 +33,7 @@ "styles": ["styles/style.css", "styles/editor.css", "styles/tracker.css"], "minimumCoreVersion": "12", "compatibleCoreVersion": "12", + "socket": true, "url": "https://github.com/MythicPalette/simpler-quests", "manifest": "https://github.com/MythicPalette/simpler-quests/releases/latest/download/module.json", "download": "https://github.com/MythicPalette/simpler-quests/releases/download/v0.1.7/module.zip" diff --git a/scripts/helpers/SocketHandler.js b/scripts/helpers/SocketHandler.js new file mode 100644 index 0000000..0ead2d2 --- /dev/null +++ b/scripts/helpers/SocketHandler.js @@ -0,0 +1,21 @@ +import { constants } from "./global.js"; + +export class SocketHandler { + identifier = `module.simpler-quests`; + + constructor() { + this.registerSocketListeners(); + } + + registerSocketListeners() { + game.socket?.on(this.identifier, (data) => { + console.log(data); + }); + } + + emit(data) { + console.log(`Emitting: ${data}`); + const sock = game.socket; + if (sock) return sock.emit(this.identifier, data); + } +} diff --git a/scripts/helpers/global.js b/scripts/helpers/global.js index 3a5b251..9cae587 100644 --- a/scripts/helpers/global.js +++ b/scripts/helpers/global.js @@ -30,3 +30,11 @@ export function gmCheck() { } return true; } + +var _sock; +export function getSocket() { + return _sock; +} +export function setSocket(socket) { + _sock = socket; +} diff --git a/scripts/helpers/settings.js b/scripts/helpers/settings.js index 7078390..cc5e6fc 100644 --- a/scripts/helpers/settings.js +++ b/scripts/helpers/settings.js @@ -15,6 +15,7 @@ export class Settings { TRACKER_POS: "trackerWindowPosition", TRACKER_OPEN: "trackerWindowOpen", TRACKER_HIDE: "trackerHideFromPlayers", + PLAYER_EDIT: "playersEditQuest", }); static registerSettings() { @@ -36,6 +37,16 @@ export class Settings { requiresReload: true, }); + game.settings.register(constants.moduleName, this.NAMES.PLAYER_EDIT, { + name: "SimplerQuests.Settings.PlayerEdit.Name", + hint: "SimplerQuests.Settings.PlayerEdit.Hint", + scope: "world", + type: Boolean, + default: false, + config: true, + requiresReload: true, + }); + game.settings.register( constants.moduleName, this.NAMES.QUEST_VIEW_STYLE, diff --git a/scripts/init.js b/scripts/init.js index 148e102..06d7700 100644 --- a/scripts/init.js +++ b/scripts/init.js @@ -3,6 +3,8 @@ import { UIManager } from "./ui/ui-manager.js"; import { Settings } from "./helpers/settings.js"; import { HandlebarHelper } from "./helpers/handlebars.js"; import { SimplerQuestsAPI } from "./api.js"; +import { setSocket } from "./helpers/global.js"; +import { SocketHandler } from "./helpers/socketHandler.js"; Hooks.once("init", (opts) => { // Start by registering the module settings. @@ -13,6 +15,8 @@ Hooks.once("init", (opts) => { // Prepare the quest tracker. UIManager.init(); + + setSocket(new SocketHandler()); }); Hooks.on("ready", async () => { diff --git a/scripts/ui/questeditor.js b/scripts/ui/questeditor.js index fbcc045..66e7616 100644 --- a/scripts/ui/questeditor.js +++ b/scripts/ui/questeditor.js @@ -1,4 +1,4 @@ -import { constants, objectiveState } from "../helpers/global.js"; +import { constants, getSocket, objectiveState } from "../helpers/global.js"; import { QuestDatabase } from "../data/database.js"; import { Quest } from "../data/quest.js"; import { Objective } from "../data/objective.js"; @@ -94,18 +94,30 @@ export class QuestEditor extends Application { .find("#objective-display-select > .selection-bar > .body") .data("value"); - let q = new Quest({ + // Prepare the quest data + let qData = { id: this.quest.id, title: title, objectives: objs, viewStyle: selectBody, visible: this.quest.visible, - }); - - QuestDatabase.InsertOrUpdate(q); - console.log(q); - UIManager.tracker.render(); - this.close(); + }; + + // If the user is the GM then save the quest + // TODO Flip this by removing the ! + if (!game.user.isGM) { + let q = new Quest(qData); + + QuestDatabase.InsertOrUpdate(q); + console.log(q); + UIManager.tracker.render(); + this.close(); + } else { + getSocket().emit({ + type: "InsertOrUpdate", + data: qData, + }); + } }); // Quest visibility toggle. diff --git a/scripts/ui/questtracker.js b/scripts/ui/questtracker.js index 30586e8..05aa19a 100644 --- a/scripts/ui/questtracker.js +++ b/scripts/ui/questtracker.js @@ -1,4 +1,4 @@ -import { constants } from "../helpers/global.js"; +import { constants, getSocket } from "../helpers/global.js"; import { QuestDatabase } from "../data/database.js"; import { QuestEditor } from "./questeditor.js"; import { objectiveState } from "../helpers/global.js"; @@ -146,6 +146,8 @@ export class QuestTracker extends Application { $html.find(".minimize").on("click", (evt) => { evt.stopPropagation(); this.collapse(); + let result = getSocket().emit({ type: "TEST" }); + console.log(result); }); // Expand/Collapse quest bodies. From 3cf90e93cc44cba7b1e582c9c17db185ce2148e5 Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 12:34:31 -0600 Subject: [PATCH 02/10] Player Edits Players can now edit existing quests. --- scripts/helpers/SocketHandler.js | 17 +++++++++++++++-- scripts/ui/questeditor.js | 2 +- scripts/ui/questtracker.js | 5 ++++- templates/tracker-body.hbs | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/scripts/helpers/SocketHandler.js b/scripts/helpers/SocketHandler.js index 0ead2d2..2534f76 100644 --- a/scripts/helpers/SocketHandler.js +++ b/scripts/helpers/SocketHandler.js @@ -1,4 +1,7 @@ import { constants } from "./global.js"; +import { Quest } from "../data/quest.js"; +import { QuestDatabase } from "../data/database.js"; +import { UIManager } from "../ui/ui-manager.js"; export class SocketHandler { identifier = `module.simpler-quests`; @@ -8,8 +11,8 @@ export class SocketHandler { } registerSocketListeners() { - game.socket?.on(this.identifier, (data) => { - console.log(data); + game.socket?.on(this.identifier, (ev) => { + if (ev.type === "InsertOrUpdate") this.#OnQuestEdit(ev.data); }); } @@ -18,4 +21,14 @@ export class SocketHandler { const sock = game.socket; if (sock) return sock.emit(this.identifier, data); } + + #OnQuestEdit(data) { + if (!game.user.isGM) return; + + console.log(`Received quest data: ${data}`); + let q = new Quest(data); + QuestDatabase.InsertOrUpdate(q); + console.log(q); + UIManager.tracker.render(); + } } diff --git a/scripts/ui/questeditor.js b/scripts/ui/questeditor.js index 66e7616..a083c28 100644 --- a/scripts/ui/questeditor.js +++ b/scripts/ui/questeditor.js @@ -105,7 +105,7 @@ export class QuestEditor extends Application { // If the user is the GM then save the quest // TODO Flip this by removing the ! - if (!game.user.isGM) { + if (game.user.isGM) { let q = new Quest(qData); QuestDatabase.InsertOrUpdate(q); diff --git a/scripts/ui/questtracker.js b/scripts/ui/questtracker.js index 05aa19a..dce8839 100644 --- a/scripts/ui/questtracker.js +++ b/scripts/ui/questtracker.js @@ -92,6 +92,7 @@ export class QuestTracker extends Application { collapsed: this.collapsed, quests: QuestDatabase.quests, isGM: game.user.isGM, + canEdit: game.user.isGM || Settings.get(Settings.NAMES.PLAYER_EDIT), activeQuests: this.activeQuests, offset: `${Settings.get(Settings.NAMES.TRACKER_OFFSET) / 16}rem`, docked: Settings.get(Settings.NAMES.TRACKER_DOCKED), @@ -193,7 +194,9 @@ export class QuestTracker extends Application { }); // All of the listeners beyond this point are for the GM only. - if (!game.user.isGM) return; + if (!game.user.isGM && !Settings.get(Settings.NAMES.PLAYER_EDIT)) + return; + // Progress the state of an objective. $html.find(".simpler-quest-objective").on("click", (evt) => { evt.stopPropagation(); diff --git a/templates/tracker-body.hbs b/templates/tracker-body.hbs index 805271d..2267882 100644 --- a/templates/tracker-body.hbs +++ b/templates/tracker-body.hbs @@ -5,7 +5,7 @@

{{this.title}}

- {{#if ../isGM}} + {{#if ../canEdit}} {{#if this.visible}}
{{else}} From 523d39a1d3b5b89e958a60913e1a74c688a9b397 Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 12:36:20 -0600 Subject: [PATCH 03/10] More Settings Added settings for creating quests and marking objectives. --- scripts/helpers/settings.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/scripts/helpers/settings.js b/scripts/helpers/settings.js index cc5e6fc..7405a3e 100644 --- a/scripts/helpers/settings.js +++ b/scripts/helpers/settings.js @@ -16,6 +16,8 @@ export class Settings { TRACKER_OPEN: "trackerWindowOpen", TRACKER_HIDE: "trackerHideFromPlayers", PLAYER_EDIT: "playersEditQuest", + PLAYER_CREATE: "playersCreateQuest", + PLAYER_MARK: "playersMarkObjectives", }); static registerSettings() { @@ -47,6 +49,26 @@ export class Settings { requiresReload: true, }); + game.settings.register(constants.moduleName, this.NAMES.PLAYER_CREATE, { + name: "SimplerQuests.Settings.PlayerCreate.Name", + hint: "SimplerQuests.Settings.PlayerCreate.Hint", + scope: "world", + type: Boolean, + default: false, + config: true, + requiresReload: true, + }); + + game.settings.register(constants.moduleName, this.NAMES.PLAYER_MARK, { + name: "SimplerQuests.Settings.PlayersMark.Name", + hint: "SimplerQuests.Settings.PlayersMark.Hint", + scope: "world", + type: Boolean, + default: false, + config: true, + requiresReload: true, + }); + game.settings.register( constants.moduleName, this.NAMES.QUEST_VIEW_STYLE, From 3755834c71aabf2881751c16fcb87ddcea80788b Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 12:50:02 -0600 Subject: [PATCH 04/10] Visibility Quests created by players are always visible Players no-longer have access to creating hidden quests. --- scripts/ui/questeditor.js | 4 ++++ scripts/ui/questtracker.js | 2 ++ scripts/ui/ui-manager.js | 3 ++- templates/editor.hbs | 2 ++ templates/tracker-body.hbs | 10 ++++++---- templates/tracker-dock.hbs | 2 +- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/scripts/ui/questeditor.js b/scripts/ui/questeditor.js index a083c28..7a9fe68 100644 --- a/scripts/ui/questeditor.js +++ b/scripts/ui/questeditor.js @@ -33,6 +33,7 @@ export class QuestEditor extends Application { } } else { this.#quest = new Quest(); + if (!game.user.isGM) this.#quest.visible = true; } } @@ -117,6 +118,8 @@ export class QuestEditor extends Application { type: "InsertOrUpdate", data: qData, }); + UIManager.tracker.render(); + this.close(); } }); @@ -136,6 +139,7 @@ export class QuestEditor extends Application { Settings.get(Settings.NAMES.QUEST_VIEW_STYLE); return foundry.utils.mergeObject(super.getData(), { + isGM: game.user.isGM, title: "Quest Editor Test", questTitle: this.quest.title, objectives: Quest.stringify(this.quest), diff --git a/scripts/ui/questtracker.js b/scripts/ui/questtracker.js index dce8839..1cf53b8 100644 --- a/scripts/ui/questtracker.js +++ b/scripts/ui/questtracker.js @@ -93,6 +93,8 @@ export class QuestTracker extends Application { quests: QuestDatabase.quests, isGM: game.user.isGM, canEdit: game.user.isGM || Settings.get(Settings.NAMES.PLAYER_EDIT), + canCreate: + game.user.isGM || Settings.get(Settings.NAMES.PLAYER_CREATE), activeQuests: this.activeQuests, offset: `${Settings.get(Settings.NAMES.TRACKER_OFFSET) / 16}rem`, docked: Settings.get(Settings.NAMES.TRACKER_DOCKED), diff --git a/scripts/ui/ui-manager.js b/scripts/ui/ui-manager.js index 43a1016..7cd9797 100644 --- a/scripts/ui/ui-manager.js +++ b/scripts/ui/ui-manager.js @@ -69,7 +69,8 @@ export class UIManager { buttons[0].tooltip = buttons[0].label; buttons[0].label = null; - if (game.user.isGM) buttons.unshift(...UIManager.headerButtons); + if (game.user.isGM || Settings.get(Settings.NAMES.PLAYER_CREATE)) + buttons.unshift(...UIManager.headerButtons); } } } diff --git a/templates/editor.hbs b/templates/editor.hbs index f46d209..a8484a0 100644 --- a/templates/editor.hbs +++ b/templates/editor.hbs @@ -9,6 +9,7 @@ data-quest-id="{{this.id}}" value="{{this.questTitle}}" /> + {{#if this.isGM}}
{{#if this.visible}} @@ -16,6 +17,7 @@ {{/if}}
+ {{/if}}
diff --git a/templates/tracker-body.hbs b/templates/tracker-body.hbs index 2267882..5fc01e0 100644 --- a/templates/tracker-body.hbs +++ b/templates/tracker-body.hbs @@ -6,10 +6,12 @@

{{this.title}}

{{#if ../canEdit}} - {{#if this.visible}} -
- {{else}} -
+ {{#if ../isGM}} + {{#if this.visible}} +
+ {{else}} +
+ {{/if}} {{/if}}
diff --git a/templates/tracker-dock.hbs b/templates/tracker-dock.hbs index cbcee14..354fed7 100644 --- a/templates/tracker-dock.hbs +++ b/templates/tracker-dock.hbs @@ -6,7 +6,7 @@ {{else}}

{{localize 'SimplerQuests.Tracker.ActiveQuests'}}

- {{#if isGM}} + {{#if canCreate}}
{{/if}}
From f37d44d5ae42c1343a01fe9e21d7f8c00c313ded Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 13:00:25 -0600 Subject: [PATCH 05/10] Update Objective Players can now update objectives with permission Ensured players cannot mark objectives as secret. --- scripts/helpers/SocketHandler.js | 6 ++ scripts/ui/questtracker.js | 98 ++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/scripts/helpers/SocketHandler.js b/scripts/helpers/SocketHandler.js index 2534f76..ce35a78 100644 --- a/scripts/helpers/SocketHandler.js +++ b/scripts/helpers/SocketHandler.js @@ -13,6 +13,8 @@ export class SocketHandler { registerSocketListeners() { game.socket?.on(this.identifier, (ev) => { if (ev.type === "InsertOrUpdate") this.#OnQuestEdit(ev.data); + else if (ev.type == "UpdateObjective") + this.#OnUpdateObjective(ev.data); }); } @@ -31,4 +33,8 @@ export class SocketHandler { console.log(q); UIManager.tracker.render(); } + + #OnUpdateObjective(data) { + Quest.updateObjective(data.questId, data.objId, "state"); + } } diff --git a/scripts/ui/questtracker.js b/scripts/ui/questtracker.js index 1cf53b8..412d465 100644 --- a/scripts/ui/questtracker.js +++ b/scripts/ui/questtracker.js @@ -195,7 +195,7 @@ export class QuestTracker extends Application { this.render(); }); - // All of the listeners beyond this point are for the GM only. + // All of the listeners beyond this point require permission. if (!game.user.isGM && !Settings.get(Settings.NAMES.PLAYER_EDIT)) return; @@ -214,44 +214,29 @@ export class QuestTracker extends Application { // Update the objective state const questId = evt.target.closest("[data-quest-id]").dataset.questId; - Quest.updateObjective(questId, objId, "state"); + + if (game.user.isGM) Quest.updateObjective(questId, objId, "state"); + else if (Settings.get(Settings.NAMES.PLAYER_MARK)) { + getSocket().emit({ + type: "UpdateObjective", + data: { + questId: questId, + objId: objId, + key: "state", + }, + }); + } }); - // Toggle the Secret status of an objective. - $html.find(".simpler-quest-objective").on("contextmenu", (evt) => { + // Create a new quest. + $html.find(".header > .new-quest").on("click", (evt) => { evt.stopPropagation(); - evt.preventDefault(); - // Get the object ID. - const objId = getObjectiveId(evt.target); - if (!objId) return; - - // Update the objective secret - const questId = - evt.target.closest("[data-quest-id]").dataset.questId; - Quest.updateObjective(questId, objId, "secret"); + // Load a blank QuestEditor and render. + let qe = new QuestEditor(); + qe.render(true, { focus: true }); }); - // Toggle the visibility of quests. - $html - .find(".simpler-tracked-quest > .header > .vis-toggle") - .on("click", (evt) => { - evt.stopPropagation(); - - // Get the quest data. - const data = getQuestData(evt.target); - - // If the quest data is valid - if (data.quest) { - // Set the quest visibility and save. - QuestDatabase.update({ - ...data.quest, - visible: !data.quest.visible, - }); - QuestDatabase.save(); - } - }); - // Edit a quest's data. $html .find(".simpler-tracked-quest > .header > .edit") @@ -267,15 +252,6 @@ export class QuestTracker extends Application { qe.render(true, { focus: true }); }); - // Create a new quest. - $html.find(".header > .new-quest").on("click", (evt) => { - evt.stopPropagation(); - - // Load a blank QuestEditor and render. - let qe = new QuestEditor(); - qe.render(true, { focus: true }); - }); - // Delete a quest. $html .find(".simpler-tracked-quest > .header > .delete") @@ -302,6 +278,44 @@ export class QuestTracker extends Application { QuestDatabase.removeQuest(data.questId); } }); + + // All listeners beyond this point work only for GM. + if (!game.user.isGM) return; + + // Toggle the visibility of quests. + $html + .find(".simpler-tracked-quest > .header > .vis-toggle") + .on("click", (evt) => { + evt.stopPropagation(); + + // Get the quest data. + const data = getQuestData(evt.target); + + // If the quest data is valid + if (data.quest) { + // Set the quest visibility and save. + QuestDatabase.update({ + ...data.quest, + visible: !data.quest.visible, + }); + QuestDatabase.save(); + } + }); + + // Toggle the Secret status of an objective. + $html.find(".simpler-quest-objective").on("contextmenu", (evt) => { + evt.stopPropagation(); + evt.preventDefault(); + + // Get the object ID. + const objId = getObjectiveId(evt.target); + if (!objId) return; + + // Update the objective secret + const questId = + evt.target.closest("[data-quest-id]").dataset.questId; + Quest.updateObjective(questId, objId, "secret"); + }); } refresh() { From 02303c5af26a76b4fdbd3f7d6ab371d9b154870f Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 13:17:39 -0600 Subject: [PATCH 06/10] Updated language files Updated en.json Updated de.json Added quest GMQuest flag --- lang/de.json | 12 ++++++++++++ lang/en.json | 12 ++++++++++++ scripts/data/quest.js | 1 + scripts/ui/questeditor.js | 5 ++++- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lang/de.json b/lang/de.json index b3ad78b..b0f554c 100644 --- a/lang/de.json +++ b/lang/de.json @@ -51,6 +51,18 @@ "TrackerMaxHeight": { "Name": "Quest-Log Max Höhe", "Hint": "Legt die maximale Höhe (in Pixeln) des Quest-Logs fest, wenn es angedockt ist. Hat keine Auswirkung, wenn schwebend." + }, + "PlayerEdit": { + "Name": "Spieler bearbeiten erlauben", + "Hint": "Erlaube Spielern, Quests zu bearbeiten. Achtung, dies ermöglicht es den Spielern, Eintragsdaten für Ziele zu sehen, was geheime Ziele offenbaren könnte." + }, + "PlayerCreate": { + "Name": "Spieler erstellen erlauben", + "Hint": "Erlaube Spielern, Quests zu erstellen." + }, + "PlayersMark": { + "Name": "Spielern erlauben, Ziele zu markieren", + "Hint": "Erlaube Spielern, Ziele als abgeschlossen, gescheitert oder unvollständig zu markieren." } }, "Tracker": { diff --git a/lang/en.json b/lang/en.json index 959e4cb..d4c885d 100644 --- a/lang/en.json +++ b/lang/en.json @@ -51,6 +51,18 @@ "TrackerMaxHeight": { "Name": "Tracker Max Height", "Hint": "Sets the max height (in pixels) of the tracker while docked. Has no effect if not docked." + }, + "PlayerEdit": { + "Name": "Allow Player Edits", + "Hint": "Allow players to edit quests. Warning, this will allow players to see objective entry data, potentially revealing secret objectives." + }, + "PlayerCreate": { + "Name": "Allow Player Create", + "Hint": "Allow players to create quests." + }, + "PlayersMark": { + "Name": "Allow Players to Mark Objectives", + "Hint": "Allow players to mark objectives as complete, failed, or incomplete." } }, "Tracker": { diff --git a/scripts/data/quest.js b/scripts/data/quest.js index 561b43f..655669b 100644 --- a/scripts/data/quest.js +++ b/scripts/data/quest.js @@ -16,6 +16,7 @@ export class Quest { this.objectives = []; this.viewStyle = data.viewStyle || Settings.get(Settings.NAMES.QUEST_VIEW_STYLE); + this.GMQuest = data.GMQuest || true; // Default to GM-made quests. // Go through the objectives in the data and create them. if (data.objectives) { diff --git a/scripts/ui/questeditor.js b/scripts/ui/questeditor.js index 7a9fe68..6913053 100644 --- a/scripts/ui/questeditor.js +++ b/scripts/ui/questeditor.js @@ -33,7 +33,10 @@ export class QuestEditor extends Application { } } else { this.#quest = new Quest(); - if (!game.user.isGM) this.#quest.visible = true; + if (!game.user.isGM) { + this.#quest.visible = true; + this.#quest.GMQuest = false; + } } } From ecad8d10d022d558e8eef72b5b58a08a879153cb Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 13:36:54 -0600 Subject: [PATCH 07/10] GM vs Player Quests The system now marks the difference between GM-made quests and Player-Made quests, allowing finer control over permissions. --- lang/de.json | 14 +++++++------- lang/en.json | 12 ++++++------ scripts/data/database.js | 15 ++++++++++++++- scripts/data/quest.js | 2 +- scripts/helpers/SocketHandler.js | 4 ++-- scripts/ui/questeditor.js | 1 + templates/tracker-body.hbs | 14 +++++++------- 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/lang/de.json b/lang/de.json index b0f554c..5675f68 100644 --- a/lang/de.json +++ b/lang/de.json @@ -52,17 +52,17 @@ "Name": "Quest-Log Max Höhe", "Hint": "Legt die maximale Höhe (in Pixeln) des Quest-Logs fest, wenn es angedockt ist. Hat keine Auswirkung, wenn schwebend." }, - "PlayerEdit": { - "Name": "Spieler bearbeiten erlauben", - "Hint": "Erlaube Spielern, Quests zu bearbeiten. Achtung, dies ermöglicht es den Spielern, Eintragsdaten für Ziele zu sehen, was geheime Ziele offenbaren könnte." - }, "PlayerCreate": { "Name": "Spieler erstellen erlauben", - "Hint": "Erlaube Spielern, Quests zu erstellen." + "Hint": "Erlaube es den Spielern, Quests zu erstellen." + }, + "PlayerEdit": { + "Name": "Spielern erlauben, GM-Quests zu bearbeiten", + "Hint": "Erlaube es den Spielern, Quests des GM zu bearbeiten. Achtung, dies ermöglicht es den Spielern, die Eingabedaten der Ziele zu sehen, was möglicherweise geheime Ziele enthüllt." }, "PlayersMark": { - "Name": "Spielern erlauben, Ziele zu markieren", - "Hint": "Erlaube Spielern, Ziele als abgeschlossen, gescheitert oder unvollständig zu markieren." + "Name": "Spielern erlauben, GM-Ziele zu markieren", + "Hint": "Erlaube es den Spielern, die Ziele der Quests des GM als abgeschlossen, fehlgeschlagen oder unvollständig zu markieren." } }, "Tracker": { diff --git a/lang/en.json b/lang/en.json index d4c885d..77e04d1 100644 --- a/lang/en.json +++ b/lang/en.json @@ -52,17 +52,17 @@ "Name": "Tracker Max Height", "Hint": "Sets the max height (in pixels) of the tracker while docked. Has no effect if not docked." }, - "PlayerEdit": { - "Name": "Allow Player Edits", - "Hint": "Allow players to edit quests. Warning, this will allow players to see objective entry data, potentially revealing secret objectives." - }, "PlayerCreate": { "Name": "Allow Player Create", "Hint": "Allow players to create quests." }, + "PlayerEdit": { + "Name": "Allow Players to Edit GM Quests", + "Hint": "Allow players to edit quests made by the GM. Warning, this will allow players to see objective entry data, potentially revealing secret objectives." + }, "PlayersMark": { - "Name": "Allow Players to Mark Objectives", - "Hint": "Allow players to mark objectives as complete, failed, or incomplete." + "Name": "Allow Players to Mark GM Objectives", + "Hint": "Allow players to mark the objectives of quests made by the GM as complete, failed, or incomplete." } }, "Tracker": { diff --git a/scripts/data/database.js b/scripts/data/database.js index e388cd5..14612a4 100644 --- a/scripts/data/database.js +++ b/scripts/data/database.js @@ -50,6 +50,11 @@ export class QuestDatabase extends Collection { } } + q.canEdit = + game.user.isGM || + Settings.get(Settings.NAMES.PLAYER_EDIT) || + !q.GMQuest; + // Return the quest with modified data. return { ...q, @@ -191,8 +196,16 @@ export class QuestDatabase extends Collection { static refresh() { this.#quests = Settings.get(Settings.NAMES.QUEST_DB).quests; - // Verify that all quest objectives have an id + // Validate all quest data. this.#quests.forEach((q, i) => { + // For backwards compatability, if a quest + // does not have the GMQuest flag, add it. + if (!("GMQuest" in q)) { + q.GMQuest = true; + console.log(q); + } + + // Ensure that all quest objectives have an id if (q.objectives) this.#quests[i] = { ...q, diff --git a/scripts/data/quest.js b/scripts/data/quest.js index 655669b..e745a9c 100644 --- a/scripts/data/quest.js +++ b/scripts/data/quest.js @@ -16,7 +16,7 @@ export class Quest { this.objectives = []; this.viewStyle = data.viewStyle || Settings.get(Settings.NAMES.QUEST_VIEW_STYLE); - this.GMQuest = data.GMQuest || true; // Default to GM-made quests. + this.GMQuest = "GMQuest" in data ? data.GMQuest : true; // Default to GM-made quests. // Go through the objectives in the data and create them. if (data.objectives) { diff --git a/scripts/helpers/SocketHandler.js b/scripts/helpers/SocketHandler.js index ce35a78..ec3c257 100644 --- a/scripts/helpers/SocketHandler.js +++ b/scripts/helpers/SocketHandler.js @@ -12,7 +12,7 @@ export class SocketHandler { registerSocketListeners() { game.socket?.on(this.identifier, (ev) => { - if (ev.type === "InsertOrUpdate") this.#OnQuestEdit(ev.data); + if (ev.type === "InsertOrUpdate") this.#OnInsertOrUpdate(ev.data); else if (ev.type == "UpdateObjective") this.#OnUpdateObjective(ev.data); }); @@ -24,7 +24,7 @@ export class SocketHandler { if (sock) return sock.emit(this.identifier, data); } - #OnQuestEdit(data) { + #OnInsertOrUpdate(data) { if (!game.user.isGM) return; console.log(`Received quest data: ${data}`); diff --git a/scripts/ui/questeditor.js b/scripts/ui/questeditor.js index 6913053..e2bfca9 100644 --- a/scripts/ui/questeditor.js +++ b/scripts/ui/questeditor.js @@ -105,6 +105,7 @@ export class QuestEditor extends Application { objectives: objs, viewStyle: selectBody, visible: this.quest.visible, + GMQuest: this.quest.GMQuest, }; // If the user is the GM then save the quest diff --git a/templates/tracker-body.hbs b/templates/tracker-body.hbs index 5fc01e0..5e04303 100644 --- a/templates/tracker-body.hbs +++ b/templates/tracker-body.hbs @@ -5,14 +5,14 @@

{{this.title}}

- {{#if ../canEdit}} - {{#if ../isGM}} - {{#if this.visible}} -
- {{else}} -
- {{/if}} + {{#if ../isGM}} + {{#if this.visible}} +
+ {{else}} +
{{/if}} + {{/if}} + {{#if canEdit}}
{{/if}} From fb2937f0983f1a432b6c6efc349947433f5734bb Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 13:40:13 -0600 Subject: [PATCH 08/10] Include User Socket emission now flags the data with the user who sent it. --- scripts/helpers/SocketHandler.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/helpers/SocketHandler.js b/scripts/helpers/SocketHandler.js index ec3c257..5a937b9 100644 --- a/scripts/helpers/SocketHandler.js +++ b/scripts/helpers/SocketHandler.js @@ -20,6 +20,10 @@ export class SocketHandler { emit(data) { console.log(`Emitting: ${data}`); + + // Add the user to the data for tracking who sent the data. + data.user = game.user; + const sock = game.socket; if (sock) return sock.emit(this.identifier, data); } From a5e155689664a28d4e223822ab139fdae42b83e0 Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 14:22:53 -0600 Subject: [PATCH 09/10] canDelete Disabled the ability of users to delete GM quests. Fixed a bug where disallowing edits but allowing marking would prevent marking from working. --- scripts/data/database.js | 3 +++ scripts/helpers/SocketHandler.js | 43 ++++++++++++++++++++++++++------ scripts/helpers/settings.js | 12 ++++----- scripts/ui/questeditor.js | 5 +--- scripts/ui/questtracker.js | 29 +++++++++++---------- templates/tracker-body.hbs | 2 ++ 6 files changed, 62 insertions(+), 32 deletions(-) diff --git a/scripts/data/database.js b/scripts/data/database.js index 14612a4..a2f5baa 100644 --- a/scripts/data/database.js +++ b/scripts/data/database.js @@ -55,6 +55,9 @@ export class QuestDatabase extends Collection { Settings.get(Settings.NAMES.PLAYER_EDIT) || !q.GMQuest; + // Players can never delete GM quests. + q.canDelete = game.user.isGM || !q.GMQuest; + // Return the quest with modified data. return { ...q, diff --git a/scripts/helpers/SocketHandler.js b/scripts/helpers/SocketHandler.js index 5a937b9..bb6fbdb 100644 --- a/scripts/helpers/SocketHandler.js +++ b/scripts/helpers/SocketHandler.js @@ -2,6 +2,7 @@ import { constants } from "./global.js"; import { Quest } from "../data/quest.js"; import { QuestDatabase } from "../data/database.js"; import { UIManager } from "../ui/ui-manager.js"; +import { Settings } from "./settings.js"; export class SocketHandler { identifier = `module.simpler-quests`; @@ -13,32 +14,60 @@ export class SocketHandler { registerSocketListeners() { game.socket?.on(this.identifier, (ev) => { if (ev.type === "InsertOrUpdate") this.#OnInsertOrUpdate(ev.data); + if (ev.type === "DeleteQuest") this.#OnDeleteQuest(ev.data); else if (ev.type == "UpdateObjective") this.#OnUpdateObjective(ev.data); }); } - emit(data) { - console.log(`Emitting: ${data}`); - + emit(type, payload) { // Add the user to the data for tracking who sent the data. - data.user = game.user; + payload.user = game.user; const sock = game.socket; - if (sock) return sock.emit(this.identifier, data); + if (sock) + return sock.emit(this.identifier, { type: type, data: payload }); } #OnInsertOrUpdate(data) { + // If the user isn't a GM, ignore. if (!game.user.isGM) return; - console.log(`Received quest data: ${data}`); + // If the quest is a GM quest but players aren't allowed + // to edit GM quests, don't allow the edit. + if (data.GMQuest && !Settings.get(Settings.NAMES.PLAYER_EDIT)) return; + + console.log(`User ${data.user.id} has edited quest ${data.questId}`); let q = new Quest(data); QuestDatabase.InsertOrUpdate(q); - console.log(q); UIManager.tracker.render(); } + #OnDeleteQuest(data) { + // If the user isn't a GM, ignore. + if (!game.user.isGM) return; + + // If the quest is a GM quest, players cannot delete it. + if (data.GMQuest) return; + + console.log(`User ${data.user.id} has deleted quest ${data.questId}`); + QuestDatabase.removeQuest(data.questId); + } + #OnUpdateObjective(data) { + // If the user isn't a GM, ignore. + if (!game.user.isGM) return; + + // Get the quest + var Q = QuestDatabase.getQuest(data.questId); + + // If the quest is a GM quest but players aren't allowed + // to mark GM quests, don't allow the mark. + if (Q.GMQuest && !Settings.get(Settings.NAMES.PLAYER_MARK)) return; + + console.log( + `User ${data.user.id} has marked quest ${data.questId} objective ${data.objId}` + ); Quest.updateObjective(data.questId, data.objId, "state"); } } diff --git a/scripts/helpers/settings.js b/scripts/helpers/settings.js index 7405a3e..d7d517f 100644 --- a/scripts/helpers/settings.js +++ b/scripts/helpers/settings.js @@ -39,9 +39,9 @@ export class Settings { requiresReload: true, }); - game.settings.register(constants.moduleName, this.NAMES.PLAYER_EDIT, { - name: "SimplerQuests.Settings.PlayerEdit.Name", - hint: "SimplerQuests.Settings.PlayerEdit.Hint", + game.settings.register(constants.moduleName, this.NAMES.PLAYER_CREATE, { + name: "SimplerQuests.Settings.PlayerCreate.Name", + hint: "SimplerQuests.Settings.PlayerCreate.Hint", scope: "world", type: Boolean, default: false, @@ -49,9 +49,9 @@ export class Settings { requiresReload: true, }); - game.settings.register(constants.moduleName, this.NAMES.PLAYER_CREATE, { - name: "SimplerQuests.Settings.PlayerCreate.Name", - hint: "SimplerQuests.Settings.PlayerCreate.Hint", + game.settings.register(constants.moduleName, this.NAMES.PLAYER_EDIT, { + name: "SimplerQuests.Settings.PlayerEdit.Name", + hint: "SimplerQuests.Settings.PlayerEdit.Hint", scope: "world", type: Boolean, default: false, diff --git a/scripts/ui/questeditor.js b/scripts/ui/questeditor.js index e2bfca9..47b9d64 100644 --- a/scripts/ui/questeditor.js +++ b/scripts/ui/questeditor.js @@ -118,10 +118,7 @@ export class QuestEditor extends Application { UIManager.tracker.render(); this.close(); } else { - getSocket().emit({ - type: "InsertOrUpdate", - data: qData, - }); + getSocket().emit("InsertOrUpdate", qData); UIManager.tracker.render(); this.close(); } diff --git a/scripts/ui/questtracker.js b/scripts/ui/questtracker.js index 412d465..53f7534 100644 --- a/scripts/ui/questtracker.js +++ b/scripts/ui/questtracker.js @@ -149,7 +149,6 @@ export class QuestTracker extends Application { $html.find(".minimize").on("click", (evt) => { evt.stopPropagation(); this.collapse(); - let result = getSocket().emit({ type: "TEST" }); console.log(result); }); @@ -195,10 +194,6 @@ export class QuestTracker extends Application { this.render(); }); - // All of the listeners beyond this point require permission. - if (!game.user.isGM && !Settings.get(Settings.NAMES.PLAYER_EDIT)) - return; - // Progress the state of an objective. $html.find(".simpler-quest-objective").on("click", (evt) => { evt.stopPropagation(); @@ -216,18 +211,19 @@ export class QuestTracker extends Application { evt.target.closest("[data-quest-id]").dataset.questId; if (game.user.isGM) Quest.updateObjective(questId, objId, "state"); - else if (Settings.get(Settings.NAMES.PLAYER_MARK)) { - getSocket().emit({ - type: "UpdateObjective", - data: { - questId: questId, - objId: objId, - key: "state", - }, + else { + getSocket().emit("UpdateObjective", { + questId: questId, + objId: objId, + key: "state", }); } }); + // All of the listeners beyond this point require permission. + if (!game.user.isGM && !Settings.get(Settings.NAMES.PLAYER_EDIT)) + return; + // Create a new quest. $html.find(".header > .new-quest").on("click", (evt) => { evt.stopPropagation(); @@ -275,11 +271,14 @@ export class QuestTracker extends Application { // If the user confirmed, delete the quest. if (confirmed) { - QuestDatabase.removeQuest(data.questId); + if (game.user.isGM) QuestDatabase.removeQuest(data.questId); + else { + getSocket().emit("DeleteQuest", { questId: questId }); + } } }); - // All listeners beyond this point work only for GM. + // Listeners beyond this point are GM Only. if (!game.user.isGM) return; // Toggle the visibility of quests. diff --git a/templates/tracker-body.hbs b/templates/tracker-body.hbs index 5e04303..1c5c881 100644 --- a/templates/tracker-body.hbs +++ b/templates/tracker-body.hbs @@ -14,6 +14,8 @@ {{/if}} {{#if canEdit}}
+ {{/if}} + {{#if canDelete}}
{{/if}}
From 70e57afb214822a30e6dabaee783aaadd5f76a8a Mon Sep 17 00:00:00 2001 From: LadyDefile Date: Sun, 10 Nov 2024 14:26:03 -0600 Subject: [PATCH 10/10] Update module.json Increased version number. --- module.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module.json b/module.json index 2b7bc92..858608c 100644 --- a/module.json +++ b/module.json @@ -12,7 +12,7 @@ } } ], - "version": "v0.1.7", + "version": "v0.1.8", "compatibility": { "minimum": "12", "verified": "12" @@ -36,5 +36,5 @@ "socket": true, "url": "https://github.com/MythicPalette/simpler-quests", "manifest": "https://github.com/MythicPalette/simpler-quests/releases/latest/download/module.json", - "download": "https://github.com/MythicPalette/simpler-quests/releases/download/v0.1.7/module.zip" + "download": "https://github.com/MythicPalette/simpler-quests/releases/download/v0.1.8/module.zip" }