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) => {
|
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);
|
const fname = path.join(storePath, filenameSafe);
|
||||||
switch (job.type) {
|
switch (job.type) {
|
||||||
case "read": {
|
case "read": {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
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 = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
website: "https://tobspr.io",
|
website: "https://tobspr.io",
|
||||||
author: "tobspr",
|
author: "tobspr",
|
||||||
|
|||||||
@ -77,7 +77,12 @@ export class Application {
|
|||||||
MODS.app = this;
|
MODS.app = this;
|
||||||
|
|
||||||
// MODS
|
// MODS
|
||||||
|
|
||||||
|
try {
|
||||||
await MODS.initMods();
|
await MODS.initMods();
|
||||||
|
} catch (ex) {
|
||||||
|
alert("Failed to load mods (launch with --dev for more info): \n\n" + ex);
|
||||||
|
}
|
||||||
|
|
||||||
this.unloaded = false;
|
this.unloaded = false;
|
||||||
|
|
||||||
|
|||||||
@ -7,17 +7,23 @@ import { MOD_SIGNALS } from "./mod_signals";
|
|||||||
|
|
||||||
export class Mod {
|
export class Mod {
|
||||||
/**
|
/**
|
||||||
* @param {Application} app
|
* @param {object} param0
|
||||||
* @param {ModLoader} modLoader
|
* @param {Application} param0.app
|
||||||
* @param {import("./modloader").ModMetadata} meta
|
* @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.app = app;
|
||||||
this.modLoader = modLoader;
|
this.modLoader = modLoader;
|
||||||
this.metadata = meta;
|
this.metadata = meta;
|
||||||
|
|
||||||
this.signals = MOD_SIGNALS;
|
this.signals = MOD_SIGNALS;
|
||||||
this.modInterface = modLoader.modInterface;
|
this.modInterface = modLoader.modInterface;
|
||||||
|
|
||||||
|
this.settings = settings;
|
||||||
|
this.saveSettings = saveSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|||||||
@ -3,6 +3,9 @@ import { Application } from "../application";
|
|||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { createLogger } from "../core/logging";
|
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 { Mod } from "./mod";
|
||||||
import { ModInterface } from "./mod_interface";
|
import { ModInterface } from "./mod_interface";
|
||||||
import { MOD_SIGNALS } from "./mod_signals";
|
import { MOD_SIGNALS } from "./mod_signals";
|
||||||
@ -17,6 +20,7 @@ const LOG = createLogger("mods");
|
|||||||
* website: string;
|
* website: string;
|
||||||
* description: string;
|
* description: string;
|
||||||
* id: string;
|
* id: string;
|
||||||
|
* settings: []
|
||||||
* }} ModMetadata
|
* }} ModMetadata
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -80,12 +84,20 @@ export class ModLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initMods() {
|
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();
|
this.exposeExports();
|
||||||
|
|
||||||
if (G_IS_STANDALONE || G_IS_DEV) {
|
|
||||||
try {
|
|
||||||
let mods = [];
|
let mods = [];
|
||||||
if (G_IS_STANDALONE) {
|
if (G_IS_STANDALONE) {
|
||||||
mods = await ipcRenderer.invoke("get-mods");
|
mods = await ipcRenderer.invoke("get-mods");
|
||||||
@ -110,11 +122,7 @@ export class ModLoader {
|
|||||||
|
|
||||||
window.$shapez_registerMod = (modClass, meta) => {
|
window.$shapez_registerMod = (modClass, meta) => {
|
||||||
if (this.modLoadQueue.some(entry => entry.meta.id === meta.id)) {
|
if (this.modLoadQueue.some(entry => entry.meta.id === meta.id)) {
|
||||||
console.warn(
|
console.warn("Not registering mod", meta, "since a mod with the same id is already loaded");
|
||||||
"Not registering mod",
|
|
||||||
meta,
|
|
||||||
"since a mod with the same id is already loaded"
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.modLoadQueue.push({
|
this.modLoadQueue.push({
|
||||||
@ -142,22 +150,45 @@ export class ModLoader {
|
|||||||
});
|
});
|
||||||
|
|
||||||
delete window.$shapez_registerMod;
|
delete window.$shapez_registerMod;
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
|
||||||
|
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) {
|
} catch (ex) {
|
||||||
alert("Failed to load mods (launch with --dev for more info): \n\n" + 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialized = true;
|
|
||||||
this.modLoadQueue.forEach(({ modClass, meta }) => {
|
|
||||||
try {
|
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();
|
mod.init();
|
||||||
this.mods.push(mod);
|
this.mods.push(mod);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.error(ex);
|
console.error(ex);
|
||||||
alert("Failed to initialize mods (launch with --dev for more info): \n\n" + ex);
|
alert("Failed to initialize mods (launch with --dev for more info): \n\n" + ex);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
this.modLoadQueue = [];
|
this.modLoadQueue = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user