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:
parent
b0bf10f286
commit
68eeeeb7a6
|
|
@ -60,27 +60,10 @@ public class DeckSetupSystem : ISystem
|
|||
for (int i = cardEntities.Length - 1; i > 0; i--)
|
||||
{
|
||||
int j = Mulberry32.NextInt(ref seed, 0, i);
|
||||
|
||||
// Swap the InDeck relationship targets (cards are always in the deck,
|
||||
// so there's nothing to swap except the cards themselves — but we
|
||||
// shuffle the card order conceptually by removing and re-adding
|
||||
// InDeck components in shuffled order). Actually, since InDeck
|
||||
// is just a tag, we just re-shuffle the order in the source collection.
|
||||
// The simplest approach: no need to swap component data; we just
|
||||
// need to ensure the cards are iterated in shuffled order.
|
||||
// We'll swap the card entities in the array.
|
||||
(cardEntities[i], cardEntities[j]) = (cardEntities[j], cardEntities[i]);
|
||||
}
|
||||
|
||||
// Now remove all InDeck and re-add in shuffled order so GetSources
|
||||
// returns them in shuffled order.
|
||||
for (int i = cardEntities.Length - 1; i >= 0; i--)
|
||||
{
|
||||
world.RemoveComponent<InDeck>(cardEntities[i]);
|
||||
}
|
||||
for (int i = 0; i < cardEntities.Length; i++)
|
||||
{
|
||||
world.AddComponent(cardEntities[i], new InDeck { Target = deckEntity });
|
||||
}
|
||||
// Reorder the source set in-place — no component add/remove needed.
|
||||
world.ReorderSources<InDeck>(deckEntity, cardEntities);
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ public sealed class ObservableCapture : IDisposable
|
|||
if (change.ComponentType != null
|
||||
&& change.Kind != ChangeKind.ComponentRemoved
|
||||
&& change.Kind != ChangeKind.EntityRemoved
|
||||
&& change.Kind != ChangeKind.RelationshipReordered
|
||||
&& _formatters.TryGetValue(change.ComponentType, out var formatter))
|
||||
{
|
||||
formattedValue = formatter(_world, change.Entity);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue