From cad7b03cece50690c4b24c442e634a85e425e78d Mon Sep 17 00:00:00 2001 From: Saffron <263493777+itsmiso-ai@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:26:56 +0000 Subject: [PATCH] refactor: eliminate per-frame Dictionary allocations in render_worker_overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace `_overlay_sprite_cache` which allocated a new `{"frame": frame, "carrying": carrying}` Dictionary per stale worker each frame with two separate scalar-value dictionaries (`_overlay_sprite_cache_frame` and `_overlay_sprite_cache_carrying`). This avoids creating short-lived Dictionary objects every frame (~60 fps), reducing GC pressure. The existing `_overlay_collision_slots` and `_overlay_used_slots` scratch buffers were already reused via `.clear()` — no change needed there. Added a comment explaining the GC-conscious design to prevent future regressions. Fixes #292 Signed-off-by: Saffron <263493777+itsmiso-ai@users.noreply.github.com> --- scripts/main.gd | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/main.gd b/scripts/main.gd index dbb4950..3ded501 100644 --- a/scripts/main.gd +++ b/scripts/main.gd @@ -1422,11 +1422,14 @@ func render_tile(index: int) -> void: amount_label.visible = hover_tile_index == index progress_label.text = "" -# Reused per-frame scratch dictionaries and per-sprite caches — this runs in -# _process, so per-frame allocations (string keys, texture lookups) add up. +# GC-conscious per-frame scratch buffers (audit #292): +# - _overlay_collision_slots / _overlay_used_slots are cleared each frame and reused. +# - _overlay_sprite_cache_frame / _overlay_sprite_cache_carrying store scalar values +# directly instead of allocating a new Dictionary per stale worker each frame. var _overlay_collision_slots: Dictionary = {} var _overlay_used_slots: Dictionary = {} -var _overlay_sprite_cache: Dictionary = {} +var _overlay_sprite_cache_frame: Dictionary = {} +var _overlay_sprite_cache_carrying: Dictionary = {} var _overlay_tile_size := Vector2i.ZERO func render_worker_overlay() -> void: @@ -1465,12 +1468,12 @@ func render_worker_overlay() -> void: var frame := worker_anim_frame(worker) var carrying := carried_resource(worker) var texture_stale := true - if _overlay_sprite_cache.has(name): - var cached: Dictionary = _overlay_sprite_cache[name] - texture_stale = int(cached["frame"]) != frame or String(cached["carrying"]) != carrying + if _overlay_sprite_cache_frame.has(name): + texture_stale = int(_overlay_sprite_cache_frame[name]) != frame or String(_overlay_sprite_cache_carrying.get(name, "")) != carrying if texture_stale: sprite.texture = worker_texture(name, frame, carrying) - _overlay_sprite_cache[name] = {"frame": frame, "carrying": carrying} + _overlay_sprite_cache_frame[name] = frame + _overlay_sprite_cache_carrying[name] = carrying var from_pos := data_to_vec(worker.get("prev_pos", worker.get("pos", vec_to_data(stockpile_pos)))) var to_pos := data_to_vec(worker.get("pos", vec_to_data(stockpile_pos))) var from_center := tile_center(from_pos)