Settings Menu injection. #2
Merged
ruthenic
merged 5 commits from sink/demoncord:PATCH_settings-inj
into master
2 years ago
@ -1,13 +1,14 @@
|
||||
import flow from 'rollup-plugin-flow'
|
||||
import { minify } from 'rollup-plugin-esbuild'
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import flow from "rollup-plugin-flow";
|
||||
import { minify } from "rollup-plugin-esbuild";
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import { defineConfig } from "rollup";
|
||||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
plugins: [flow(), commonjs(), nodeResolve(), minify()],
|
||||
output: {
|
||||
file: 'dist/build.js',
|
||||
format: "iife"
|
||||
}
|
||||
}
|
||||
export default defineConfig({
|
||||
input: "src/index.js",
|
||||
plugins: [flow(), commonjs(), nodeResolve(), minify()],
|
||||
output: {
|
||||
file: "dist/build.js",
|
||||
format: "iife",
|
||||
},
|
||||
});
|
||||
|
@ -1,35 +1,43 @@
|
||||
// @flow
|
||||
|
||||
const commandsSym = Symbol("__commands");
|
||||
|
||||
function init(obj: Object) {
|
||||
obj.demon.__commands = {}
|
||||
obj.demon.patcher.after("sendMessage", obj.demon.webpack.findByProps("sendMessage"),
|
||||
(args, otherRes) => {
|
||||
let res;
|
||||
for (const key of Reflect.ownKeys(obj.demon.__commands)) {
|
||||
let command = obj.demon.__commands[key]
|
||||
if (args[1].content.split(" ")[0] === ">" + command.name) {
|
||||
res = command.callback(args)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (res !== undefined) args[1].content = res
|
||||
return args
|
||||
}
|
||||
)
|
||||
obj.demon[commandsSym] = {};
|
||||
obj.demon.patcher.after(
|
||||
"sendMessage",
|
||||
obj.demon.webpack.findByProps("sendMessage"),
|
||||
(args, otherRes) => {
|
||||
let res;
|
||||
for (const key of Reflect.ownKeys(obj.demon[commandsSym])) {
|
||||
let command = obj.demon[commandsSym][key];
|
||||
if (args[1].content.split(" ")[0] === ">" + command.name) {
|
||||
res = command.callback(args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res !== undefined) args[1].content = res;
|
||||
return args;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// command = {
|
||||
// name: "name",
|
||||
// callback: (args)=>"Hello, world!"
|
||||
// }
|
||||
function add(command: {name: string, callback: (args: Array<any>) => string}): ()=>void {
|
||||
let sym = Symbol(command.name);
|
||||
window.demon.__commands[sym] = command;
|
||||
return () => {
|
||||
delete window.demon.__commands[sym];
|
||||
}
|
||||
function add(command: {
|
||||
name: string,
|
||||
callback: (args: Array<any>) => string,
|
||||
}): () => void {
|
||||
let sym = Symbol(command.name);
|
||||
window.demon[commandsSym][sym] = command;
|
||||
return () => {
|
||||
delete window.demon[commandsSym][sym];
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
add: add,
|
||||
init: init
|
||||
}
|
||||
add: add,
|
||||
init: init,
|
||||
};
|
||||
|
@ -1,108 +1,122 @@
|
||||
// @flow
|
||||
import { get, set } from 'idb-keyval';
|
||||
import logger from './utils/logger.js'
|
||||
import { get, set } from "idb-keyval";
|
||||
import logger from "./utils/logger.js";
|
||||
import settingsInj from "./settingsInj.js";
|
||||
|
||||
const pluginsSym = Symbol("__plugins");
|
||||
|
||||
async function init(obj: Object): Promise<boolean> {
|
||||
//TODO: check for enabled plugins in the idb, start them
|
||||
let globalSettings = await get("demoncord")
|
||||
if (globalSettings === undefined) {
|
||||
await set("demoncord", {plugin: {}})
|
||||
globalSettings = await get("demoncord")
|
||||
}
|
||||
obj.demon.__plugins = {}
|
||||
for (let plug: Object in globalSettings.plugin) {
|
||||
plug = globalSettings.plugin[plug]
|
||||
if (plug.enabled) {
|
||||
startPlugin(plug.metadata.name)
|
||||
}
|
||||
}
|
||||
return true
|
||||
//TODO: check for enabled plugins in the idb, start them
|
||||
let globalSettings = await get("demoncord");
|
||||
if (globalSettings === undefined) {
|
||||
await set("demoncord", { plugin: {} });
|
||||
globalSettings = await get("demoncord");
|
||||
}
|
||||
obj.demon[pluginsSym] = {};
|
||||
for (let plug: Object in globalSettings.plugin) {
|
||||
plug = globalSettings.plugin[plug];
|
||||
if (plug.enabled) {
|
||||
startPlugin(plug.metadata.name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function addPlugin(iife: string, metadata: Object): Promise<boolean> {
|
||||
// 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
|
||||
metadata: metadata,
|
||||
iife: iife,
|
||||
enabled: false // should plugins be enabled by default? not sure
|
||||
}
|
||||
const globalSettings: Object = await get("demoncord");
|
||||
/*try {
|
||||
// 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
|
||||
metadata: metadata,
|
||||
iife: iife,
|
||||
enabled: false, // should plugins be enabled by default? not sure
|
||||
};
|
||||
const globalSettings: Object = await get("demoncord");
|
||||
/*try {
|
||||
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
|
||||
}
|
||||
} catch (error) {*/
|
||||
globalSettings["plugin"][metadata.name] = obj
|
||||
//} //Disabling checking for previous plugins for now as it is breaking literally fucking everything
|
||||
await set("demoncord", globalSettings)
|
||||
return true
|
||||
globalSettings["plugin"][metadata.name] = obj;
|
||||
//} //Disabling checking for previous plugins for now as it is breaking literally fucking everything
|
||||
await set("demoncord", globalSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function delPlugin(name: string): Promise<boolean> {
|
||||
const globalSettings = await get("demoncord")
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot remove non-existant plugin!", ["Plugins"])
|
||||
return false
|
||||
} else {
|
||||
globalSettings["plugin"][name] = undefined
|
||||
delete globalSettings["plugin"][name]
|
||||
}
|
||||
await set("demoncord", globalSettings)
|
||||
return true
|
||||
const globalSettings = await get("demoncord");
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot remove non-existant plugin!", ["Plugins"]);
|
||||
return false;
|
||||
} else {
|
||||
globalSettings["plugin"][name] = undefined;
|
||||
delete globalSettings["plugin"][name];
|
||||
}
|
||||
await set("demoncord", globalSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function startPlugin(name: string): Promise<boolean> {
|
||||
const globalSettings = await get("demoncord")
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot start non-existant plugin!", ["Plugins"])
|
||||
return false
|
||||
} else {
|
||||
logger.log(`Starting ${name}...`, ["Plugins"])
|
||||
const plug = globalSettings["plugin"][name]
|
||||
const exports: Object = (0, eval)(plug.iife)
|
||||
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
|
||||
onStart(ctx)
|
||||
logger.log(`Started ${name}!`, ["Plugins"])
|
||||
window.demon.__plugins[name] = {status: 1, ctx: ctx}
|
||||
return true
|
||||
}
|
||||
const globalSettings = await get("demoncord");
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot start non-existant plugin!", ["Plugins"]);
|
||||
return false;
|
||||
} else {
|
||||
logger.log(`Starting ${name}...`, ["Plugins"]);
|
||||
const plug = globalSettings["plugin"][name];
|
||||
const exports: Object = (0, eval)(plug.iife);
|
||||
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
|
||||
onStart(ctx);
|
||||
if (exports.settings)
|
||||
settingsInj.registerSettingsEntry(
|
||||
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> {
|
||||
const globalSettings = await get("demoncord")
|
||||
if (globalSettings["plugin"][name] === undefined ) {
|
||||
logger.error("Cannot stop non-existant or non-running plugin!", ["Plugins"])
|
||||
return false
|
||||
} else {
|
||||
logger.log(`Stopping ${name}...`, ["Plugins"])
|
||||
const plug = globalSettings["plugin"][name]
|
||||
const exports: Object = (0, eval)(plug.iife)
|
||||
const onStop: (ctx: Object)=>void = exports.onStop
|
||||
onStop(window.demon.__plugins[name].ctx)
|
||||
logger.log(`Stopped ${name}!`, ["Plugins"])
|
||||
return true
|
||||
}
|
||||
const globalSettings = await get("demoncord");
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot stop non-existant or non-running plugin!", [
|
||||
"Plugins",
|
||||
]);
|
||||
return false;
|
||||
} else {
|
||||
logger.log(`Stopping ${name}...`, ["Plugins"]);
|
||||
const plug = globalSettings["plugin"][name];
|
||||
const exports: Object = (0, eval)(plug.iife);
|
||||
const onStop: (ctx: Object) => void = exports.onStop;
|
||||
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> {
|
||||
const globalSettings = await get("demoncord")
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot toggle non-existant plugin!", ["Plugins"])
|
||||
return false
|
||||
} else {
|
||||
globalSettings["plugin"][name].enabled = !globalSettings["plugin"][name].enabled
|
||||
await set("demoncord", globalSettings)
|
||||
return true
|
||||
}
|
||||
const globalSettings = await get("demoncord");
|
||||
if (globalSettings["plugin"][name] === undefined) {
|
||||
logger.error("Cannot toggle non-existant plugin!", ["Plugins"]);
|
||||
return false;
|
||||
} else {
|
||||
globalSettings["plugin"][name].enabled =
|
||||
!globalSettings["plugin"][name].enabled;
|
||||
await set("demoncord", globalSettings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
init,
|
||||
addPlugin,
|
||||
delPlugin,
|
||||
startPlugin,
|
||||
stopPlugin,
|
||||
togglePlugin
|
||||
}
|
||||
init,
|
||||
addPlugin,
|
||||
delPlugin,
|
||||
startPlugin,
|
||||
stopPlugin,
|
||||
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
|
||||
import Patcher from "simian"
|
||||
import webpack from "./api/webpack.js"
|
||||
import common from "./api/common.js"
|
||||
import commands from "./api/commands.js"
|
||||
import plugins from "./api/plugins.js"
|
||||
import Patcher from "simian";
|
||||
import webpack from "./api/webpack";
|
||||
import common from "./api/common";
|
||||
import commands from "./api/commands";
|
||||
import plugins from "./api/plugins";
|
||||
import settingsInj from "./api/settingsInj";
|
||||
|
||||
async function init(obj: Object): Promise<void> {
|
||||
const patcher = new Patcher()
|
||||
obj.demon = {
|
||||
patcher: {
|
||||
monkeyPatch: function(name: string, parentObj: Object, patches: Object): ()=>void {
|
||||
let [upb,upi,upa] = [()=>{},()=>{},()=>{}]
|
||||
if (patches.before !== undefined) upb = patcher.before(
|
||||
name,
|
||||
parentObj,
|
||||
patches.before
|
||||
)
|
||||
if (patches.instead !== undefined) upb = patcher.instead(
|
||||
name,
|
||||
parentObj,
|
||||
patches.instead
|
||||
)
|
||||
if (patches.after !== undefined) upb = patcher.after(
|
||||
name,
|
||||
parentObj,
|
||||
patches.after
|
||||
)
|
||||
return ()=>{
|
||||
upb()
|
||||
upi()
|
||||
upa()
|
||||
}
|
||||
},
|
||||
before: patcher.before,
|
||||
instead: patcher.instead,
|
||||
after: patcher.after
|
||||
},
|
||||
webpack,
|
||||
common,
|
||||
commands: {
|
||||
add: commands.add
|
||||
},
|
||||
__DO_NOT_USE_OR_YOU_WILL_BE_FIRED_UNTO_THE_DEPTHS_OF_HELL: {
|
||||
plugins
|
||||
}
|
||||
}
|
||||
commands.init(obj)
|
||||
plugins.init(obj)
|
||||
const patcher = new Patcher();
|
||||
obj.demon = {
|
||||
patcher: {
|
||||
monkeyPatch: function (
|
||||
name: string,
|
||||
parentObj: Object,
|
||||
patches: Object
|
||||
): () => void {
|
||||
let [upb, upi, upa] = [() => {}, () => {}, () => {}];
|
||||
if (patches.before !== undefined)
|
||||
upb = patcher.before(name, parentObj, patches.before);
|
||||
if (patches.instead !== undefined)
|
||||
upb = patcher.instead(name, parentObj, patches.instead);
|
||||
if (patches.after !== undefined)
|
||||
upb = patcher.after(name, parentObj, patches.after);
|
||||
return () => {
|
||||
upb();
|
||||
upi();
|
||||
upa();
|
||||
};
|
||||
},
|
||||
before: patcher.before,
|
||||
instead: patcher.instead,
|
||||
after: patcher.after,
|
||||
},
|
||||
webpack,
|
||||
common,
|
||||
commands: {
|
||||
add: commands.add,
|
||||
},
|
||||
__DO_NOT_USE_OR_YOU_WILL_BE_FIRED_UNTO_THE_DEPTHS_OF_HELL: {
|
||||
plugins,
|
||||
}
|
||||
};
|
||||
commands.init(obj);
|
||||
settingsInj.init();
|
||||
plugins.init(obj);
|
||||
}
|
||||
|
||||
export default init;
|
||||
|
Loading…
Reference in new issue