mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-14 02:31:51 +00:00
Refactor how mods are loaded to resolve circular dependencies and prepare for future mod loading
This commit is contained in:
parent
01b9bf561c
commit
16ecbf9c6d
@ -1,7 +1,7 @@
|
|||||||
import { globalConfig } from "../../core/config";
|
import { globalConfig } from "../../core/config";
|
||||||
import { DrawParameters } from "../../core/draw_parameters";
|
import { DrawParameters } from "../../core/draw_parameters";
|
||||||
import { Signal } from "../../core/signal";
|
import { Signal } from "../../core/signal";
|
||||||
import { MODS } from "../../mods/modloader";
|
import { MOD_SIGNALS } from "../../mods/mod_signals";
|
||||||
import { KEYMAPPINGS } from "../key_action_mapper";
|
import { KEYMAPPINGS } from "../key_action_mapper";
|
||||||
import { MetaBuilding } from "../meta_building";
|
import { MetaBuilding } from "../meta_building";
|
||||||
import { GameRoot } from "../root";
|
import { GameRoot } from "../root";
|
||||||
@ -92,7 +92,7 @@ export class GameHUD {
|
|||||||
|
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
for (const key in this.parts) {
|
for (const key in this.parts) {
|
||||||
MODS.signals.hudElementInitialized.dispatch(this.parts[key]);
|
MOD_SIGNALS.hudElementInitialized.dispatch(this.parts[key]);
|
||||||
this.parts[key].createElements(frag);
|
this.parts[key].createElements(frag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ export class GameHUD {
|
|||||||
|
|
||||||
for (const key in this.parts) {
|
for (const key in this.parts) {
|
||||||
this.parts[key].initialize();
|
this.parts[key].initialize();
|
||||||
MODS.signals.hudElementFinalized.dispatch(this.parts[key]);
|
MOD_SIGNALS.hudElementFinalized.dispatch(this.parts[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);
|
this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this);
|
||||||
|
|||||||
@ -10,10 +10,14 @@ import { COLOR_ITEM_SINGLETONS } from "./items/color_item";
|
|||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { enumSubShape } from "./shape_definition";
|
import { enumSubShape } from "./shape_definition";
|
||||||
import { Rectangle } from "../core/rectangle";
|
import { Rectangle } from "../core/rectangle";
|
||||||
import { MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS } from "../mods/mod_interface";
|
|
||||||
|
|
||||||
const logger = createLogger("map_chunk");
|
const logger = createLogger("map_chunk");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<string, (distanceToOriginInChunks: number) => number>}
|
||||||
|
*/
|
||||||
|
export const MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS = {};
|
||||||
|
|
||||||
export class MapChunk {
|
export class MapChunk {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@ -38,7 +38,7 @@ import { HUDSandboxController } from "../hud/parts/sandbox_controller";
|
|||||||
import { queryParamOptions } from "../../core/query_parameters";
|
import { queryParamOptions } from "../../core/query_parameters";
|
||||||
import { MetaBlockBuilding } from "../buildings/block";
|
import { MetaBlockBuilding } from "../buildings/block";
|
||||||
import { MetaItemProducerBuilding } from "../buildings/item_producer";
|
import { MetaItemProducerBuilding } from "../buildings/item_producer";
|
||||||
import { MODS } from "../../mods/modloader";
|
import { MOD_SIGNALS } from "../../mods/mod_signals";
|
||||||
|
|
||||||
/** @typedef {{
|
/** @typedef {{
|
||||||
* shape: string,
|
* shape: string,
|
||||||
@ -512,7 +512,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
|
|||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
MODS.signals.modifyLevelDefinitions.dispatch(levelDefinitions);
|
MOD_SIGNALS.modifyLevelDefinitions.dispatch(levelDefinitions);
|
||||||
|
|
||||||
if (G_IS_DEV) {
|
if (G_IS_DEV) {
|
||||||
levelDefinitions.forEach(({ shape }) => {
|
levelDefinitions.forEach(({ shape }) => {
|
||||||
|
|||||||
@ -3,11 +3,23 @@ import { globalConfig } from "../core/config";
|
|||||||
import { smoothenDpi } from "../core/dpi_manager";
|
import { smoothenDpi } from "../core/dpi_manager";
|
||||||
import { DrawParameters } from "../core/draw_parameters";
|
import { DrawParameters } from "../core/draw_parameters";
|
||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
import { MODS_ADDITIONAL_SUB_SHAPE_DRAWERS } from "../mods/mod_interface";
|
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors";
|
import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors";
|
||||||
import { THEME } from "./theme";
|
import { THEME } from "./theme";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* context: CanvasRenderingContext2D,
|
||||||
|
* quadrantSize: number,
|
||||||
|
* layerScale: number,
|
||||||
|
* }} SubShapeDrawOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<string, (options: SubShapeDrawOptions) => void>}
|
||||||
|
*/
|
||||||
|
export const MODS_ADDITIONAL_SUB_SHAPE_DRAWERS = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* subShape: enumSubShape,
|
* subShape: enumSubShape,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { MODS } from "../mods/modloader";
|
import { MOD_SIGNALS } from "../mods/mod_signals";
|
||||||
|
|
||||||
export const THEMES = {
|
export const THEMES = {
|
||||||
dark: require("./themes/dark.json"),
|
dark: require("./themes/dark.json"),
|
||||||
@ -9,5 +9,5 @@ export let THEME = THEMES.light;
|
|||||||
|
|
||||||
export function applyGameTheme(id) {
|
export function applyGameTheme(id) {
|
||||||
THEME = THEMES[id];
|
THEME = THEMES[id];
|
||||||
MODS.signals.preprocessTheme.dispatch({ id, theme: THEME });
|
MOD_SIGNALS.preprocessTheme.dispatch({ id, theme: THEME });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,8 @@
|
|||||||
import { Entity } from "../game/entity";
|
import { Entity } from "../game/entity";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { Mod } from "./mod";
|
export default function ({ Mod, MetaBuilding }) {
|
||||||
import { MetaBuilding } from "../game/meta_building";
|
class MetaDemoModBuilding extends MetaBuilding {
|
||||||
|
|
||||||
export class MetaDemoModBuilding extends MetaBuilding {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("demoModBuilding");
|
super("demoModBuilding");
|
||||||
}
|
}
|
||||||
@ -19,9 +17,9 @@ export class MetaDemoModBuilding extends MetaBuilding {
|
|||||||
* @param {Entity} entity
|
* @param {Entity} entity
|
||||||
*/
|
*/
|
||||||
setupEntityComponents(entity) {}
|
setupEntityComponents(entity) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DemoMod extends Mod {
|
return class ModImpl extends Mod {
|
||||||
constructor(modLoader) {
|
constructor(modLoader) {
|
||||||
super(
|
super(
|
||||||
{
|
{
|
||||||
@ -37,17 +35,17 @@ export class DemoMod extends Mod {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Add some custom css
|
// Add some custom css
|
||||||
this.modLoader.modInterface.registerCss(`
|
this.modInterface.registerCss(`
|
||||||
* {
|
* {
|
||||||
color: red !important;
|
color: red !important;
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Replace a builtin sprite
|
// Replace a builtin sprite
|
||||||
this.modLoader.modInterface.registerSprite("sprites/colors/red.png", RESOURCES["red.png"]);
|
this.modInterface.registerSprite("sprites/colors/red.png", RESOURCES["red.png"]);
|
||||||
|
|
||||||
// Add a new type of sub shape ("Line", short code "L")
|
// Add a new type of sub shape ("Line", short code "L")
|
||||||
this.modLoader.modInterface.registerSubShapeType({
|
this.modInterface.registerSubShapeType({
|
||||||
id: "line",
|
id: "line",
|
||||||
shortCode: "L",
|
shortCode: "L",
|
||||||
weightComputation: distanceToOriginInChunks =>
|
weightComputation: distanceToOriginInChunks =>
|
||||||
@ -69,17 +67,17 @@ export class DemoMod extends Mod {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Modify the theme colors
|
// Modify the theme colors
|
||||||
this.modLoader.signals.preprocessTheme.add(({ theme }) => {
|
this.signals.preprocessTheme.add(({ theme }) => {
|
||||||
theme.map.background = "#eee";
|
theme.map.background = "#eee";
|
||||||
theme.items.outline = "#000";
|
theme.items.outline = "#000";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Modify the goal of the first level
|
// Modify the goal of the first level
|
||||||
this.modLoader.signals.modifyLevelDefinitions.add(definitions => {
|
this.signals.modifyLevelDefinitions.add(definitions => {
|
||||||
definitions[0].shape = "LuCuLuCu";
|
definitions[0].shape = "LuCuLuCu";
|
||||||
});
|
});
|
||||||
|
|
||||||
this.modLoader.modInterface.registerTranslations("en", {
|
this.modInterface.registerTranslations("en", {
|
||||||
ingame: {
|
ingame: {
|
||||||
interactiveTutorial: {
|
interactiveTutorial: {
|
||||||
title: "Hello",
|
title: "Hello",
|
||||||
@ -91,7 +89,7 @@ export class DemoMod extends Mod {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Register the new building
|
// Register the new building
|
||||||
this.modLoader.modInterface.registerNewBuilding({
|
this.modInterface.registerNewBuilding({
|
||||||
metaClass: MetaDemoModBuilding,
|
metaClass: MetaDemoModBuilding,
|
||||||
buildingIconBase64: RESOURCES["demoBuilding.png"],
|
buildingIconBase64: RESOURCES["demoBuilding.png"],
|
||||||
|
|
||||||
@ -108,13 +106,14 @@ export class DemoMod extends Mod {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add it to the regular toolbar
|
// Add it to the regular toolbar
|
||||||
this.modLoader.signals.hudElementInitialized.add(element => {
|
this.signals.hudElementInitialized.add(element => {
|
||||||
if (element.constructor.name === "HUDBuildingsToolbar") {
|
if (element.constructor.name === "HUDBuildingsToolbar") {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
element.primaryBuildings.push(MetaDemoModBuilding);
|
element.primaryBuildings.push(MetaDemoModBuilding);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
import { ModLoader } from "./modloader";
|
import { ModLoader } from "./modloader";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
|
import { MOD_SIGNALS } from "./mod_signals";
|
||||||
|
|
||||||
export class Mod {
|
export class Mod {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -17,6 +19,9 @@ export class Mod {
|
|||||||
constructor(metadata, modLoader) {
|
constructor(metadata, modLoader) {
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.modLoader = modLoader;
|
this.modLoader = modLoader;
|
||||||
|
|
||||||
|
this.signals = MOD_SIGNALS;
|
||||||
|
this.modInterface = modLoader.modInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {}
|
init() {}
|
||||||
|
|||||||
@ -6,33 +6,21 @@ import { MetaBuilding } from "../game/meta_building";
|
|||||||
import { defaultBuildingVariant } from "../game/meta_building";
|
import { defaultBuildingVariant } from "../game/meta_building";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
|
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
|
||||||
import { enumShortcodeToSubShape, enumSubShape, enumSubShapeToShortcode } from "../game/shape_definition";
|
import {
|
||||||
|
enumShortcodeToSubShape,
|
||||||
|
enumSubShape,
|
||||||
|
enumSubShapeToShortcode,
|
||||||
|
MODS_ADDITIONAL_SUB_SHAPE_DRAWERS,
|
||||||
|
} from "../game/shape_definition";
|
||||||
import { Loader } from "../core/loader";
|
import { Loader } from "../core/loader";
|
||||||
import { LANGUAGES } from "../languages";
|
import { LANGUAGES } from "../languages";
|
||||||
import { matchDataRecursive, T } from "../translations";
|
import { matchDataRecursive, T } from "../translations";
|
||||||
import { registerBuildingVariant } from "../game/building_codes";
|
import { registerBuildingVariant } from "../game/building_codes";
|
||||||
import { gMetaBuildingRegistry } from "../core/global_registries";
|
import { gMetaBuildingRegistry } from "../core/global_registries";
|
||||||
|
import { MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS } from "../game/map_chunk";
|
||||||
|
|
||||||
const LOG = createLogger("mod-interface");
|
const LOG = createLogger("mod-interface");
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Object<string, (distanceToOriginInChunks: number) => number>}
|
|
||||||
*/
|
|
||||||
export const MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{
|
|
||||||
* context: CanvasRenderingContext2D,
|
|
||||||
* quadrantSize: number,
|
|
||||||
* layerScale: number,
|
|
||||||
* }} SubShapeDrawOptions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Object<string, (options: SubShapeDrawOptions) => void>}
|
|
||||||
*/
|
|
||||||
export const MODS_ADDITIONAL_SUB_SHAPE_DRAWERS = {};
|
|
||||||
|
|
||||||
export class ModInterface {
|
export class ModInterface {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -91,7 +79,7 @@ export class ModInterface {
|
|||||||
* @param {string} param0.id
|
* @param {string} param0.id
|
||||||
* @param {string} param0.shortCode
|
* @param {string} param0.shortCode
|
||||||
* @param {(distanceToOriginInChunks: number) => number} param0.weightComputation
|
* @param {(distanceToOriginInChunks: number) => number} param0.weightComputation
|
||||||
* @param {(options: SubShapeDrawOptions) => void} param0.draw
|
* @param {(options: import("../game/shape_definition").SubShapeDrawOptions) => void} param0.draw
|
||||||
*/
|
*/
|
||||||
registerSubShapeType({ id, shortCode, weightComputation, draw }) {
|
registerSubShapeType({ id, shortCode, weightComputation, draw }) {
|
||||||
if (shortCode.length !== 1) {
|
if (shortCode.length !== 1) {
|
||||||
|
|||||||
16
src/js/mods/mod_signals.js
Normal file
16
src/js/mods/mod_signals.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Signal } from "../core/signal";
|
||||||
|
/* typehints:start */
|
||||||
|
import { BaseHUDPart } from "../game/hud/base_hud_part";
|
||||||
|
/* typehints:end */
|
||||||
|
|
||||||
|
// Single file to avoid circular deps
|
||||||
|
|
||||||
|
export const MOD_SIGNALS = {
|
||||||
|
postInit: new Signal(),
|
||||||
|
injectSprites: new Signal(),
|
||||||
|
preprocessTheme: /** @type {TypedSignal<[Object]>} */ (new Signal()),
|
||||||
|
modifyLevelDefinitions: /** @type {TypedSignal<[Array[Object]]>} */ (new Signal()),
|
||||||
|
|
||||||
|
hudElementInitialized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
||||||
|
hudElementFinalized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
||||||
|
};
|
||||||
@ -1,9 +1,8 @@
|
|||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { Signal } from "../core/signal";
|
|
||||||
import { DemoMod } from "./demo_mod";
|
|
||||||
import { Mod } from "./mod";
|
import { Mod } from "./mod";
|
||||||
import { ModInterface } from "./mod_interface";
|
import { ModInterface } from "./mod_interface";
|
||||||
import { BaseHUDPart } from "../game/hud/base_hud_part";
|
import { MetaBuilding } from "../game/meta_building";
|
||||||
|
import { MOD_SIGNALS } from "./mod_signals";
|
||||||
|
|
||||||
const LOG = createLogger("mods");
|
const LOG = createLogger("mods");
|
||||||
|
|
||||||
@ -21,17 +20,14 @@ export class ModLoader {
|
|||||||
|
|
||||||
this.initialized = false;
|
this.initialized = false;
|
||||||
|
|
||||||
this.signals = {
|
this.signals = MOD_SIGNALS;
|
||||||
postInit: new Signal(),
|
|
||||||
injectSprites: new Signal(),
|
|
||||||
preprocessTheme: /** @type {TypedSignal<[Object]>} */ (new Signal()),
|
|
||||||
modifyLevelDefinitions: /** @type {TypedSignal<[Array[Object]]>} */ (new Signal()),
|
|
||||||
|
|
||||||
hudElementInitialized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
this.registerMod(
|
||||||
hudElementFinalized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()),
|
/** @type {any} */ (require("./demo_mod").default({
|
||||||
};
|
Mod,
|
||||||
|
MetaBuilding,
|
||||||
this.registerMod(DemoMod);
|
}))
|
||||||
|
);
|
||||||
this.initMods();
|
this.initMods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user