Skip to content

GECS v 7.1.0 - Relationships added to Archetypes

Choose a tag to compare

@csprance csprance released this 22 Mar 23:21
· 75 commits to main since this release
5aea028

GECS v7.1.0 — Structural Relationship Queries

Relationship queries are now as fast as component queries. No API changes required — your existing with_relationship() calls just got dramatically faster.

What Changed

with_relationship() previously worked as a post-filter: after selecting entities by component, it iterated every matched entity and linearly scanned their relationships array. This was O(N×M×K) where N = entities, M = relationships per entity, K = filters.

In v7.1.0, each (Relation, Target) pair is baked into the archetype signature. Relationship queries now resolve through the same O(1) archetype bucket lookup that component queries use — no per-entity scanning.

Performance (Godot 4.6, from benchmarks)

Exact relationship queries — constant time regardless of entity count:

Scale Relationship Query Component Query (baseline)
100 0.089 ms 0.060 ms
1,000 0.092 ms 0.061 ms
10,000 0.091 ms 0.137 ms

Exact with_relationship([Relationship.new(C_Type.new(), target)]) queries are flat at ~0.09ms whether you have 100 or 10,000 entities. That's within noise of a with_all() component query.

Wildcard relationship queries (Relationship.new(C_Type.new(), null)) scale with the number of distinct archetypes matched, not total entities:

Scale Wildcard Query
100 0.214 ms
1,000 1.941 ms
10,000 21.274 ms

(This benchmark is worst-case: every entity has a unique target, creating one archetype per entity. Real-world usage with shared targets will be much faster.)

What You Need to Do

Nothing. The with_relationship() API is unchanged. Your existing code benefits automatically.

# This is the same API — it's just fast now
var children = world.query.with_relationship([
    Relationship.new(C_ChildOf.new(), parent_entity)
]).execute()

Property-based relationship queries continue to work as post-filters (runtime values can't be archetype-keyed):

# Still works — property queries remain post-filter
var high_damage = world.query.with_relationship([
    Relationship.new({C_Damage: {"amount": {"_gte": 50}}}, target)
]).execute()

Other Changes

  • Legacy relationship_entity_index removed — the old Dictionary-based index is gone, replaced entirely by the archetype system. Slightly lower memory footprint.
  • Archetype explosion warning — if you exceed 500 archetypes (possible with many unique relationship targets), a one-time debug warning fires so you can catch unintended combinatorial blowup early.
  • Batch relationship transitions — add_relationships([r1, r2, r3]) produces exactly one archetype transition instead of N, keeping bulk operations fast.
  • Freed-target cleanup — when a target entity is removed from the world, all source relationships pointing to it are automatically cleaned up via the archetype index.

Test Coverage

313 tests passing, zero regressions. 34 new tests added covering structural relationship storage, signature computation, archetype transitions, query integration, and property query preservation.

What's Changed

  • Relationship v2 - Add Relationships to Archetypes by @csprance in #99

Full Changelog: v7.0.1...v7.1.0