diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index ec38c305..f9c28d93 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -37,6 +37,7 @@ import { HUDScreenshotExporter } from "./parts/screenshot_exporter"; import { HUDColorBlindHelper } from "./parts/color_blind_helper"; import { HUDShapeViewer } from "./parts/shape_viewer"; import { HUDWiresOverlay } from "./parts/wires_overlay"; +import { HUDChangesDebugger } from "./parts/debug_changes"; export class GameHUD { /** @@ -72,6 +73,9 @@ export class GameHUD { screenshotExporter: new HUDScreenshotExporter(this.root), shapeViewer: new HUDShapeViewer(this.root), wiresOverlay: new HUDWiresOverlay(this.root), + + /** @type {HUDChangesDebugger} */ + changesDebugger: null, }; this.signals = { @@ -96,6 +100,10 @@ export class GameHUD { this.parts.watermark = new HUDWatermark(this.root); } + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.parts.changesDebugger = new HUDChangesDebugger(this.root); + } + if (this.root.app.settings.getAllSettings().offerHints) { this.parts.tutorialHints = new HUDPartTutorialHints(this.root); this.parts.interactiveTutorial = new HUDInteractiveTutorial(this.root); @@ -223,6 +231,7 @@ export class GameHUD { "buildingPlacer", "blueprintPlacer", "colorBlindHelper", + "changesDebugger", ]; for (let i = 0; i < partsOrder.length; ++i) { diff --git a/src/js/game/hud/parts/debug_changes.js b/src/js/game/hud/parts/debug_changes.js new file mode 100644 index 00000000..46ad5234 --- /dev/null +++ b/src/js/game/hud/parts/debug_changes.js @@ -0,0 +1,78 @@ +import { globalConfig } from "../../../core/config"; +import { DrawParameters } from "../../../core/draw_parameters"; +import { Rectangle } from "../../../core/rectangle"; +import { BaseHUDPart } from "../base_hud_part"; + +/** + * @typedef {{ + * label: string, + * area: Rectangle, + * hideAt: number, + * fillColor: string + * }} DebugChange + */ + +export class HUDChangesDebugger extends BaseHUDPart { + createElements(parent) {} + + initialize() { + /** @type {Array} */ + this.changes = []; + } + + /** + * Renders a new change + * @param {string} label Text to display + * @param {Rectangle} area Affected area world space + * @param {string} fillColor Color to display (Hex) + * @param {number=} timeToDisplay How long to display the change + */ + renderChange(label, area, fillColor, timeToDisplay = 2) { + this.changes.push({ + label, + area: area.clone(), + fillColor, + hideAt: this.root.time.realtimeNow() + timeToDisplay, + }); + } + + update() { + const now = this.root.time.realtimeNow(); + // Detect outdated changes + for (let i = 0; i < this.changes.length; ++i) { + const change = this.changes[i]; + if (change.hideAt <= now) { + this.changes.splice(i, 1); + i -= 1; + continue; + } + } + } + + /** + * + * @param {DrawParameters} parameters + */ + draw(parameters) { + for (let i = 0; i < this.changes.length; ++i) { + const change = this.changes[i]; + parameters.context.fillStyle = change.fillColor; + parameters.context.globalAlpha = 0.5; + parameters.context.fillRect( + change.area.x * globalConfig.tileSize, + change.area.y * globalConfig.tileSize, + change.area.w * globalConfig.tileSize, + change.area.h * globalConfig.tileSize + ); + + parameters.context.fillStyle = "#222"; + parameters.context.globalAlpha = 1; + parameters.context.font = "bold 8px GameFont"; + parameters.context.fillText( + change.label, + change.area.x * globalConfig.tileSize + 2, + change.area.y * globalConfig.tileSize + 12 + ); + } + } +} diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index 83273a07..10f57b4b 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -1,4 +1,4 @@ -import { Math_sqrt } from "../../core/builtins"; +import { Math_sqrt, Math_max } from "../../core/builtins"; import { globalConfig } from "../../core/config"; import { DrawParameters } from "../../core/draw_parameters"; import { gMetaBuildingRegistry } from "../../core/global_registries"; @@ -117,7 +117,9 @@ export class BeltSystem extends GameSystemWithFilter { } else { this.areaToRecompute = affectedArea.clone(); } - logger.log("Queuing recompute:", this.areaToRecompute); + if (G_IS_DEV) { + logger.log("Queuing recompute:", this.areaToRecompute); + } } } @@ -169,6 +171,15 @@ export class BeltSystem extends GameSystemWithFilter { computeBeltCache() { if (this.areaToRecompute) { logger.log("Updating belt cache by updating area:", this.areaToRecompute); + + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.root.hud.parts.changesDebugger.renderChange( + "belt-area", + this.areaToRecompute, + "#00fff6" + ); + } + for (let x = this.areaToRecompute.x; x < this.areaToRecompute.right(); ++x) { for (let y = this.areaToRecompute.y; y < this.areaToRecompute.bottom(); ++y) { const tile = this.root.map.getTileContentXY(x, y); @@ -182,6 +193,15 @@ export class BeltSystem extends GameSystemWithFilter { this.areaToRecompute = null; } else { logger.log("Doing full belt recompute"); + + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.root.hud.parts.changesDebugger.renderChange( + "", + new Rectangle(-1000, -1000, 2000, 2000), + "#00fff6" + ); + } + for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i]; entity.components.Belt.followUpCache = this.findFollowUpEntity(entity); @@ -246,6 +266,11 @@ export class BeltSystem extends GameSystemWithFilter { speedMultiplier = SQRT_2; } + // How much offset we add when transferring to a new belt + // This substracts one tick because the belt will be updated directly + // afterwards anyways + const takeoverOffset = 1.0 + beltSpeed * speedMultiplier; + // Not really nice. haven't found the reason for this yet. if (items.length > 2 / globalConfig.itemSpacingOnBelts) { beltComp.sortedItems = []; @@ -260,7 +285,7 @@ export class BeltSystem extends GameSystemWithFilter { if (beltComp.followUpCache) { const followUpBelt = beltComp.followUpCache.components.Belt; if (followUpBelt.canAcceptItem()) { - followUpBelt.takeItem(progressAndItem[1], progressAndItem[0] - 1.0); + followUpBelt.takeItem(progressAndItem[1], progressAndItem[0] - takeoverOffset); items.splice(itemIndex, 1); } else { // Well, we couldn't really take it to a follow up belt, keep it at diff --git a/src/js/game/systems/item_ejector.js b/src/js/game/systems/item_ejector.js index f448aef2..d6597ecd 100644 --- a/src/js/game/systems/item_ejector.js +++ b/src/js/game/systems/item_ejector.js @@ -56,10 +56,25 @@ export class ItemEjectorSystem extends GameSystemWithFilter { recomputeCache() { if (this.areaToRecompute) { logger.log("Recomputing cache using rectangle"); + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.root.hud.parts.changesDebugger.renderChange( + "ejector-area", + this.areaToRecompute, + "#fe50a6" + ); + } this.recomputeAreaCache(this.areaToRecompute); this.areaToRecompute = null; } else { logger.log("Full cache recompute"); + if (G_IS_DEV && globalConfig.debug.renderChanges) { + this.root.hud.parts.changesDebugger.renderChange( + "ejector-full", + new Rectangle(-1000, -1000, 2000, 2000), + "#fe50a6" + ); + } + // Try to find acceptors for every ejector for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i];