diff --git a/src/js/core/config.js b/src/js/core/config.js index fe18234f..634a96c9 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.js @@ -18,8 +18,10 @@ export const globalConfig = { assetsSharpness: 1.2, shapesSharpness: 1.4, + // Production analytics statisticsGraphDpi: 2.5, statisticsGraphSlices: 100, + analyticsSliceDurationSeconds: 10, // [Calculated] physics step size physicsDeltaMs: 0, @@ -41,8 +43,6 @@ export const globalConfig = { undergroundBeltMaxTiles: 5, - analyticsSliceDurationSeconds: 10, - buildingSpeeds: { cutter: 1 / 4, rotater: 1 / 1, diff --git a/src/js/game/hud/parts/statistics.js b/src/js/game/hud/parts/statistics.js index dc90d6eb..78a29373 100644 --- a/src/js/game/hud/parts/statistics.js +++ b/src/js/game/hud/parts/statistics.js @@ -7,6 +7,13 @@ import { BaseHUDPart } from "../base_hud_part"; import { DynamicDomAttach } from "../dynamic_dom_attach"; import { enumDisplayMode, HUDShapeStatisticsHandle } from "./statistics_handle"; +const enumDataSourceToText = { + [enumAnalyticsDataSource.stored]: "Displaying amount of stored shapes in your central building.", + [enumAnalyticsDataSource.produced]: + "Displaying all shapes your whole factory produces, including intermediate products.", + [enumAnalyticsDataSource.delivered]: "Displaying shapes which are delivered to your central building.", +}; + export class HUDStatistics extends BaseHUDPart { createElements(parent) { this.background = makeDiv(parent, "ingame_HUD_Statistics", ["ingameDialog"]); @@ -18,6 +25,7 @@ export class HUDStatistics extends BaseHUDPart { this.trackClicks(this.closeButton, this.close); this.filterHeader = makeDiv(this.dialogInner, null, ["filterHeader"]); + this.sourceExplanation = makeDiv(this.dialogInner, null, ["sourceExplanation"]); this.filtersDataSource = makeDiv(this.filterHeader, null, ["filtersDataSource"]); this.filtersDisplayMode = makeDiv(this.filterHeader, null, ["filtersDisplayMode"]); @@ -45,6 +53,8 @@ export class HUDStatistics extends BaseHUDPart { setDataSource(source) { this.dataSource = source; this.dialogInner.setAttribute("data-datasource", source); + + this.sourceExplanation.innerText = enumDataSourceToText[source]; if (this.visible) { this.rerenderFull(); } @@ -146,7 +156,22 @@ export class HUDStatistics extends BaseHUDPart { removeAllChildren(this.contentDiv); // Now, attach new ones - const entries = Object.entries(this.root.hubGoals.storedShapes); + + let entries = null; + switch (this.dataSource) { + case enumAnalyticsDataSource.stored: { + entries = Object.entries(this.root.hubGoals.storedShapes); + break; + } + case enumAnalyticsDataSource.produced: + case enumAnalyticsDataSource.delivered: { + entries = Object.entries(this.root.productionAnalytics.getCurrentShapeRates(this.dataSource)); + break; + } + } + + // const entries = Object.entries(this.root.hubGoals.storedShapes); + entries.sort((a, b) => b[1] - a[1]); let rendered = new Set(); @@ -155,9 +180,6 @@ export class HUDStatistics extends BaseHUDPart { const entry = entries[i]; const shapeKey = entry[0]; const amount = entry[1]; - if (amount < 1) { - continue; - } let handle = this.activeHandles[shapeKey]; if (!handle) { diff --git a/src/js/game/hud/parts/statistics_handle.js b/src/js/game/hud/parts/statistics_handle.js index 35326b6b..b39eeff8 100644 --- a/src/js/game/hud/parts/statistics_handle.js +++ b/src/js/game/hud/parts/statistics_handle.js @@ -116,16 +116,16 @@ export class HUDShapeStatisticsHandle { this.graphContext.strokeStyle = "#66ccbc"; this.graphContext.lineWidth = 1.5; - const sliceWidth = w / globalConfig.statisticsGraphSlices; + const sliceWidth = w / (globalConfig.statisticsGraphSlices - 1); let values = []; let maxValue = 1; - for (let i = 0; i < globalConfig.statisticsGraphSlices - 1; ++i) { + for (let i = 0; i < globalConfig.statisticsGraphSlices - 2; ++i) { const value = this.root.productionAnalytics.getPastShapeRate( dataSource, this.definition, - globalConfig.statisticsGraphSlices - i - 1 + globalConfig.statisticsGraphSlices - i - 2 ); if (value > maxValue) { maxValue = value; diff --git a/src/js/game/production_analytics.js b/src/js/game/production_analytics.js index eba4d6a1..23dd0e0d 100644 --- a/src/js/game/production_analytics.js +++ b/src/js/game/production_analytics.js @@ -3,6 +3,7 @@ import { ShapeDefinition } from "./shape_definition"; import { globalConfig } from "../core/config"; import { BaseItem } from "./base_item"; import { ShapeItem } from "./items/shape_item"; +import { BasicSerializableObject } from "../savegame/serialization"; /** @enum {string} */ export const enumAnalyticsDataSource = { @@ -11,11 +12,16 @@ export const enumAnalyticsDataSource = { delivered: "delivered", }; -export class ProductionAnalytics { +export class ProductionAnalytics extends BasicSerializableObject { + static getId() { + return "ProductionAnalytics"; + } + /** * @param {GameRoot} root */ constructor(root) { + super(); this.root = root; this.history = { @@ -50,6 +56,7 @@ export class ProductionAnalytics { if (item instanceof ShapeItem) { const definition = item.definition; const key = definition.getHash(); + console.log("Shape item produced:", key); const entry = this.history[enumAnalyticsDataSource.produced]; entry[entry.length - 1][key] = (entry[entry.length - 1][key] || 0) + 1; } @@ -73,21 +80,7 @@ export class ProductionAnalytics { } /** - * @param {ShapeDefinition} definition - */ - getCurrentShapeProductionRate(definition) { - const slices = this.history[enumAnalyticsDataSource.produced]; - return slices[slices.length - 2][definition.getHash()] || 0; - } - - /** - * @param {ShapeDefinition} definition - */ - getCurrentShapeDeliverRate(definition) { - const slices = this.history[enumAnalyticsDataSource.delivered]; - return slices[slices.length - 2][definition.getHash()] || 0; - } - /** + * Returns the current rate of a given shape * @param {enumAnalyticsDataSource} dataSource * @param {ShapeDefinition} definition */ @@ -97,19 +90,40 @@ export class ProductionAnalytics { } /** - * + * Returns the rate of a given shape, frames ago * @param {enumAnalyticsDataSource} dataSource * @param {ShapeDefinition} definition * @param {number} historyOffset */ getPastShapeRate(dataSource, definition, historyOffset) { assertAlways( - historyOffset >= 0 && historyOffset < globalConfig.statisticsGraphSlices, + historyOffset >= 0 && historyOffset < globalConfig.statisticsGraphSlices - 1, "Invalid slice offset: " + historyOffset ); const slices = this.history[dataSource]; - return slices[slices.length - 1 - historyOffset][definition.getHash()] || 0; + return slices[slices.length - 2 - historyOffset][definition.getHash()] || 0; + } + + /** + * Returns the rates of all shapes + * @param {enumAnalyticsDataSource} dataSource + */ + getCurrentShapeRates(dataSource) { + const slices = this.history[dataSource]; + + // First, copy current slice + const baseValues = Object.assign({}, slices[slices.length - 2]); + + // Add past values + for (let i = 0; i < 10; ++i) { + const pastValues = slices[slices.length - i - 3]; + for (const key in pastValues) { + baseValues[key] = baseValues[key] || 0; + } + } + + return baseValues; } update() {