mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-13 18:21:51 +00:00
Support for mod settings
This commit is contained in:
parent
fd0ae12a84
commit
54a69c9725
@ -316,7 +316,7 @@ async function writeFileSafe(filename, contents) {
|
||||
}
|
||||
|
||||
ipcMain.handle("fs-job", async (event, job) => {
|
||||
const filenameSafe = job.filename.replace(/[^a-z\.\-_0-9]/i, "");
|
||||
const filenameSafe = job.filename.replace(/[^a-z\.\-_0-9]/i, "_");
|
||||
const fname = path.join(storePath, filenameSafe);
|
||||
switch (job.type) {
|
||||
case "read": {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
31
mod_examples/mod_settings.js
Normal file
31
mod_examples/mod_settings.js
Normal file
@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
name: "Mod Example: Mod Settings",
|
||||
version: "1",
|
||||
id: "base",
|
||||
description: "Shows how to add settings to your mod",
|
||||
|
||||
settings: {
|
||||
timesLaunched: 0,
|
||||
},
|
||||
};
|
||||
|
||||
class Mod extends shapez.Mod {
|
||||
init() {
|
||||
// Increment the setting every time we launch the mod
|
||||
this.settings.timesLaunched++;
|
||||
this.saveSettings();
|
||||
|
||||
// Show a dialog in the main menu wit the settings
|
||||
this.signals.stateEntered.add(state => {
|
||||
if (state instanceof shapez.MainMenuState) {
|
||||
this.dialogs.showInfo(
|
||||
"Welcome back",
|
||||
"You have launched this mod " + this.settings.timesLaunched + " times"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
const METADATA = {
|
||||
website: "https://tobspr.io",
|
||||
author: "tobspr",
|
||||
|
||||
@ -77,7 +77,12 @@ export class Application {
|
||||
MODS.app = this;
|
||||
|
||||
// MODS
|
||||
await MODS.initMods();
|
||||
|
||||
try {
|
||||
await MODS.initMods();
|
||||
} catch (ex) {
|
||||
alert("Failed to load mods (launch with --dev for more info): \n\n" + ex);
|
||||
}
|
||||
|
||||
this.unloaded = false;
|
||||
|
||||
|
||||
@ -7,17 +7,23 @@ import { MOD_SIGNALS } from "./mod_signals";
|
||||
|
||||
export class Mod {
|
||||
/**
|
||||
* @param {Application} app
|
||||
* @param {ModLoader} modLoader
|
||||
* @param {import("./modloader").ModMetadata} meta
|
||||
* @param {object} param0
|
||||
* @param {Application} param0.app
|
||||
* @param {ModLoader} param0.modLoader
|
||||
* @param {import("./modloader").ModMetadata} param0.meta
|
||||
* @param {Object} param0.settings
|
||||
* @param {() => Promise<void>} param0.saveSettings
|
||||
*/
|
||||
constructor(app, modLoader, meta) {
|
||||
constructor({ app, modLoader, meta, settings, saveSettings }) {
|
||||
this.app = app;
|
||||
this.modLoader = modLoader;
|
||||
this.metadata = meta;
|
||||
|
||||
this.signals = MOD_SIGNALS;
|
||||
this.modInterface = modLoader.modInterface;
|
||||
|
||||
this.settings = settings;
|
||||
this.saveSettings = saveSettings;
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
@ -3,6 +3,9 @@ import { Application } from "../application";
|
||||
/* typehints:end */
|
||||
import { globalConfig } from "../core/config";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { StorageImplBrowserIndexedDB } from "../platform/browser/storage_indexed_db";
|
||||
import { StorageImplElectron } from "../platform/electron/storage";
|
||||
import { FILE_NOT_FOUND } from "../platform/storage";
|
||||
import { Mod } from "./mod";
|
||||
import { ModInterface } from "./mod_interface";
|
||||
import { MOD_SIGNALS } from "./mod_signals";
|
||||
@ -17,6 +20,7 @@ const LOG = createLogger("mods");
|
||||
* website: string;
|
||||
* description: string;
|
||||
* id: string;
|
||||
* settings: []
|
||||
* }} ModMetadata
|
||||
*/
|
||||
|
||||
@ -80,51 +84,55 @@ export class ModLoader {
|
||||
}
|
||||
|
||||
async initMods() {
|
||||
LOG.log("hook:init");
|
||||
if (!G_IS_STANDALONE && !G_IS_DEV) {
|
||||
this.initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a storage for reading mod settings
|
||||
const storage = G_IS_STANDALONE
|
||||
? new StorageImplElectron(this.app)
|
||||
: new StorageImplBrowserIndexedDB(this.app);
|
||||
await storage.initialize();
|
||||
|
||||
LOG.log("hook:init", this.app, this.app.storage);
|
||||
this.exposeExports();
|
||||
|
||||
if (G_IS_STANDALONE || G_IS_DEV) {
|
||||
try {
|
||||
let mods = [];
|
||||
if (G_IS_STANDALONE) {
|
||||
mods = await ipcRenderer.invoke("get-mods");
|
||||
}
|
||||
if (G_IS_DEV && globalConfig.debug.externalModUrl) {
|
||||
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
|
||||
);
|
||||
}
|
||||
let mods = [];
|
||||
if (G_IS_STANDALONE) {
|
||||
mods = await ipcRenderer.invoke("get-mods");
|
||||
}
|
||||
if (G_IS_DEV && globalConfig.debug.externalModUrl) {
|
||||
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());
|
||||
}
|
||||
mods.push(await response.text());
|
||||
}
|
||||
|
||||
window.$shapez_registerMod = (modClass, meta) => {
|
||||
if (this.modLoadQueue.some(entry => entry.meta.id === meta.id)) {
|
||||
console.warn(
|
||||
"Not registering mod",
|
||||
meta,
|
||||
"since a mod with the same id is already loaded"
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.modLoadQueue.push({
|
||||
modClass,
|
||||
meta,
|
||||
});
|
||||
};
|
||||
window.$shapez_registerMod = (modClass, meta) => {
|
||||
if (this.modLoadQueue.some(entry => entry.meta.id === meta.id)) {
|
||||
console.warn("Not registering mod", meta, "since a mod with the same id is already loaded");
|
||||
return;
|
||||
}
|
||||
this.modLoadQueue.push({
|
||||
modClass,
|
||||
meta,
|
||||
});
|
||||
};
|
||||
|
||||
mods.forEach(modCode => {
|
||||
modCode += `
|
||||
mods.forEach(modCode => {
|
||||
modCode += `
|
||||
if (typeof Mod !== 'undefined') {
|
||||
if (typeof METADATA !== 'object') {
|
||||
throw new Error("No METADATA variable found");
|
||||
@ -132,32 +140,55 @@ export class ModLoader {
|
||||
window.$shapez_registerMod(Mod, METADATA);
|
||||
}
|
||||
`;
|
||||
try {
|
||||
const func = new Function(modCode);
|
||||
func();
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
alert("Failed to parse mod (launch with --dev for more info): \n\n" + ex);
|
||||
}
|
||||
});
|
||||
|
||||
delete window.$shapez_registerMod;
|
||||
try {
|
||||
const func = new Function(modCode);
|
||||
func();
|
||||
} catch (ex) {
|
||||
alert("Failed to load mods (launch with --dev for more info): \n\n" + ex);
|
||||
console.error(ex);
|
||||
alert("Failed to parse mod (launch with --dev for more info): \n\n" + ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
delete window.$shapez_registerMod;
|
||||
|
||||
this.initialized = true;
|
||||
this.modLoadQueue.forEach(({ modClass, meta }) => {
|
||||
|
||||
for (let i = 0; i < this.modLoadQueue.length; i++) {
|
||||
const { modClass, meta } = this.modLoadQueue[i];
|
||||
const modDataFile = "modsettings_" + meta.id + "__" + meta.version + ".json";
|
||||
|
||||
let settings = meta.settings;
|
||||
|
||||
if (meta.settings) {
|
||||
try {
|
||||
const storedSettings = await storage.readFileAsync(modDataFile);
|
||||
settings = JSON.parse(storedSettings);
|
||||
} catch (ex) {
|
||||
if (ex === FILE_NOT_FOUND) {
|
||||
// Write default data
|
||||
await storage.writeFileAsync(modDataFile, JSON.stringify(meta.settings));
|
||||
} else {
|
||||
alert("Failed to load settings for " + meta.id + ", will use defaults:\n\n" + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const mod = new modClass(this.app, this, meta);
|
||||
const mod = new modClass({
|
||||
app: this.app,
|
||||
modLoader: this,
|
||||
meta,
|
||||
settings,
|
||||
saveSettings: () => storage.writeFileAsync(modDataFile, JSON.stringify(mod.settings)),
|
||||
});
|
||||
mod.init();
|
||||
this.mods.push(mod);
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
alert("Failed to initialize mods (launch with --dev for more info): \n\n" + ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.modLoadQueue = [];
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user