Skip to content

Commit b78b50e

Browse files
committed
Refactor Setup Hook
1 parent 6166220 commit b78b50e

6 files changed

Lines changed: 94 additions & 134 deletions

File tree

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ If you would like to create a module that supplies its own sheet out of the box
2525

2626
```js
2727
Hooks.once('pbtaSheetConfig', () => {
28-
// Disable the sheet config form.
29-
game.settings.set('pbta', 'sheetConfigOverride', true);
3028
// Define custom tags.
3129
game.pbta.tagConfigOverride = {
3230
// Tags available to any actor and item

src/module/forms/sheet-config.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,11 @@ export class PbtaSettingsConfigDialog extends FormApplication {
2626

2727
/* -------------------------------------------- */
2828

29-
get sheetOverriden() {
30-
return game.settings.get("pbta", "sheetConfigOverride");
31-
}
32-
33-
/* -------------------------------------------- */
34-
3529
/** @override */
3630
async getData(options) {
3731
const sheetConfig = game.settings.get("pbta", "sheetConfig") || {};
3832
return {
3933
...foundry.utils.deepClone(sheetConfig),
40-
sheetConfigOverride: this.sheetOverriden,
4134
tomlString: sheetConfig.tomlString || ""
4235
};
4336
}

src/module/pbta.js

Lines changed: 82 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ globalThis.pbta = {
3131
utils
3232
};
3333

34-
Hooks.once("init", async function () {
34+
Hooks.once("init", () => {
3535
globalThis.pbta = game.pbta = Object.assign(game.system, globalThis.pbta);
3636

3737
CONFIG.ui.combat = applications.combat.PbtACombatTracker;
@@ -104,27 +104,32 @@ Hooks.once("init", async function () {
104104
});
105105

106106
Hooks.on("i18nInit", () => {
107+
const activeModules = [...game.modules.entries()].filter(([key, m]) => m.active && m.flags[key]?.["pbta-override"]);
108+
109+
if (activeModules.length > 1 && game.user.isGM) {
110+
const names = activeModules.map(([key, m]) => m.name).join(", ");
111+
ui.notifications.warn(game.i18n.format("PBTA.Warnings.TooManyModules", { names }));
112+
}
113+
game.pbta.moduleConfig = activeModules.length > 0;
114+
107115
registerSettings();
108116

109117
// Build out character data structures.
110118
const pbtaSettings = game.settings.get("pbta", "sheetConfig");
111119

112-
// Retrieve overridden config, if enabled.
113-
if (pbtaSettings?.overridden && game.settings.get("pbta", "sheetConfigOverride")) {
120+
if (pbtaSettings.overridden && game.pbta.moduleConfig) {
114121
game.pbta.sheetConfig = pbtaSettings.overridden;
115-
} else if (pbtaSettings?.computed) {
116-
// Otherwise, retrieve computed config.
122+
} else if (pbtaSettings.computed) {
117123
game.pbta.sheetConfig = utils.convertSheetConfig(pbtaSettings.computed);
118124
} else {
119-
// Fallback to empty config.
120125
game.pbta.sheetConfig = pbtaSettings;
121126
}
122127
});
123128

124129
/**
125130
* This function runs after game data has been requested and loaded from the servers, so documents exist
126131
*/
127-
Hooks.once("setup", function () {
132+
Hooks.once("setup", () => {
128133
// Localize CONFIG objects once up-front
129134
const toLocalize = [];
130135
for (let o of toLocalize) {
@@ -134,100 +139,14 @@ Hooks.once("setup", function () {
134139
}, {});
135140
}
136141

137-
if (game.user.isGM) {
138-
Hooks.on("renderSettings", (app, html) => {
139-
const header = document.createElement("h2");
140-
header.innerText = game.i18n.localize("Powered by the Apocalypse");
141-
142-
const pbtaSettings = document.createElement("div");
143-
html.find("#settings-game")?.after(header, pbtaSettings);
144-
145-
const buttons = [
146-
{
147-
action: (ev) => {
148-
ev.preventDefault();
149-
let menu = game.settings.menus.get("pbta.sheetConfigMenu");
150-
let app = new menu.type();
151-
app.render(true);
152-
},
153-
iconClasses: ["fas", "fa-file-alt"],
154-
label: "PBTA.Settings.sheetConfig.label"
155-
},
156-
{
157-
action: (ev) => {
158-
ev.preventDefault();
159-
window.open("https://asacolips.gitbook.io/pbta-system/", "pbtaHelp", "width=1032,height=720");
160-
},
161-
iconClasses: ["fas", "fa-question-circle"],
162-
label: "PBTA.Settings.button.help"
163-
}
164-
].map(({ action, iconClasses, label }) => {
165-
const button = document.createElement("button");
166-
button.type = "button";
167-
168-
const icon = document.createElement("i");
169-
icon.classList.add(...iconClasses);
170-
171-
button.append(icon, game.i18n.localize(label));
172-
173-
button.addEventListener("click", action);
174-
175-
return button;
176-
});
177-
178-
pbtaSettings.append(...buttons);
179-
});
142+
if (game.modules.get("babele")?.active) {
143+
Hooks.on("babele.ready", () => utils.getPlaybooks());
144+
} else {
145+
utils.getPlaybooks();
180146
}
181147
});
182148

183-
Hooks.once("ready", async function () {
184-
// Override sheet config.
185-
if (game.user.isGM) {
186-
// Force sheet config override off, unless a module changes it.
187-
await game.settings.set("pbta", "sheetConfigOverride", false);
188-
189-
// Allow modules to override the sheet config.
190-
Hooks.callAll("pbtaSheetConfig");
191-
192-
// @todo find something better than this timeout hack.
193-
const timeout = 1000;
194-
setTimeout(() => {
195-
// Retrieve the previous configuration.
196-
let existingConfig = game.settings.get("pbta", "sheetConfig") ?? {};
197-
// @todo hack to fix the old the default value. Remove in a future update.
198-
if (typeof existingConfig !== "object") {
199-
existingConfig = {};
200-
}
201-
// If a module enabled the override, assign it to the config so that player
202-
// clients can use it without the GM being logged in.
203-
if (game.settings.get("pbta", "sheetConfigOverride")) {
204-
existingConfig.overridden = game.pbta.sheetConfig;
205-
game.settings.set("pbta", "sheetConfig", existingConfig);
206-
} else if (existingConfig?.overridden) {
207-
// Otherwise, delete the override config.
208-
209-
// If not tomlString exists, delete the config outright to prevent
210-
// it from being malformed.
211-
if (!existingConfig?.tomlString) {
212-
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.overrideRemoved"));
213-
existingConfig = null;
214-
} else {
215-
// Otherwise, restore the previous config.
216-
217-
// Delete overrides.
218-
delete existingConfig.overridden;
219-
delete existingConfig.computed;
220-
// Restore computed config and reapply.
221-
existingConfig.computed = utils.parseTomlString(existingConfig.tomlString);
222-
game.pbta.sheetConfig = utils.convertSheetConfig(existingConfig.computed);
223-
utils.applyActorTemplates(true);
224-
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.previousSettingRestored"));
225-
}
226-
game.settings.set("pbta", "sheetConfig", existingConfig);
227-
}
228-
}, timeout);
229-
}
230-
149+
Hooks.once("ready", () => {
231150
// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
232151
Hooks.on("hotbarDrop", (bar, data, slot) => {
233152
if (["Item"].includes(data.type)) {
@@ -236,12 +155,26 @@ Hooks.once("ready", async function () {
236155
}
237156
});
238157

239-
CONFIG.PBTA = PBTA;
158+
if (game.user.isGM) {
159+
Hooks.callAll("pbta.sheetConfig");
160+
let existingConfig = game.settings.get("pbta", "sheetConfig") ?? {};
161+
const { overridden, tomlString } = existingConfig;
162+
if (game.pbta.moduleConfig) {
163+
existingConfig.overridden = game.pbta.sheetConfig;
164+
} else if (overridden) {
165+
if (!tomlString) {
166+
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.overrideRemoved"));
167+
existingConfig = {};
168+
} else {
169+
delete existingConfig.overridden;
240170

241-
if (game.modules.get("babele")?.active && game.i18n.lang !== "en") {
242-
Hooks.on("babele.ready", () => utils.getPlaybooks());
243-
} else {
244-
utils.getPlaybooks();
171+
existingConfig.computed = utils.parseTomlString(existingConfig.tomlString);
172+
game.pbta.sheetConfig = utils.convertSheetConfig(existingConfig.computed);
173+
utils.applyActorTemplates(true);
174+
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.previousSettingRestored"));
175+
}
176+
}
177+
game.settings.set("pbta", "sheetConfig", existingConfig);
245178
}
246179

247180
// Apply structure to actor types.
@@ -276,6 +209,52 @@ Hooks.on("renderChatMessage", (data, html, options) => {
276209

277210
Hooks.on("renderChatLog", (app, html, data) => documents.ItemPbta.chatListeners(html));
278211
Hooks.on("renderChatPopout", (app, html, data) => documents.ItemPbta.chatListeners(html));
212+
Hooks.on("renderSettings", (app, html) => {
213+
if (!game.user.isGM) return;
214+
const header = document.createElement("h2");
215+
header.innerText = game.i18n.localize("Powered by the Apocalypse");
216+
217+
const pbtaSettings = document.createElement("div");
218+
html.find("#settings-game")?.after(header, pbtaSettings);
219+
220+
const buttons = [
221+
{
222+
action: (ev) => {
223+
ev.preventDefault();
224+
window.open("https://asacolips.gitbook.io/pbta-system/", "pbtaHelp", "width=1032,height=720");
225+
},
226+
iconClasses: ["fas", "fa-question-circle"],
227+
label: "PBTA.Settings.button.help"
228+
}
229+
];
230+
if (!game.pbta.moduleConfig) {
231+
buttons.unshift({
232+
action: (ev) => {
233+
ev.preventDefault();
234+
let menu = game.settings.menus.get("pbta.sheetConfigMenu");
235+
let app = new menu.type();
236+
app.render(true);
237+
},
238+
iconClasses: ["fas", "fa-file-alt"],
239+
label: "PBTA.Settings.sheetConfig.label"
240+
});
241+
}
242+
const formattedButtons = buttons.map(({ action, iconClasses, label }) => {
243+
const button = document.createElement("button");
244+
button.type = "button";
245+
246+
const icon = document.createElement("i");
247+
icon.classList.add(...iconClasses);
248+
249+
button.append(icon, game.i18n.localize(label));
250+
251+
button.addEventListener("click", action);
252+
253+
return button;
254+
});
255+
256+
pbtaSettings.append(...formattedButtons);
257+
});
279258

280259
/**
281260
* Configure explicit lists of attributes that are trackable on the token HUD and in the combat tracker.

src/module/settings.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ import { PbtaTagConfigDialog } from "./forms/tag-config.js";
55
* Register all of the system's settings.
66
*/
77
export function registerSettings() {
8-
game.settings.registerMenu("pbta", "sheetConfigMenu", {
9-
name: game.i18n.localize("PBTA.Settings.sheetConfig.name"),
10-
label: game.i18n.localize("PBTA.Settings.sheetConfig.title"),
11-
hint: game.i18n.localize("PBTA.Settings.sheetConfig.hint"),
12-
icon: "fas fa-file-alt", // A Font Awesome icon used in the submenu button
13-
type: PbtaSettingsConfigDialog, // A FormApplication subclass which should be created
14-
restricted: true, // Restrict this submenu to gamemaster only?
15-
scope: "world"
16-
});
17-
8+
if (!game.pbta.moduleConfig) {
9+
game.settings.registerMenu("pbta", "sheetConfigMenu", {
10+
name: game.i18n.localize("PBTA.Settings.sheetConfig.name"),
11+
label: game.i18n.localize("PBTA.Settings.sheetConfig.title"),
12+
hint: game.i18n.localize("PBTA.Settings.sheetConfig.hint"),
13+
icon: "fas fa-file-alt", // A Font Awesome icon used in the submenu button
14+
type: PbtaSettingsConfigDialog, // A FormApplication subclass which should be created
15+
restricted: true, // Restrict this submenu to gamemaster only?
16+
scope: "world"
17+
});
18+
}
1819
game.settings.registerMenu("pbta", "tagConfigMenu", {
1920
name: game.i18n.localize("PBTA.Settings.tagConfig.name"),
2021
label: game.i18n.localize("PBTA.Settings.tagConfig.label"),
@@ -125,14 +126,6 @@ export function registerSettings() {
125126
default: {}
126127
});
127128

128-
game.settings.register("pbta", "sheetConfigOverride", {
129-
name: "Override PBTA Sheet Config",
130-
scope: "world",
131-
config: false,
132-
type: Boolean,
133-
default: false
134-
});
135-
136129
game.settings.register("pbta", "tagConfig", {
137130
name: "PBTA Tag Config",
138131
scope: "world",

src/templates/dialog/sheet-config.html

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
<i class="fas fa-question-circle"></i> {{localize "PBTA.Settings.button.help"}}
77
</button>
88

9-
{{#if sheetConfigOverride}}
10-
<div class="notification error">{{localize "PBTA.Settings.sheetConfig.sheetConfigDisabledModule"}}</div>
11-
{{else}}
129
<section class="pbta-sheet-config-editor">
1310
<textarea name="tomlString" class="pbta-sheet-config">
1411
{{~" "}}{{{tomlString}}}{{" "~}}
@@ -24,5 +21,4 @@
2421
<i class="fas fa-sync"></i> {{localize 'PERMISSION.Reset'}}
2522
</button>
2623
</div>
27-
{{/if}}
2824
</form>

src/yaml/lang/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ PBTA:
226226
MissingTargetWarn: "Your controlled actor '{actor}' does not have an item with name '{name}'."
227227
MultipleTargetsWarn: "Your controlled actor '{actor}' has more than one item with name '{name}'. The first match will be chosen."
228228
TagDeprecation: "Tags as items have been deprecated, use the Tag Configuration menu on the game settings to create your tags."
229+
TooManyModules: "You have more than one module attempting to override PbtA's sheet config: {names}"
229230
UnlinkedToken:
230231
Equipment: "Equipment cannot be rearranged while this token is not linked to an actor."
231232
Moves: "Moves cannot be rearranged while this token is not linked to an actor."

0 commit comments

Comments
 (0)