diff --git a/src/js/application.js b/src/js/application.js index c49b7027..66e9eb8c 100644 --- a/src/js/application.js +++ b/src/js/application.js @@ -35,6 +35,8 @@ import { PuzzleMenuState } from "./states/puzzle_menu"; import { ClientAPI } from "./platform/api"; import { LoginState } from "./states/login"; import { WegameSplashState } from "./states/wegame_splash"; +import { MODS } from "./mods/modloader"; +import { MOD_SIGNALS } from "./mods/mod_signals"; /** * @typedef {import("./platform/achievement_provider").AchievementProviderInterface} AchievementProviderInterface @@ -128,6 +130,8 @@ export class Application { // Store the mouse position, or null if not available /** @type {Vector|null} */ this.mousePosition = null; + + MODS.initMods(); } /** @@ -148,6 +152,8 @@ export class Application { this.analytics = new GoogleAnalyticsImpl(this); this.gameAnalytics = new ShapezGameAnalytics(this); this.achievementProvider = new NoAchievementProvider(this); + + MOD_SIGNALS.platformInstancesInitialized.dispatch(); } /** diff --git a/src/js/game/modes/regular.js b/src/js/game/modes/regular.js index 699874b5..b52cbc89 100644 --- a/src/js/game/modes/regular.js +++ b/src/js/game/modes/regular.js @@ -69,10 +69,16 @@ const tierGrowth = 2.5; const chinaShapes = G_WEGAME_VERSION || G_CHINA_VERSION; +const upgradesCache = {}; + /** * Generates all upgrades * @returns {Object} */ function generateUpgrades(limitedVersion = false) { + if (upgradesCache[limitedVersion]) { + return upgradesCache[limitedVersion]; + } + const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1]; const numEndgameUpgrades = limitedVersion ? 0 : 1000 - fixedImprovements.length - 1; @@ -265,6 +271,8 @@ function generateUpgrades(limitedVersion = false) { } } + MOD_SIGNALS.modifyUpgrades.dispatch(upgrades); + // VALIDATE if (G_IS_DEV) { for (const upgradeId in upgrades) { @@ -280,14 +288,20 @@ function generateUpgrades(limitedVersion = false) { } } + upgradesCache[limitedVersion] = upgrades; return upgrades; } +const levelDefinitionsCache = {}; + /** * Generates the level definitions * @param {boolean} limitedVersion */ export function generateLevelDefinitions(limitedVersion = false) { + if (levelDefinitionsCache[limitedVersion]) { + return levelDefinitionsCache[limitedVersion]; + } const levelDefinitions = [ // 1 // Circle @@ -524,15 +538,11 @@ export function generateLevelDefinitions(limitedVersion = false) { }); } + levelDefinitionsCache[limitedVersion] = levelDefinitions; + return levelDefinitions; } -const fullVersionUpgrades = generateUpgrades(false); -const demoVersionUpgrades = generateUpgrades(true); - -const fullVersionLevels = generateLevelDefinitions(false); -const demoVersionLevels = generateLevelDefinitions(true); - export class RegularGameMode extends GameMode { static getId() { return enumGameModeIds.regular; @@ -603,9 +613,7 @@ export class RegularGameMode extends GameMode { * @returns {Object} */ getUpgrades() { - return this.root.app.restrictionMgr.getHasExtendedUpgrades() - ? fullVersionUpgrades - : demoVersionUpgrades; + return generateUpgrades(!this.root.app.restrictionMgr.getHasExtendedUpgrades()); } /** @@ -613,9 +621,7 @@ export class RegularGameMode extends GameMode { * @returns {Array} */ getLevelDefinitions() { - return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay() - ? fullVersionLevels - : demoVersionLevels; + return generateLevelDefinitions(!this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay()); } /** diff --git a/src/js/mods/demo_mod.js b/src/js/mods/demo_mod.js index 944cae38..e11c3667 100644 --- a/src/js/mods/demo_mod.js +++ b/src/js/mods/demo_mod.js @@ -20,8 +20,9 @@ export default function ({ Mod, MetaBuilding }) { } return class ModImpl extends Mod { - constructor(modLoader) { + constructor(app, modLoader) { super( + app, { authorContact: "tobias@tobspr.io", authorName: "tobspr", @@ -37,7 +38,7 @@ export default function ({ Mod, MetaBuilding }) { // Add some custom css this.modInterface.registerCss(` * { - color: red !important; + font-family: "Comic Sans", "Comic Sans MS", Tahoma !important; } `); diff --git a/src/js/mods/mod.js b/src/js/mods/mod.js index 12992999..b9018b68 100644 --- a/src/js/mods/mod.js +++ b/src/js/mods/mod.js @@ -1,4 +1,5 @@ /* typehints:start */ +import { Application } from "../application"; import { ModLoader } from "./modloader"; /* typehints:end */ @@ -7,6 +8,7 @@ import { MOD_SIGNALS } from "./mod_signals"; export class Mod { /** * + * @param {Application} app * @param {object} metadata * @param {string} metadata.name * @param {string} metadata.version @@ -16,7 +18,8 @@ export class Mod { * * @param {ModLoader} modLoader */ - constructor(metadata, modLoader) { + constructor(app, metadata, modLoader) { + this.app = app; this.metadata = metadata; this.modLoader = modLoader; diff --git a/src/js/mods/mod_interface.js b/src/js/mods/mod_interface.js index 5d395819..64c4971e 100644 --- a/src/js/mods/mod_interface.js +++ b/src/js/mods/mod_interface.js @@ -15,7 +15,7 @@ import { import { Loader } from "../core/loader"; import { LANGUAGES } from "../languages"; import { matchDataRecursive, T } from "../translations"; -import { registerBuildingVariant } from "../game/building_codes"; +import { gBuildingVariants, registerBuildingVariant } from "../game/building_codes"; import { gMetaBuildingRegistry } from "../core/global_registries"; import { MODS_ADDITIONAL_SHAPE_MAP_WEIGHTS } from "../game/map_chunk"; @@ -126,11 +126,15 @@ export class ModInterface { throw new Error("Tried to register building twice: " + id); } gMetaBuildingRegistry.register(metaClass); + const metaInstance = gMetaBuildingRegistry.findByClass(metaClass); T.buildings[id] = {}; variantsAndRotations.forEach(payload => { const actualVariant = payload.variant || defaultBuildingVariant; registerBuildingVariant(id, metaClass, actualVariant, payload.rotationVariant || 0); + + gBuildingVariants[id].metaInstance = metaInstance; + T.buildings[id][actualVariant] = { name: payload.name, description: payload.description, diff --git a/src/js/mods/mod_signals.js b/src/js/mods/mod_signals.js index a2bc0380..23670d8b 100644 --- a/src/js/mods/mod_signals.js +++ b/src/js/mods/mod_signals.js @@ -7,9 +7,12 @@ import { BaseHUDPart } from "../game/hud/base_hud_part"; export const MOD_SIGNALS = { postInit: new Signal(), + platformInstancesInitialized: new Signal(), + injectSprites: new Signal(), preprocessTheme: /** @type {TypedSignal<[Object]>} */ (new Signal()), modifyLevelDefinitions: /** @type {TypedSignal<[Array[Object]]>} */ (new Signal()), + modifyUpgrades: /** @type {TypedSignal<[Object]>} */ (new Signal()), hudElementInitialized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()), hudElementFinalized: /** @type {TypedSignal<[BaseHUDPart]>} */ (new Signal()), diff --git a/src/js/mods/modloader.js b/src/js/mods/modloader.js index 49e30662..8edc2d3d 100644 --- a/src/js/mods/modloader.js +++ b/src/js/mods/modloader.js @@ -15,20 +15,14 @@ export class ModLoader { this.modInterface = new ModInterface(this); - /** @type {(new (ModLoader) => Mod)[]} */ + /** @type {((Object) => (new (Application, ModLoader) => Mod))[]} */ this.modLoadQueue = []; this.initialized = false; this.signals = MOD_SIGNALS; - this.registerMod( - /** @type {any} */ (require("./demo_mod").default({ - Mod, - MetaBuilding, - })) - ); - this.initMods(); + this.registerMod(/** @type {any} */ (require("./demo_mod").default)); } linkApp(app) { @@ -39,7 +33,10 @@ export class ModLoader { LOG.log("hook:init"); this.initialized = true; this.modLoadQueue.forEach(modClass => { - const mod = new modClass(this); + const mod = new (modClass({ + Mod, + MetaBuilding, + }))(this.app, this); mod.init(); this.mods.push(mod); }); @@ -49,7 +46,7 @@ export class ModLoader { /** * - * @param {new (ModLoader) => Mod} mod + * @param {(Object) => (new (Application, ModLoader) => Mod)} mod */ registerMod(mod) { if (this.initialized) {