diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e33ad3..bfd1247 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## [2.4.0] 2022-04-29 + +- Add compatibility for Foundry v9 (MattStJean) + ## [2.3.0] 2021-01-16 ### CHANGED diff --git a/README.md b/README.md index 47b390e..f3528dd 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Confirmed compatibility with Tidy5e Sheet, Alt5e Sheet, and Better Rolls for 5e. Makes use of libWrapper to reduce likelihood of conflicts. Installing libWrapper is not required to make use of this module. +Updated to be compatible with Foundry v9. + ## License Licensed under the GPLv3 License (see [LICENSE](LICENSE)). diff --git a/lib/libWrapper/shim.js b/lib/libWrapper/shim.js index 1643130..fe935cb 100644 --- a/lib/libWrapper/shim.js +++ b/lib/libWrapper/shim.js @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later +// SPDX-License-Identifier: MIT // Copyright © 2021 fvtt-lib-wrapper Rui Pinheiro @@ -7,6 +7,11 @@ // A shim for the libWrapper library export let libWrapper = undefined; +export const VERSIONS = [1,12,1]; +export const TGT_SPLIT_RE = new RegExp("([^.[]+|\\[('([^'\\\\]|\\\\.)+?'|\"([^\"\\\\]|\\\\.)+?\")\\])", 'g'); +export const TGT_CLEANUP_RE = new RegExp("(^\\['|'\\]$|^\\[\"|\"\\]$)", 'g'); + +// Main shim code Hooks.once('init', () => { // Check if the real module is already loaded - if so, use it if(globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) { @@ -18,14 +23,26 @@ Hooks.once('init', () => { libWrapper = class { static get is_fallback() { return true }; - static register(module, target, fn, type="MIXED") { + static get WRAPPER() { return 'WRAPPER' }; + static get MIXED() { return 'MIXED' }; + static get OVERRIDE() { return 'OVERRIDE' }; + + static register(package_id, target, fn, type="MIXED", {chain=undefined, bind=[]}={}) { const is_setter = target.endsWith('#set'); target = !is_setter ? target : target.slice(0, -4); - const split = target.split('.'); - const fn_name = split.pop(); + const split = target.match(TGT_SPLIT_RE).map((x)=>x.replace(/\\(.)/g, '$1').replace(TGT_CLEANUP_RE,'')); const root_nm = split.splice(0,1)[0]; - const _eval = eval; // The browser doesn't expose all global variables (e.g. 'Game') inside globalThis, but it does to an eval. We copy it to a variable to have it run in global scope. - const obj = split.reduce((x,y)=>x[y], globalThis[root_nm] ?? _eval(root_nm)); + + let obj, fn_name; + if(split.length == 0) { + obj = globalThis; + fn_name = root_nm; + } + else { + const _eval = eval; + fn_name = split.pop(); + obj = split.reduce((x,y)=>x[y], globalThis[root_nm] ?? _eval(root_nm)); + } let iObj = obj; let descriptor = null; @@ -34,10 +51,13 @@ Hooks.once('init', () => { if(descriptor) break; iObj = Object.getPrototypeOf(iObj); } - if(!descriptor) throw `libWrapper Shim: '${target}' does not exist or could not be found.`; + if(!descriptor || descriptor?.configurable === false) throw new Error(`libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`); let original = null; - const wrapper = (type == 'OVERRIDE') ? function() { return fn.call(this, ...arguments); } : function() { return fn.call(this, original.bind(this), ...arguments); } + const wrapper = (chain ?? (type.toUpperCase?.() != 'OVERRIDE' && type != 3)) ? + function(...args) { return fn.call(this, original.bind(this), ...bind, ...args); } : + function(...args) { return fn.call(this, ...bind, ...args); } + ; if(!is_setter) { if(descriptor.value) { @@ -50,7 +70,7 @@ Hooks.once('init', () => { } } else { - if(!descriptor.set) throw `libWrapper Shim: '${target}' does not have a setter`; + if(!descriptor.set) throw new Error(`libWrapper Shim: '${target}' does not have a setter`); original = descriptor.set; descriptor.set = wrapper; } @@ -59,50 +79,4 @@ Hooks.once('init', () => { Object.defineProperty(obj, fn_name, descriptor); } } - - //************** USER CUSTOMIZABLE: - // Whether to warn GM that the fallback is being used - const WARN_FALLBACK = false; - - // Set up the ready hook that shows the "libWrapper not installed" warning dialog - if(WARN_FALLBACK) { - //************** USER CUSTOMIZABLE: - // Module ID - by default attempts to auto-detect, but you might want to hardcode your module ID here to avoid potential auto-detect issues - const MODULE_ID = ((import.meta?.url ?? Error().stack)?.match(/(?<=\/)modules\/.+(?=\/)/i)??[])[0]?.split('/')?.find(n => n && game.modules.has(n)); - if(!MODULE_ID) { - console.error("libWrapper Shim: Could not auto-detect module ID. The libWrapper fallback warning dialog will be disabled."); - return; - } - - Hooks.once('ready', () => { - // Module title - const MODULE_TITLE = game.modules.get(MODULE_ID).data.title; - - //************** USER CUSTOMIZABLE: - // Title and message for the dialog shown when the real libWrapper is not installed. - const FALLBACK_MESSAGE_TITLE = MODULE_TITLE; - const FALLBACK_MESSAGE = ` -
'${MODULE_TITLE}' depends on the 'libWrapper' module, which is not present.
-A fallback implementation will be used, which increases the chance of compatibility issues with other modules.
-'libWrapper' is a library which provides module developers with a simple way to modify core Foundry VTT code, while reducing the likelihood of conflict with other modules.
-You can install it from the "Add-on Modules" tab in the Foundry VTT Setup, from the Foundry VTT package repository, or from libWrapper's Github page.
- `; - - // Settings key used for the "Don't remind me again" setting - const DONT_REMIND_AGAIN_KEY = "libwrapper-dont-remind-again"; - - // Dialog code - console.warn(`${MODULE_TITLE}: libWrapper not present, using fallback implementation.`); - game.settings.register(MODULE_ID, DONT_REMIND_AGAIN_KEY, { name: '', default: false, type: Boolean, scope: 'world', config: false }); - if(game.user.isGM && !game.settings.get(MODULE_ID, DONT_REMIND_AGAIN_KEY)) { - new Dialog({ - title: FALLBACK_MESSAGE_TITLE, - content: FALLBACK_MESSAGE, buttons: { - ok: { icon: '', label: 'Understood' }, - dont_remind: { icon: '', label: "Don't remind me again", callback: () => game.settings.set(MODULE_ID, DONT_REMIND_AGAIN_KEY, true) } - } - }).render(true); - } - }); - } -}); +}); \ No newline at end of file diff --git a/module.json b/module.json index 0fd06ee..e539423 100644 --- a/module.json +++ b/module.json @@ -5,20 +5,31 @@ "systems": [ "dnd5e" ], - "version": "2.3.0", - "author": "Cole Schultz (cole#9640)", + "version": "2.4.0", + "authors": [ + { + "name": "Cole Schultz", + "url": "https://github.com/schultzcole", + "discord": "cole#9640" + }, + { + "name": "Matt St Jean", + "url": "https://github.com/mattstjean", + "discord": "maatttt#9864" + } + ], "esmodules": [ "skl-customization.js" ], "styles": [ "skl-cust-styles.css" ], - "minimumCoreVersion": "0.6.2", - "compatibleCoreVersion": "0.7.9", - "url": "https://github.com/schultzcole/FVTT-Skill-Customization-5e", - "manifest": "https://raw.githubusercontent.com/schultzcole/FVTT-Skill-Customization-5e/master/module.json", - "download": "https://github.com/schultzcole/FVTT-Skill-Customization-5e/archive/2.3.0.zip", - "license": "https://github.com/schultzcole/FVTT-Skill-Customization-5e/blob/2.3.0/LICENSE", - "readme": "https://github.com/schultzcole/FVTT-Skill-Customization-5e/blob/2.3.0/README.md", - "changelog": "https://github.com/schultzcole/FVTT-Skill-Customization-5e/blob/2.3.0/CHANGELOG.md" + "minimumCoreVersion": "9.235", + "compatibleCoreVersion": "9.255", + "url": "https://github.com/mattstjean/FVTT-Skill-Customization-5e", + "manifest": "https://raw.githubusercontent.com/mattstjean/FVTT-Skill-Customization-5e/master/module.json", + "download": "https://github.com/mattstjean/FVTT-Skill-Customization-5e/archive/2.4.0.zip", + "license": "https://github.com/mattstjean/FVTT-Skill-Customization-5e/blob/2.4.0/LICENSE", + "readme": "https://github.com/mattstjean/FVTT-Skill-Customization-5e/blob/2.4.0/README.md", + "changelog": "https://github.com/mattstjean/FVTT-Skill-Customization-5e/blob/2.4.0/CHANGELOG.md" } diff --git a/skl-customization.js b/skl-customization.js index 9db408d..7a2f34e 100644 --- a/skl-customization.js +++ b/skl-customization.js @@ -12,7 +12,7 @@ Hooks.once("setup", () => { Hooks.on("renderActorSheet", injectActorSheet); function patchActor5ePrepareData() { - libWrapper.register(MODULE_NAME, "CONFIG.Actor.entityClass.prototype.prepareData", function patchedPrepareData(wrapped, ...args) { + libWrapper.register(MODULE_NAME, "CONFIG.Actor.documentClass.prototype.prepareData", function patchedPrepareData(wrapped, ...args) { wrapped(...args); const skills = this.data.data.skills; @@ -34,7 +34,7 @@ function patchActor5ePrepareData() { } function patchActor5eRollSkill() { - libWrapper.register(MODULE_NAME, "CONFIG.Actor.entityClass.prototype.rollSkill", function patchedRollSkill(wrapped, ...args) { + libWrapper.register(MODULE_NAME, "CONFIG.Actor.documentClass.prototype.rollSkill", function patchedRollSkill(wrapped, ...args) { const [ skillId, options ] = args; const skillBonus = this.getFlag(MODULE_NAME, `${skillId}.${SKILL_BONUS_KEY}`); if (skillBonus) {