2 Commits

Author SHA1 Message Date
01857f6ef4 Release v1.2.6 2021-05-05 01:10:57 +02:00
1215ddf55a Use libWrapper for function hooks (resolves #5) 2021-05-05 01:06:33 +02:00
5 changed files with 85 additions and 21 deletions

View File

@@ -1,3 +1,7 @@
## 1.2.6
### Compatibility
- Smart Doors now uses the libwrapper module and as a result is now compatible with the module "FoundryVTT Arms Reach"
## 1.2.5
### New features
- Synchronized doors can now be configured to synchronize their secret door status as well

61
lib/libwrapper_shim.js Normal file
View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT
// Copyright © 2021 fvtt-lib-wrapper Rui Pinheiro
'use strict';
// A shim for the libWrapper library
export let libWrapper = undefined;
Hooks.once('init', () => {
// Check if the real module is already loaded - if so, use it
if(globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) {
libWrapper = globalThis.libWrapper;
return;
}
// Fallback implementation
libWrapper = class {
static get is_fallback() { return true };
static register(module, target, fn, type="MIXED", {chain=undefined}={}) {
const is_setter = target.endsWith('#set');
target = !is_setter ? target : target.slice(0, -4);
const split = target.split('.');
const fn_name = split.pop();
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 iObj = obj;
let descriptor = null;
while(iObj) {
descriptor = Object.getOwnPropertyDescriptor(iObj, fn_name);
if(descriptor) break;
iObj = Object.getPrototypeOf(iObj);
}
if(!descriptor || descriptor?.configurable === false) throw `libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`;
let original = null;
const wrapper = (chain ?? type != 'OVERRIDE') ? function() { return fn.call(this, original.bind(this), ...arguments); } : function() { return fn.apply(this, arguments); };
if(!is_setter) {
if(descriptor.value) {
original = descriptor.value;
descriptor.value = wrapper;
}
else {
original = descriptor.get;
descriptor.get = wrapper;
}
}
else {
if(!descriptor.set) throw `libWrapper Shim: '${target}' does not have a setter`;
original = descriptor.set;
descriptor.set = wrapper;
}
descriptor.configurable = true;
Object.defineProperty(obj, fn_name, descriptor);
}
}
});

View File

@@ -2,7 +2,7 @@
"name": "smart-doors",
"title": "Smart Doors",
"description": "Makes doors smarter. Allows doors to synchronize across multiple scenes and sends chat messages when players try to open locked doors.",
"version": "1.2.5",
"version": "1.2.6",
"minimumCoreVersion" : "0.7.7",
"compatibleCoreVersion" : "0.7.9",
"authors": [
@@ -13,6 +13,7 @@
}
],
"esmodules": [
"lib/libwrapper_shim.js",
"src/main.js"
],
"languages": [
@@ -24,7 +25,7 @@
],
"url": "https://github.com/manuelVo/foundryvtt-smart-doors",
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-smart-doors/master/module.json",
"download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.2.5.zip",
"download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.2.6.zip",
"readme": "https://github.com/manuelVo/foundryvtt-smart-doors/blob/master/README.md",
"changelog": "https://github.com/manuelVo/foundryvtt-smart-doors/blob/master/CHANGELOG.md",
"bugs": "https://github.com/manuelVo/foundryvtt-smart-doors/issues"

View File

@@ -1,13 +1,14 @@
import { libWrapper } from "../../lib/libwrapper_shim.js"
import {settingsKey} from "../settings.js"
// Adjust the repositioning formula for the door controls
export function hookDoorControlReposition() {
DoorControl.prototype.reposition = function () {
libWrapper.register("smart-doors", "DoorControl.prototype.reposition", function () {
let gridSize = this.wall.scene.data.grid
gridSize *= game.settings.get(settingsKey, "doorControlSizeFactor")
const pos = this.wall.midpoint.map(p => p - gridSize * 0.2)
this.position.set(...pos)
}
}, "OVERRIDE");
}
// Set the size of all door controls in relation to the grid size so it'll have a constant percieved size

View File

@@ -1,5 +1,6 @@
"use strict";
import {libWrapper} from "../lib/libwrapper_shim.js";
import * as DoorControlIconScale from "./features/door_control_icon_scale.js"
import * as DoorControlOutline from "./features/door_control_outline.js"
import * as HighlightSecretDoors from "./features/highlight_secret_doors.js"
@@ -35,45 +36,41 @@ Hooks.on("renderWallConfig", SynchronizedDoors.onRederWallConfig)
// Hook the update function of the WallConfig dialog so we can store our custom data
function hookWallConfigUpdate() {
// Replace the original function with our custom one
const originalHandler = WallConfig.prototype._updateObject;
WallConfig.prototype._updateObject = async function (event, formData) {
await originalHandler.call(this, event, formData)
libWrapper.register("smart-doors", "WallConfig.prototype._updateObject", async function (wrapped, event, formData) {
await wrapped(event, formData);
return SynchronizedDoors.onWallConfigUpdate.call(this, event, formData)
}
}, "WRAPPER");
}
function hookDoorControlDraw() {
const originalHandler = DoorControl.prototype.draw
DoorControl.prototype.draw = async function () {
const result = await originalHandler.call(this)
libWrapper.register("smart-doors", "DoorControl.prototype.draw", async function (wrapped) {
const result = await wrapped();
DoorControlIconScale.onDoorControlPostDraw.call(this)
DoorControlOutline.onDoorControlPostDraw.call(this)
return result
}
return result;
}, "WRAPPER");
}
// Hook mouse events on DoorControls to perform our logic.
// If we successfully handled the event block the original handler. Forward the event otherwise.
function hookDoorEvents() {
// Replace the original mousedown handler with our custom one
const originalMouseDownHandler = DoorControl.prototype._onMouseDown
DoorControl.prototype._onMouseDown = function (event) {
libWrapper.register("smart-doors", "DoorControl.prototype._onMouseDown", function (wrapped, event) {
// Call our handler first. Only allow the original handler to run if our handler returns true
const eventHandled = onDoorMouseDown.call(this, event)
if (eventHandled)
return
return originalMouseDownHandler.call(this, event)
}
return wrapped(event);
}, "MIXED");
// Replace the original rightdown handler with our custom one
const originalRightDownHandler = DoorControl.prototype._onRightDown
DoorControl.prototype._onRightDown = function (event) {
libWrapper.register("smart-doors", "DoorControl.prototype._onRightDown", function (wrapped, event) {
// Call our handler first. Only allow the original handler to run if our handler returns true
const eventHandled = onDoorRightDown.call(this, event)
if (eventHandled)
return
return originalRightDownHandler.call(this, event)
}
return wrapped(event);
}, "MIXED");
}
// Our custom handler for mousedown events on doors