From cf5d776270354763d1d5b9cdc7f9bc07762e495e Mon Sep 17 00:00:00 2001 From: tobspr Date: Thu, 14 May 2020 08:44:07 +0200 Subject: [PATCH] Add type hints to signals --- src/js/core/signal.js | 4 +-- src/js/game/hud/base_hud_part.js | 12 --------- src/js/game/hud/hud.js | 7 ++---- src/js/game/production_analytics.js | 17 ++++++++----- src/js/game/root.js | 35 +++++++++++++++------------ src/js/game/systems/item_processor.js | 10 ++++---- src/js/game/systems/miner.js | 4 +-- src/js/globals.d.ts | 11 +++++++++ src/js/states/ingame.js | 5 ++-- 9 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/js/core/signal.js b/src/js/core/signal.js index 57fe1fca..7daae4ea 100644 --- a/src/js/core/signal.js +++ b/src/js/core/signal.js @@ -8,7 +8,7 @@ export class Signal { /** * Adds a new signal listener - * @param {object} receiver + * @param {function} receiver * @param {object} scope */ add(receiver, scope = null) { @@ -40,7 +40,7 @@ export class Signal { /** * Removes a receiver - * @param {object} receiver + * @param {function} receiver */ remove(receiver) { let index = null; diff --git a/src/js/game/hud/base_hud_part.js b/src/js/game/hud/base_hud_part.js index cec7e525..cd6aff17 100644 --- a/src/js/game/hud/base_hud_part.js +++ b/src/js/game/hud/base_hud_part.js @@ -90,18 +90,6 @@ export class BaseHUDPart { // Helpers - /** - * Calls closeMethod if an overlay is opened - * @param {function=} closeMethod - */ - closeOnOverlayOpen(closeMethod = null) { - this.root.hud.signals.overlayOpened.add(overlay => { - if (overlay !== this) { - (closeMethod || this.close).call(this); - } - }, this); - } - /** * Helper method to construct a new click detector * @param {Element} element The element to listen on diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index 7cd3d461..1cb7d048 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -16,6 +16,7 @@ import { IS_MOBILE } from "../../core/config"; import { HUDMassSelector } from "./parts/mass_selector"; import { HUDVignetteOverlay } from "./parts/vignette_overlay"; import { HUDStatistics } from "./parts/statistics"; +import { MetaBuilding } from "../meta_building"; export class GameHUD { /** @@ -29,10 +30,6 @@ export class GameHUD { * Initializes the hud parts */ initialize() { - this.signals = { - overlayOpened: new Signal(/* overlay */), - }; - this.parts = { processingOverlay: new HUDProcessingOverlay(this.root), @@ -54,7 +51,7 @@ export class GameHUD { }; this.signals = { - selectedPlacementBuildingChanged: new Signal(/* metaBuilding|null */), + selectedPlacementBuildingChanged: /** @type {TypedSignal<[MetaBuilding|null]>} */ (new Signal()), }; if (!IS_MOBILE) { diff --git a/src/js/game/production_analytics.js b/src/js/game/production_analytics.js index 63c5083e..eba4d6a1 100644 --- a/src/js/game/production_analytics.js +++ b/src/js/game/production_analytics.js @@ -1,6 +1,8 @@ import { GameRoot } from "./root"; import { ShapeDefinition } from "./shape_definition"; import { globalConfig } from "../core/config"; +import { BaseItem } from "./base_item"; +import { ShapeItem } from "./items/shape_item"; /** @enum {string} */ export const enumAnalyticsDataSource = { @@ -27,7 +29,7 @@ export class ProductionAnalytics { } this.root.signals.shapeDelivered.add(this.onShapeDelivered, this); - this.root.signals.shapeProduced.add(this.onShapeProduced, this); + this.root.signals.itemProduced.add(this.onItemProduced, this); this.lastAnalyticsSlice = 0; } @@ -42,12 +44,15 @@ export class ProductionAnalytics { } /** - * @param {ShapeDefinition} definition + * @param {BaseItem} item */ - onShapeProduced(definition) { - const key = definition.getHash(); - const entry = this.history[enumAnalyticsDataSource.produced]; - entry[entry.length - 1][key] = (entry[entry.length - 1][key] || 0) + 1; + onItemProduced(item) { + if (item instanceof ShapeItem) { + const definition = item.definition; + const key = definition.getHash(); + const entry = this.history[enumAnalyticsDataSource.produced]; + entry[entry.length - 1][key] = (entry[entry.length - 1][key] || 0) + 1; + } } /** diff --git a/src/js/game/root.js b/src/js/game/root.js index 8bf5066c..41cd5eeb 100644 --- a/src/js/game/root.js +++ b/src/js/game/root.js @@ -28,6 +28,9 @@ import { PerlinNoise } from "../core/perlin_noise"; import { HubGoals } from "./hub_goals"; import { BufferMaintainer } from "../core/buffer_maintainer"; import { ProductionAnalytics } from "./production_analytics"; +import { Entity } from "./entity"; +import { ShapeDefinition } from "./shape_definition"; +import { BaseItem } from "./base_item"; /* typehints:end */ const logger = createLogger("game/root"); @@ -131,32 +134,32 @@ export class GameRoot { this.signals = { // Entities - entityAdded: new Signal(/* entity */), - entityGotNewComponent: new Signal(/* entity */), - entityQueuedForDestroy: new Signal(/* entity */), - entityDestroyed: new Signal(/* entity */), + entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()), + entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()), + entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()), + entityDestroyed: /** @type {TypedSignal<[Entity]>} */ (new Signal()), // Global - resized: new Signal(/* w, h */), // Game got resized, - readyToRender: new Signal(), - aboutToDestruct: new Signal(), + resized: /** @type {TypedSignal<[number, number]>} */ (new Signal()), + readyToRender: /** @type {TypedSignal<[]>} */ (new Signal()), + aboutToDestruct: /** @type {TypedSignal<[]>} */ new Signal(), // Game Hooks - gameSaved: new Signal(), // Game got saved - gameRestored: new Signal(), // Game got restored - gameOver: new Signal(), // Game over + gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved + gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored + gameOver: /** @type {TypedSignal<[]>} */ (new Signal()), // Game over - storyGoalCompleted: new Signal(/* level, reward */), - upgradePurchased: new Signal(), + storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()), + upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()), // Called right after game is initialized - postLoadHook: new Signal(), + postLoadHook: /** @type {TypedSignal<[]>} */ (new Signal()), // Can be used to trigger an async task - performAsync: new Signal(), + performAsync: /** @type {TypedSignal<[function]>} */ (new Signal()), - shapeDelivered: new Signal(/* definition */), - shapeProduced: new Signal(/* definition */), + shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()), + itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()), }; // RNG's diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js index 7937f642..2d36ae06 100644 --- a/src/js/game/systems/item_processor.js +++ b/src/js/game/systems/item_processor.js @@ -157,11 +157,9 @@ export class ItemProcessorSystem extends GameSystemWithFilter { item: new ShapeItem(cutDefinition1), requiredSlot: 0, }); - this.root.signals.shapeProduced.dispatch(cutDefinition1); } if (!cutDefinition2.isEntirelyEmpty()) { - this.root.signals.shapeProduced.dispatch(cutDefinition2); outItems.push({ item: new ShapeItem(cutDefinition2), requiredSlot: 1, @@ -178,7 +176,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter { const inputDefinition = inputItem.definition; const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition); - this.root.signals.shapeProduced.dispatch(rotatedDefinition); outItems.push({ item: new ShapeItem(rotatedDefinition), }); @@ -200,7 +197,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter { lowerItem.definition, upperItem.definition ); - this.root.signals.shapeProduced.dispatch(stackedDefinition); outItems.push({ item: new ShapeItem(stackedDefinition), }); @@ -253,7 +249,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter { colorItem.color ); - this.root.signals.shapeProduced.dispatch(colorizedDefinition); outItems.push({ item: new ShapeItem(colorizedDefinition), }); @@ -277,6 +272,11 @@ export class ItemProcessorSystem extends GameSystemWithFilter { assertAlways(false, "Unkown item processor type: " + processorComp.type); } + // Track produced items + for (let i = 0; i < outItems.length; ++i) { + this.root.signals.itemProduced.dispatch(outItems[i].item); + } + processorComp.itemsToEject = outItems; } diff --git a/src/js/game/systems/miner.js b/src/js/game/systems/miner.js index 7d9dc037..626378f2 100644 --- a/src/js/game/systems/miner.js +++ b/src/js/game/systems/miner.js @@ -38,9 +38,7 @@ export class MinerSystem extends GameSystemWithFilter { } // Analytics hook - if (lowerLayerItem instanceof ShapeItem) { - this.root.signals.shapeProduced.dispatch(lowerLayerItem.definition); - } + this.root.signals.itemProduced.dispatch(lowerLayerItem); // Try actually ejecting if (!ejectComp.tryEject(0, lowerLayerItem)) { diff --git a/src/js/globals.d.ts b/src/js/globals.d.ts index e9abe206..89c21dfd 100644 --- a/src/js/globals.d.ts +++ b/src/js/globals.d.ts @@ -193,3 +193,14 @@ declare class TypedTrackedState { setSilent(value: any): void; get(): T; } + +declare const STOP_PROPAGATION = "stop_propagation"; + +declare interface TypedSignal> { + add(receiver: (...args: T) => typeof STOP_PROPAGATION | void, scope?: object); + remove(receiver: (...args: T) => typeof STOP_PROPAGATION | void); + + dispatch(...args: T): typeof STOP_PROPAGATION | void; + + removeAll(); +} diff --git a/src/js/states/ingame.js b/src/js/states/ingame.js index eda9a9fb..87b5a930 100644 --- a/src/js/states/ingame.js +++ b/src/js/states/ingame.js @@ -92,7 +92,7 @@ export class InGameState extends GameState { getThemeMusic() { // set later - return MUSIC.gameBg; + return MUSIC.mainMenu; } onBeforeExit() { @@ -115,7 +115,7 @@ export class InGameState extends GameState { } getPauseOnFocusLost() { - return !this.isMultiplayer(); + return false; } getHasUnloadConfirmation() { @@ -407,7 +407,6 @@ export class InGameState extends GameState { return; if (!this.savegame || !this.savegame.isSaveable()) { - // Can not save in multiplayer return Promise.resolve(); }