1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-17 12:11:51 +00:00
tobspr_shapez.io/src/js/mods/modloader.js

151 lines
4.3 KiB
JavaScript
Raw Normal View History

/* 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";
import { MOD_SIGNALS } from "./mod_signals";
2022-01-13 20:20:42 +00:00
const LOG = createLogger("mods");
2022-01-16 16:05:13 +00:00
/**
* @typedef {{
* name: string;
* version: string;
* author: string;
* website: string;
* description: string;
* id: string;
* }} ModMetadata
*/
2022-01-13 20:20:42 +00:00
export class ModLoader {
constructor() {
LOG.log("modloader created");
/**
* @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-16 16:05:13 +00:00
/** @type {({ meta: ModMetadata, modClass: typeof 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
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 18:12:50 +00:00
this.exposeExports();
2022-01-16 16:05:13 +00:00
window.$shapez_registerMod = (modClass, meta) => {
this.modLoadQueue.push({
modClass,
meta,
});
2022-01-15 09:49:58 +00:00
};
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 {
2022-01-16 16:05:13 +00:00
modCode += "\n;window.$shapez_registerMod(Mod, METADATA);";
2022-01-15 11:30:57 +00:00
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-16 16:05:13 +00:00
this.modLoadQueue.forEach(({ modClass, meta }) => {
2022-01-15 11:30:57 +00:00
try {
2022-01-16 16:05:13 +00:00
const mod = new modClass(this.app, this, meta);
2022-01-15 11:30:57 +00:00
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
2022-01-16 16:05:13 +00:00
delete window.$shapez_registerMod;
2022-01-13 20:20:42 +00:00
}
}
export const MODS = new ModLoader();