Grid Building 5.0.4 Patch Notes

Release Date: May 2, 2026 Version: 5.0.4 Type: Maintenance / Bug Fix / Hardening Release


Highlights

  • Web exports now work — placement rules, resources, and indicators load correctly in exported builds
  • Manipulation system fully stabilized — no more crashes from stale state, deleted sources, or rapid interactions
  • Templates work out-of-the-box for any project — collision layers and resource references are project-agnostic
  • New pre_instance_added signal — configure placed objects before _ready() runs
  • 1693 tests passing — full regression coverage across 165 test suites (135 demo tests)

New Features

  • BuildingState.pre_instance_added signal

    • Emitted after scene instantiation but before add_child(), allowing external code to configure instances before _ready() runs
  • Web export resource loading guide (see web-export guide in this documentation)

    • Documents web export requirements, resource loading differences, best practices, and troubleshooting
    • Includes references to upstream Godot bug reports (#97782, #72489, #70575) for self-diagnosis

Bug Fixes

Web Export

  • Fixed placement rules not loading in web exports

    • Base rules were embedded as sub-resources; web exports silently deserialized placement_rules as empty arrays
    • Extracted rules into standalone .tres files for all three demos (top-down, platformer, isometric)
    • Removed fragile Array[ExtResource(...)] typed array syntax from all demo and template settings (see godot#97782)
  • Fixed Placeable UID loading for web export

    • Placeable.load_resource() now allows UID resolution in web builds
  • Fixed nested rule resource defaults not persisting on web export

    • CollisionsCheckRule.messages and other nested sub-resources now saved explicitly in template .tres files
    • Added _ensure_messages() lazy-loading safeguard as a fallback for deserialization failures (see godot#70575)

Demo

  • Fixed player inventory gold resetting on level transitions

    • World.move_to_level_sync() and World.move_to_level() were resetting inventory to starting value on every level change
    • Inventory now persists across level transitions as intended
  • Fixed template default collision layers to be project-agnostic

    • Default CollisionsCheckRule template now uses single layer (collision_mask = 1, apply_to_objects_mask = 1) instead of demo-specific multi-layer masks

Manipulation System

  • Fixed stale move copies causing collision interference

    • Previous manipulations are now properly cancelled before starting new ones
    • Prevents stale collision shapes from persisting and interfering with new indicators
  • Fixed == vs = state corruption (manipulation_system.gd:726)

    • _states.manipulation.data == null was a comparison that discarded the result; stale data was never cleared
    • Fixed to an assignment so preview state actually resets
  • Fixed hard crash when manipulation source is deleted during active move

    • Indicators parented in the scene tree were freed without removal, leaving dangling references
    • Added proper remove_child() before freeing and cleared collision exclusions on cancel/finish

Placement & Collision

  • Fixed ShapeCast2D.add_exception() outside-bounds bug in CollisionsCheckRule

    • Godot silently ignores ShapeCast2D exceptions when the cast origin is outside the excluded body’s bounds
    • Added manual post-cast exclusion filter to suppress false-positive collisions during manipulation moves
  • Fixed CollisionUtilities.does_indicator_overlap_shape() shape-owner transform

    • Was ignoring per-shape local offsets; added shape_owner_id parameter for correct transform computation
  • Fixed recursive cleanup in BuildingSystem

    • Added _cleaning_up guard flag to prevent double-cleanup when called from multiple exit paths
    • Fixed guard reset timing that allowed the mode_changed signal to defeat the guard

Stability

  • Fixed null dereference crashes in PlaceableInstance.instance_from_save(), PlaceableInstance.save(), IndicatorContext.validate_placement(), TargetHighlighter.current_target setter, and TargetHighlighter._on_started()

    • All now properly guard against null before accessing properties
  • Fixed IndicatorFactory null logger crash

    • Added fallback logger when none is passed, preventing Nonexistent function runtime errors
  • Fixed assert-to-null-guard in CollisionMapper

    • Replaced assert() calls with push_error() + early returns — asserts are compiled out in release builds
  • Fixed is_instance_valid check missing in CollisionsCheckRule

    • Prevents accessing freed indicator objects

Technical Changes

  • Fixed _validate_property signature mismatch in Placeable — matched parent class signature
  • Fixed apply_rules() argument mismatch in PlacementValidator — removed unnecessary parameter
  • Fixed _pre_check_tile_rules type error in PlacementValidator — corrected parameter and return types
  • Fixed _get_indicator_tile_pos return type in IndicatorServicereturn nullreturn Vector2i.ZERO
  • Fixed _on_mode_changed missing return type in GridPositioner2D — added explicit -> void
  • Fixed CollisionMapper internal helper references — resolved undefined class references
  • Fixed RID.is_null() parse error in CollisionUtilities — replaced with RID.is_valid() (Godot 4 API)
  • Fixed gb_camera2d_validator.gd parse error — empty function body needed pass
  • Added _ensure_messages() lazy-loading safeguard to CollisionsCheckRule — prevents null derefs when nested resources fail to deserialize
  • Added _cleaning_up variable to BuildingSystem — was referenced but undeclared

Test Suite

  • 1693 tests | 0 errors | 0 failures | 0 orphans | 1 flaky (passes on GdUnit4 retry)
    • 1558 addon tests + 135 demo tests across 165 suites
  • Added web export compatibility test suite (8 tests)
  • Added validation tests for base rule resource paths across all demos
  • Fixed ManipulationHelpers.create_test_manipulatable() signature mismatches across 3 test suites
  • Fixed orphan node leaks in manipulation test suites
  • Fixed scene runner leaks in suite after() hooks
  • Fixed composition container cross-test contamination via ResourceLoader.CACHE_MODE_IGNORE
  • Fixed grid positioner recenter test dependency wiring

Status

  • Complete — Ready for release.