Skip to content

Instantly share code, notes, and snippets.

@twnlink
Created November 21, 2022 18:36
Show Gist options
  • Save twnlink/5546ee20dae31659a8acd36b1b1945b5 to your computer and use it in GitHub Desktop.
Save twnlink/5546ee20dae31659a8acd36b1b1945b5 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Roll20 Character Sheet New Tab
// @match https://app.roll20.net/*
// @grant none
// @version 1.0
// @author toonlink
// @description 11/21/2022, 1:19:45 PM
// ==/UserScript==
// http-url:https://unpkg.com/spitroast@1.4.2/dist/esm/shared.js
var patchTypes = ["a", "b", "i"];
var patchedObjects = /* @__PURE__ */ new Map();
// http-url:https://unpkg.com/spitroast@1.4.2/dist/esm/hook.js
function hook_default(funcName, funcParent, funcArgs, ctxt, isConstruct) {
const patch = patchedObjects.get(funcParent)?.[funcName];
if (!patch)
return isConstruct ? Reflect.construct(funcParent[funcName], funcArgs, ctxt) : funcParent[funcName].apply(ctxt, funcArgs);
for (const hook of patch.b.values()) {
const maybefuncArgs = hook.call(ctxt, funcArgs);
if (Array.isArray(maybefuncArgs))
funcArgs = maybefuncArgs;
}
let insteadPatchedFunc = (...args) => isConstruct ? Reflect.construct(patch.o, args, ctxt) : patch.o.apply(ctxt, args);
for (const callback of patch.i.values()) {
const oldPatchFunc = insteadPatchedFunc;
insteadPatchedFunc = (...args) => callback.call(ctxt, args, oldPatchFunc);
}
let workingRetVal = insteadPatchedFunc(...funcArgs);
for (const hook of patch.a.values())
workingRetVal = hook.call(ctxt, funcArgs, workingRetVal) ?? workingRetVal;
return workingRetVal;
}
// http-url:https://unpkg.com/spitroast@1.4.2/dist/esm/unpatch.js
function unpatch(funcParent, funcName, hookId, type) {
const patchedObject = patchedObjects.get(funcParent);
const patch = patchedObject?.[funcName];
if (!patch?.[type].has(hookId))
return false;
patch[type].delete(hookId);
if (patchTypes.every((t) => patch[t].size === 0)) {
const success = Reflect.defineProperty(funcParent, funcName, {
value: patch.o,
writable: true,
configurable: true
});
if (!success)
funcParent[funcName] = patch.o;
delete patchedObject[funcName];
}
if (Object.keys(patchedObject).length == 0)
patchedObjects.delete(funcParent);
return true;
}
// http-url:https://unpkg.com/spitroast@1.4.2/dist/esm/getPatchFunc.js
var getPatchFunc_default = (patchType) => (funcName, funcParent, callback, oneTime = false) => {
if (typeof funcParent[funcName] !== "function")
throw new Error(`${funcName} is not a function in ${funcParent.constructor.name}`);
if (!patchedObjects.has(funcParent))
patchedObjects.set(funcParent, {});
const parentInjections = patchedObjects.get(funcParent);
if (!parentInjections[funcName]) {
const origFunc = funcParent[funcName];
parentInjections[funcName] = {
o: origFunc,
b: /* @__PURE__ */ new Map(),
i: /* @__PURE__ */ new Map(),
a: /* @__PURE__ */ new Map()
};
const runHook = (ctxt, args, construct) => {
const ret = hook_default(funcName, funcParent, args, ctxt, construct);
if (oneTime)
unpatchThisPatch();
return ret;
};
const replaceProxy = new Proxy(origFunc, {
apply: (_, ctxt, args) => runHook(ctxt, args, false),
construct: (_, args) => runHook(origFunc, args, true),
get: (target, prop, receiver) => prop == "toString" ? origFunc.toString.bind(origFunc) : Reflect.get(target, prop, receiver)
});
const success = Reflect.defineProperty(funcParent, funcName, {
value: replaceProxy,
configurable: true,
writable: true
});
if (!success)
funcParent[funcName] = replaceProxy;
}
const hookId = Symbol();
const unpatchThisPatch = () => unpatch(funcParent, funcName, hookId, patchType);
parentInjections[funcName][patchType].set(hookId, callback);
return unpatchThisPatch;
};
// http-url:https://unpkg.com/spitroast@latest/dist/esm/index.js
var before = getPatchFunc_default("b");
before("open", window, (args) => {
if (!args?.[2]) return;
args.pop(2);
return args;
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment