2022-01-14 18:01:38 +00:00
|
|
|
/* typehints:start */
|
|
|
|
|
import { Application } from "../application";
|
|
|
|
|
/* typehints:end */
|
2022-01-14 07:55:18 +00:00
|
|
|
import { globalConfig } from "../core/config";
|
2022-01-13 20:20:42 +00:00
|
|
|
import { createLogger } from "../core/logging";
|
|
|
|
|
import { Mod } from "./mod";
|
|
|
|
|
import { ModInterface } from "./mod_interface";
|
2022-01-14 06:18:25 +00:00
|
|
|
import { MOD_SIGNALS } from "./mod_signals";
|
2022-01-13 20:20:42 +00:00
|
|
|
|
|
|
|
|
const LOG = createLogger("mods");
|
|
|
|
|
|
|
|
|
|
export class ModLoader {
|
|
|
|
|
constructor() {
|
|
|
|
|
LOG.log("modloader created");
|
|
|
|
|
|
2022-01-14 18:01:38 +00:00
|
|
|
/**
|
|
|
|
|
* @type {Application}
|
|
|
|
|
*/
|
|
|
|
|
this.app = undefined;
|
|
|
|
|
|
2022-01-13 20:20:42 +00:00
|
|
|
/** @type {Mod[]} */
|
|
|
|
|
this.mods = [];
|
|
|
|
|
|
2022-01-13 21:14:49 +00:00
|
|
|
this.modInterface = new ModInterface(this);
|
|
|
|
|
|
2022-01-14 06:37:26 +00:00
|
|
|
/** @type {((Object) => (new (Application, ModLoader) => Mod))[]} */
|
2022-01-13 21:14:49 +00:00
|
|
|
this.modLoadQueue = [];
|
2022-01-13 20:20:42 +00:00
|
|
|
|
|
|
|
|
this.initialized = false;
|
2022-01-13 21:14:49 +00:00
|
|
|
|
2022-01-14 06:18:25 +00:00
|
|
|
this.signals = MOD_SIGNALS;
|
2022-01-13 20:20:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
linkApp(app) {
|
|
|
|
|
this.app = app;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-14 07:55:18 +00:00
|
|
|
anyModsActive() {
|
|
|
|
|
return this.mods.length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-14 18:12:50 +00:00
|
|
|
exposeExports() {
|
|
|
|
|
if (G_IS_DEV || G_IS_STANDALONE) {
|
|
|
|
|
let exports = {};
|
|
|
|
|
const modules = require.context("../", true, /\.js$/);
|
|
|
|
|
Array.from(modules.keys()).forEach(key => {
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
const module = modules(key);
|
|
|
|
|
for (const member in module) {
|
|
|
|
|
if (member === "default") {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (exports[member]) {
|
|
|
|
|
throw new Error("Duplicate export of " + member);
|
|
|
|
|
}
|
|
|
|
|
Object.defineProperty(exports, member, {
|
|
|
|
|
get() {
|
|
|
|
|
return module[member];
|
|
|
|
|
},
|
|
|
|
|
set(v) {
|
|
|
|
|
module[member] = v;
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
window.shapez = exports;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-14 07:55:18 +00:00
|
|
|
async initMods() {
|
2022-01-13 20:20:42 +00:00
|
|
|
LOG.log("hook:init");
|
2022-01-14 06:51:48 +00:00
|
|
|
|
2022-01-14 18:12:50 +00:00
|
|
|
this.exposeExports();
|
|
|
|
|
|
2022-01-15 09:49:58 +00:00
|
|
|
window.registerMod = mod => {
|
|
|
|
|
this.modLoadQueue.push(mod);
|
|
|
|
|
};
|
|
|
|
|
|
2022-01-14 09:56:33 +00:00
|
|
|
if (G_IS_STANDALONE || G_IS_DEV) {
|
2022-01-14 07:55:18 +00:00
|
|
|
try {
|
2022-01-14 09:56:33 +00:00
|
|
|
let mods = [];
|
|
|
|
|
if (G_IS_STANDALONE) {
|
2022-01-15 09:49:58 +00:00
|
|
|
mods = await ipcRenderer.invoke("get-mods");
|
|
|
|
|
}
|
|
|
|
|
if (G_IS_DEV && globalConfig.debug.externalModUrl) {
|
2022-01-16 15:13:57 +00:00
|
|
|
const response = await fetch(globalConfig.debug.externalModUrl, {
|
|
|
|
|
method: "GET",
|
|
|
|
|
});
|
|
|
|
|
if (response.status !== 200) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
"Failed to load " +
|
|
|
|
|
globalConfig.debug.externalModUrl +
|
|
|
|
|
": " +
|
|
|
|
|
response.status +
|
|
|
|
|
" " +
|
|
|
|
|
response.statusText
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mods.push(await response.text());
|
2022-01-14 09:56:33 +00:00
|
|
|
}
|
2022-01-14 07:55:18 +00:00
|
|
|
|
|
|
|
|
mods.forEach(modCode => {
|
2022-01-15 11:30:57 +00:00
|
|
|
try {
|
|
|
|
|
const func = new Function(modCode);
|
2022-01-15 12:59:38 +00:00
|
|
|
func();
|
2022-01-15 11:30:57 +00:00
|
|
|
} catch (ex) {
|
|
|
|
|
console.error(ex);
|
|
|
|
|
alert("Failed to parse mod (launch with --dev for more info): " + ex);
|
|
|
|
|
}
|
2022-01-14 07:55:18 +00:00
|
|
|
});
|
|
|
|
|
} catch (ex) {
|
2022-01-15 11:30:57 +00:00
|
|
|
alert("Failed to load mods (launch with --dev for more info): " + ex);
|
2022-01-14 07:55:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-13 20:20:42 +00:00
|
|
|
this.initialized = true;
|
2022-01-13 21:14:49 +00:00
|
|
|
this.modLoadQueue.forEach(modClass => {
|
2022-01-15 11:30:57 +00:00
|
|
|
try {
|
|
|
|
|
const mod = new (modClass())(this.app, this);
|
|
|
|
|
mod.init();
|
|
|
|
|
this.mods.push(mod);
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
console.error(ex);
|
|
|
|
|
alert("Failed to initialize mods (launch with --dev for more info): " + ex);
|
|
|
|
|
}
|
2022-01-13 20:20:42 +00:00
|
|
|
});
|
2022-01-13 21:14:49 +00:00
|
|
|
this.modLoadQueue = [];
|
2022-01-15 09:49:58 +00:00
|
|
|
|
|
|
|
|
delete window.registerMod;
|
2022-01-13 20:20:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const MODS = new ModLoader();
|