forked from Demon/demoncord
Merge pull request 'Settings Menu injection.' (#2) from sink/demoncord:PATCH_settings-inj into master
Reviewed-on: ruthenic/demoncord#2master
commit
90d3756f23
@ -1,13 +1,14 @@
|
|||||||
import flow from 'rollup-plugin-flow'
|
import flow from "rollup-plugin-flow";
|
||||||
import { minify } from 'rollup-plugin-esbuild'
|
import { minify } from "rollup-plugin-esbuild";
|
||||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||||
import commonjs from '@rollup/plugin-commonjs';
|
import commonjs from "@rollup/plugin-commonjs";
|
||||||
|
import { defineConfig } from "rollup";
|
||||||
|
|
||||||
export default {
|
export default defineConfig({
|
||||||
input: 'src/index.js',
|
input: "src/index.js",
|
||||||
plugins: [flow(), commonjs(), nodeResolve(), minify()],
|
plugins: [flow(), commonjs(), nodeResolve(), minify()],
|
||||||
output: {
|
output: {
|
||||||
file: 'dist/build.js',
|
file: "dist/build.js",
|
||||||
format: "iife"
|
format: "iife",
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
|
@ -1,35 +1,43 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
const commandsSym = Symbol("__commands");
|
||||||
|
|
||||||
function init(obj: Object) {
|
function init(obj: Object) {
|
||||||
obj.demon.__commands = {}
|
obj.demon[commandsSym] = {};
|
||||||
obj.demon.patcher.after("sendMessage", obj.demon.webpack.findByProps("sendMessage"),
|
obj.demon.patcher.after(
|
||||||
(args, otherRes) => {
|
"sendMessage",
|
||||||
let res;
|
obj.demon.webpack.findByProps("sendMessage"),
|
||||||
for (const key of Reflect.ownKeys(obj.demon.__commands)) {
|
(args, otherRes) => {
|
||||||
let command = obj.demon.__commands[key]
|
let res;
|
||||||
if (args[1].content.split(" ")[0] === ">" + command.name) {
|
for (const key of Reflect.ownKeys(obj.demon[commandsSym])) {
|
||||||
res = command.callback(args)
|
let command = obj.demon[commandsSym][key];
|
||||||
break
|
if (args[1].content.split(" ")[0] === ">" + command.name) {
|
||||||
}
|
res = command.callback(args);
|
||||||
}
|
break;
|
||||||
if (res !== undefined) args[1].content = res
|
}
|
||||||
return args
|
}
|
||||||
}
|
if (res !== undefined) args[1].content = res;
|
||||||
)
|
return args;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// command = {
|
// command = {
|
||||||
// name: "name",
|
// name: "name",
|
||||||
// callback: (args)=>"Hello, world!"
|
// callback: (args)=>"Hello, world!"
|
||||||
// }
|
// }
|
||||||
function add(command: {name: string, callback: (args: Array<any>) => string}): ()=>void {
|
function add(command: {
|
||||||
let sym = Symbol(command.name);
|
name: string,
|
||||||
window.demon.__commands[sym] = command;
|
callback: (args: Array<any>) => string,
|
||||||
return () => {
|
}): () => void {
|
||||||
delete window.demon.__commands[sym];
|
let sym = Symbol(command.name);
|
||||||
}
|
window.demon[commandsSym][sym] = command;
|
||||||
|
return () => {
|
||||||
|
delete window.demon[commandsSym][sym];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
add: add,
|
add: add,
|
||||||
init: init
|
init: init,
|
||||||
}
|
};
|
||||||
|
@ -1,108 +1,122 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { get, set } from 'idb-keyval';
|
import { get, set } from "idb-keyval";
|
||||||
import logger from './utils/logger.js'
|
import logger from "./utils/logger.js";
|
||||||
|
import settingsInj from "./settingsInj.js";
|
||||||
|
|
||||||
|
const pluginsSym = Symbol("__plugins");
|
||||||
|
|
||||||
async function init(obj: Object): Promise<boolean> {
|
async function init(obj: Object): Promise<boolean> {
|
||||||
//TODO: check for enabled plugins in the idb, start them
|
//TODO: check for enabled plugins in the idb, start them
|
||||||
let globalSettings = await get("demoncord")
|
let globalSettings = await get("demoncord");
|
||||||
if (globalSettings === undefined) {
|
if (globalSettings === undefined) {
|
||||||
await set("demoncord", {plugin: {}})
|
await set("demoncord", { plugin: {} });
|
||||||
globalSettings = await get("demoncord")
|
globalSettings = await get("demoncord");
|
||||||
}
|
}
|
||||||
obj.demon.__plugins = {}
|
obj.demon[pluginsSym] = {};
|
||||||
for (let plug: Object in globalSettings.plugin) {
|
for (let plug: Object in globalSettings.plugin) {
|
||||||
plug = globalSettings.plugin[plug]
|
plug = globalSettings.plugin[plug];
|
||||||
if (plug.enabled) {
|
if (plug.enabled) {
|
||||||
startPlugin(plug.metadata.name)
|
startPlugin(plug.metadata.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addPlugin(iife: string, metadata: Object): Promise<boolean> {
|
async function addPlugin(iife: string, metadata: Object): Promise<boolean> {
|
||||||
// expected metadata: {name: "name", desc: "description", author: "author"}
|
// expected metadata: {name: "name", desc: "description", author: "author"}
|
||||||
const obj: Object = { // whether the plugin is started or stopped isn't going to be stored in the iDB, so it can be accessed more easily by all components
|
const obj: Object = {
|
||||||
metadata: metadata,
|
// whether the plugin is started or stopped isn't going to be stored in the iDB, so it can be accessed more easily by all components
|
||||||
iife: iife,
|
metadata: metadata,
|
||||||
enabled: false // should plugins be enabled by default? not sure
|
iife: iife,
|
||||||
}
|
enabled: false, // should plugins be enabled by default? not sure
|
||||||
const globalSettings: Object = await get("demoncord");
|
};
|
||||||
/*try {
|
const globalSettings: Object = await get("demoncord");
|
||||||
|
/*try {
|
||||||
if (globalSettings["plugin"][metadata.name] !== undefined) {
|
if (globalSettings["plugin"][metadata.name] !== undefined) {
|
||||||
log("Cannot add plugin that already exists!", "error", "Plugins")
|
console.error("[Demoncord] Cannot add plugin that already exists!")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} catch (error) {*/
|
} catch (error) {*/
|
||||||
globalSettings["plugin"][metadata.name] = obj
|
globalSettings["plugin"][metadata.name] = obj;
|
||||||
//} //Disabling checking for previous plugins for now as it is breaking literally fucking everything
|
//} //Disabling checking for previous plugins for now as it is breaking literally fucking everything
|
||||||
await set("demoncord", globalSettings)
|
await set("demoncord", globalSettings);
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function delPlugin(name: string): Promise<boolean> {
|
async function delPlugin(name: string): Promise<boolean> {
|
||||||
const globalSettings = await get("demoncord")
|
const globalSettings = await get("demoncord");
|
||||||
if (globalSettings["plugin"][name] === undefined) {
|
if (globalSettings["plugin"][name] === undefined) {
|
||||||
logger.error("Cannot remove non-existant plugin!", ["Plugins"])
|
logger.error("Cannot remove non-existant plugin!", ["Plugins"]);
|
||||||
return false
|
return false;
|
||||||
} else {
|
} else {
|
||||||
globalSettings["plugin"][name] = undefined
|
globalSettings["plugin"][name] = undefined;
|
||||||
delete globalSettings["plugin"][name]
|
delete globalSettings["plugin"][name];
|
||||||
}
|
}
|
||||||
await set("demoncord", globalSettings)
|
await set("demoncord", globalSettings);
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startPlugin(name: string): Promise<boolean> {
|
async function startPlugin(name: string): Promise<boolean> {
|
||||||
const globalSettings = await get("demoncord")
|
const globalSettings = await get("demoncord");
|
||||||
if (globalSettings["plugin"][name] === undefined) {
|
if (globalSettings["plugin"][name] === undefined) {
|
||||||
logger.error("Cannot start non-existant plugin!", ["Plugins"])
|
logger.error("Cannot start non-existant plugin!", ["Plugins"]);
|
||||||
return false
|
return false;
|
||||||
} else {
|
} else {
|
||||||
logger.log(`Starting ${name}...`, ["Plugins"])
|
logger.log(`Starting ${name}...`, ["Plugins"]);
|
||||||
const plug = globalSettings["plugin"][name]
|
const plug = globalSettings["plugin"][name];
|
||||||
const exports: Object = (0, eval)(plug.iife)
|
const exports: Object = (0, eval)(plug.iife);
|
||||||
const onStart: (ctx: Object)=>void = exports.onStart
|
const onStart: (ctx: Object) => void = exports.onStart;
|
||||||
let ctx = {} // ctx is how you're going to store things that need to be accessed in both onStart and onStop. dumb, i know
|
let ctx = {}; // ctx is how you're going to store things that need to be accessed in both onStart and onStop. dumb, i know
|
||||||
onStart(ctx)
|
onStart(ctx);
|
||||||
logger.log(`Started ${name}!`, ["Plugins"])
|
if (exports.settings)
|
||||||
window.demon.__plugins[name] = {status: 1, ctx: ctx}
|
settingsInj.registerSettingsEntry(
|
||||||
return true
|
name,
|
||||||
}
|
"DEMON_PLUGIN_SETTINGS_" + name,
|
||||||
|
exports.settings
|
||||||
|
);
|
||||||
|
logger.log(`Started ${name}!`, ["Plugins"]);
|
||||||
|
window.demon[pluginsSym][name] = { status: 1, ctx: ctx };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stopPlugin(name: string): Promise<boolean> {
|
async function stopPlugin(name: string): Promise<boolean> {
|
||||||
const globalSettings = await get("demoncord")
|
const globalSettings = await get("demoncord");
|
||||||
if (globalSettings["plugin"][name] === undefined ) {
|
if (globalSettings["plugin"][name] === undefined) {
|
||||||
logger.error("Cannot stop non-existant or non-running plugin!", ["Plugins"])
|
logger.error("Cannot stop non-existant or non-running plugin!", [
|
||||||
return false
|
"Plugins",
|
||||||
} else {
|
]);
|
||||||
logger.log(`Stopping ${name}...`, ["Plugins"])
|
return false;
|
||||||
const plug = globalSettings["plugin"][name]
|
} else {
|
||||||
const exports: Object = (0, eval)(plug.iife)
|
logger.log(`Stopping ${name}...`, ["Plugins"]);
|
||||||
const onStop: (ctx: Object)=>void = exports.onStop
|
const plug = globalSettings["plugin"][name];
|
||||||
onStop(window.demon.__plugins[name].ctx)
|
const exports: Object = (0, eval)(plug.iife);
|
||||||
logger.log(`Stopped ${name}!`, ["Plugins"])
|
const onStop: (ctx: Object) => void = exports.onStop;
|
||||||
return true
|
onStop(window.demon[pluginsSym][name].ctx);
|
||||||
}
|
settingsInj.unregisterSettingsEntry("DEMON_PLUGIN_SETTINGS_" + name);
|
||||||
|
logger.log(`Stopped ${name}!`, ["Plugins"]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function togglePlugin(name: string): Promise<boolean> {
|
async function togglePlugin(name: string): Promise<boolean> {
|
||||||
const globalSettings = await get("demoncord")
|
const globalSettings = await get("demoncord");
|
||||||
if (globalSettings["plugin"][name] === undefined) {
|
if (globalSettings["plugin"][name] === undefined) {
|
||||||
logger.error("Cannot toggle non-existant plugin!", ["Plugins"])
|
logger.error("Cannot toggle non-existant plugin!", ["Plugins"]);
|
||||||
return false
|
return false;
|
||||||
} else {
|
} else {
|
||||||
globalSettings["plugin"][name].enabled = !globalSettings["plugin"][name].enabled
|
globalSettings["plugin"][name].enabled =
|
||||||
await set("demoncord", globalSettings)
|
!globalSettings["plugin"][name].enabled;
|
||||||
return true
|
await set("demoncord", globalSettings);
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
init,
|
init,
|
||||||
addPlugin,
|
addPlugin,
|
||||||
delPlugin,
|
delPlugin,
|
||||||
startPlugin,
|
startPlugin,
|
||||||
stopPlugin,
|
stopPlugin,
|
||||||
togglePlugin
|
togglePlugin,
|
||||||
}
|
};
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import webpack from "./webpack";
|
||||||
|
|
||||||
|
const settingsSym = Symbol("__settings");
|
||||||
|
|
||||||
|
// super secret value that shouldnt be exposed, used internally to avoid section conflicts and the like
|
||||||
|
const ovrwrtSctnSym: symbol = Symbol("__overwriteSection");
|
||||||
|
|
||||||
|
const settingsView = webpack.find(
|
||||||
|
(m) => m.default && m.default.displayName === "SettingsView"
|
||||||
|
);
|
||||||
|
|
||||||
|
type getPredicateSectionsEntry =
|
||||||
|
| {
|
||||||
|
section: "HEADER",
|
||||||
|
label: string,
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
section: "DIVIDER",
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
section: string,
|
||||||
|
label: string,
|
||||||
|
component: Function,
|
||||||
|
};
|
||||||
|
|
||||||
|
function patch(args: mixed, ret: getPredicateSectionsEntry[]) {
|
||||||
|
const processedEntries = window.demon[settingsSym].entries.map((e) => ({
|
||||||
|
section:
|
||||||
|
(e[ovrwrtSctnSym] ? e[ovrwrtSctnSym] : "DEMON_SETTINGS_LOADER_") +
|
||||||
|
e.name,
|
||||||
|
label: e.name,
|
||||||
|
element: e.component,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const injectionIndex =
|
||||||
|
2 + ret.findIndex((section) => section.section === "Game Activity");
|
||||||
|
ret.splice(
|
||||||
|
injectionIndex,
|
||||||
|
0,
|
||||||
|
{ section: "HEADER", label: "Demon" },
|
||||||
|
...processedEntries,
|
||||||
|
{ section: "DIVIDER" }
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
window.demon[settingsSym] = {
|
||||||
|
patch: window.demon.patcher.after(
|
||||||
|
"getPredicateSections",
|
||||||
|
settingsView.default.prototype,
|
||||||
|
patch
|
||||||
|
),
|
||||||
|
entries: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// debug
|
||||||
|
window.__demontemp__UnpatchSettingsInj = unInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function unInit() {
|
||||||
|
window.demon[settingsSym].patch();
|
||||||
|
delete window.demon[settingsSym];
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterSettingsEntry(name: string) {
|
||||||
|
let s = window.demon[settingsSym];
|
||||||
|
s.entries = s.entries.filter(
|
||||||
|
(e) => (e[ovrwrtSctnSym] ? e[ovrwrtSctnSym] : e.name) !== name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerSettingsEntry(
|
||||||
|
name: string,
|
||||||
|
section: ?string,
|
||||||
|
component: Function
|
||||||
|
): () => void {
|
||||||
|
let entry: { [symbol | string]: any } = { name, component };
|
||||||
|
if (section) entry[ovrwrtSctnSym] = section;
|
||||||
|
window.demon[settingsSym].entries.push(entry);
|
||||||
|
return () => unregisterSettingsEntry(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init,
|
||||||
|
unInit,
|
||||||
|
registerSettingsEntry,
|
||||||
|
unregisterSettingsEntry,
|
||||||
|
ovrwrtSctnSymm: ovrwrtSctnSym,
|
||||||
|
};
|
@ -1,52 +1,49 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import Patcher from "simian"
|
import Patcher from "simian";
|
||||||
import webpack from "./api/webpack.js"
|
import webpack from "./api/webpack";
|
||||||
import common from "./api/common.js"
|
import common from "./api/common";
|
||||||
import commands from "./api/commands.js"
|
import commands from "./api/commands";
|
||||||
import plugins from "./api/plugins.js"
|
import plugins from "./api/plugins";
|
||||||
|
import settingsInj from "./api/settingsInj";
|
||||||
|
|
||||||
async function init(obj: Object): Promise<void> {
|
async function init(obj: Object): Promise<void> {
|
||||||
const patcher = new Patcher()
|
const patcher = new Patcher();
|
||||||
obj.demon = {
|
obj.demon = {
|
||||||
patcher: {
|
patcher: {
|
||||||
monkeyPatch: function(name: string, parentObj: Object, patches: Object): ()=>void {
|
monkeyPatch: function (
|
||||||
let [upb,upi,upa] = [()=>{},()=>{},()=>{}]
|
name: string,
|
||||||
if (patches.before !== undefined) upb = patcher.before(
|
parentObj: Object,
|
||||||
name,
|
patches: Object
|
||||||
parentObj,
|
): () => void {
|
||||||
patches.before
|
let [upb, upi, upa] = [() => {}, () => {}, () => {}];
|
||||||
)
|
if (patches.before !== undefined)
|
||||||
if (patches.instead !== undefined) upb = patcher.instead(
|
upb = patcher.before(name, parentObj, patches.before);
|
||||||
name,
|
if (patches.instead !== undefined)
|
||||||
parentObj,
|
upb = patcher.instead(name, parentObj, patches.instead);
|
||||||
patches.instead
|
if (patches.after !== undefined)
|
||||||
)
|
upb = patcher.after(name, parentObj, patches.after);
|
||||||
if (patches.after !== undefined) upb = patcher.after(
|
return () => {
|
||||||
name,
|
upb();
|
||||||
parentObj,
|
upi();
|
||||||
patches.after
|
upa();
|
||||||
)
|
};
|
||||||
return ()=>{
|
},
|
||||||
upb()
|
before: patcher.before,
|
||||||
upi()
|
instead: patcher.instead,
|
||||||
upa()
|
after: patcher.after,
|
||||||
}
|
},
|
||||||
},
|
webpack,
|
||||||
before: patcher.before,
|
common,
|
||||||
instead: patcher.instead,
|
commands: {
|
||||||
after: patcher.after
|
add: commands.add,
|
||||||
},
|
},
|
||||||
webpack,
|
__DO_NOT_USE_OR_YOU_WILL_BE_FIRED_UNTO_THE_DEPTHS_OF_HELL: {
|
||||||
common,
|
plugins,
|
||||||
commands: {
|
}
|
||||||
add: commands.add
|
};
|
||||||
},
|
commands.init(obj);
|
||||||
__DO_NOT_USE_OR_YOU_WILL_BE_FIRED_UNTO_THE_DEPTHS_OF_HELL: {
|
settingsInj.init();
|
||||||
plugins
|
plugins.init(obj);
|
||||||
}
|
|
||||||
}
|
|
||||||
commands.init(obj)
|
|
||||||
plugins.init(obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default init;
|
export default init;
|
||||||
|
Loading…
Reference in new issue