feat(oecs): add support for reordering relationship sources

Introduces `RelationshipReordered` change kind and `ReorderSources`
method to allow reordering the source set of a relationship without
removing and re-adding components. This optimizes shuffling operations
like deck setup in Blackjack.
This commit is contained in:
2026-07-21 22:46:32 +08:00
parent b0bf10f286
commit 68eeeeb7a6
7 changed files with 68 additions and 20 deletions
+8 -1
View File
@@ -29,5 +29,12 @@ public enum ChangeKind
/// A component's value was modified. Must be explicitly marked
/// via <see cref="World.MarkModified{T}"/>.
/// </summary>
ComponentModified
ComponentModified,
/// <summary>
/// The source set for a relationship type on a target entity was
/// reordered. The <see cref="EntityChange.Entity"/> is the target
/// and <see cref="EntityChange.ComponentType"/> is the relationship type.
/// </summary>
RelationshipReordered
}
+9
View File
@@ -64,6 +64,15 @@ internal class ChangeSet
TryAdd(new EntityChange(entity, ChangeKind.ComponentModified, componentType));
}
/// <summary>
/// Records that the source set for a relationship type on a target entity
/// was reordered.
/// </summary>
public void MarkRelationshipReordered(Entity target, Type relationshipType)
{
TryAdd(new EntityChange(target, ChangeKind.RelationshipReordered, relationshipType));
}
/// <summary>
/// Clears all accumulated changes.
/// </summary>
+15
View File
@@ -44,6 +44,21 @@ internal sealed class OrderedEntitySet : IReadOnlyCollection<Entity>
return true;
}
/// <summary>
/// Reorders the set to match the given entity order.
/// The provided list must contain exactly the same entities as the set.
/// </summary>
public void Reorder(IReadOnlyList<Entity> ordered)
{
_order.Clear();
_index.Clear();
for (int i = 0; i < ordered.Count; i++)
{
_order.Add(ordered[i]);
_index[ordered[i]] = i;
}
}
public IEnumerator<Entity> GetEnumerator() => _order.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
+17
View File
@@ -119,6 +119,23 @@ internal class RelationshipIndex
}
}
/// <summary>
/// Reorders the source set for the given relationship type and target
/// to match the order of entities in <paramref name="ordered"/>.
/// </summary>
public void ReorderSources<T>(Entity target, IReadOnlyList<Entity> ordered)
where T : struct, IRelationship
{
var type = typeof(T);
if (!_index.TryGetValue(type, out var targetMap))
return;
if (!targetMap.TryGetValue(target, out var sources))
return;
sources.Reorder(ordered);
}
/// <summary>
/// Returns true if the index has any entries for the given relationship type.
/// </summary>
+16
View File
@@ -449,6 +449,7 @@ public class World : IDisposable
/// <summary>
/// Returns all source entities that have a relationship of type
/// <typeparamref name="T"/> pointing to the given target entity.
/// Sources are iterated in insertion order.
/// </summary>
public IReadOnlyCollection<Entity> GetSources<T>(Entity target)
where T : struct, IRelationship
@@ -456,6 +457,21 @@ public class World : IDisposable
return _relationships.GetSources<T>(target);
}
/// <summary>
/// Reorders the source set for the given relationship type and target
/// to match the order of entities in <paramref name="ordered"/>.
/// All entities currently in the set must appear exactly once in the
/// provided collection; no entities are added or removed.
/// Fires a <see cref="ChangeKind.RelationshipReordered"/> change event
/// on the target entity.
/// </summary>
public void ReorderSources<T>(Entity target, IReadOnlyList<Entity> ordered)
where T : struct, IRelationship
{
_relationships.ReorderSources<T>(target, ordered);
_changes.Pending.MarkRelationshipReordered(target, typeof(T));
}
// ── Commands ──────────────────────────────────────────────────────
/// <summary>