Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions esper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ def _get_components(*component_types: type[_C]) -> _Iterable[tuple[int, tuple[_C
comp_db = _components

min_set = None
min_type = None
min_size = inf
other_types = []

Expand All @@ -502,10 +503,11 @@ def _get_components(*component_types: type[_C]) -> _Iterable[tuple[int, tuple[_C
return
set_size = len(comp_set)
if set_size < min_size:
if min_set is not None:
other_types.append(component_types[len(other_types)])
if min_type is not None:
other_types.append(min_type)
min_size = set_size
min_set = comp_set
min_type = ct
else:
other_types.append(ct)

Expand Down
26 changes: 26 additions & 0 deletions tests/test_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,32 @@ def test_get_three_components():
assert isinstance(e, ComponentE)


def test_get_components_smallest_set_missing_component():
# Regression test: _get_components scans for the smallest component set
# first. When a type is set aside before a new smallest set is found, the
# previously-smallest type must be the one moved aside. Component sizes are
# arranged so ComponentB is set aside, then ComponentC becomes the new
# smallest -- ComponentA (the prior smallest) must not be dropped, otherwise
# an entity that matches on the remaining types but lacks ComponentA raises
# a KeyError while building the result tuple.
esper.create_entity(ComponentB(), ComponentC()) # matches B and C, not A
esper.create_entity(ComponentA())
esper.create_entity(ComponentA())
esper.create_entity(ComponentB())
esper.create_entity(ComponentB())
entity_all = esper.create_entity(ComponentA(), ComponentB(), ComponentC())

# sizes: A=3, B=4, C=2 -> C is discovered as the smallest set last
result = esper.get_components(ComponentA, ComponentB, ComponentC)

assert len(result) == 1
ent, (a, b, c) = result[0]
assert ent == entity_all
assert isinstance(a, ComponentA)
assert isinstance(b, ComponentB)
assert isinstance(c, ComponentC)


def test_try_component():
entity1 = esper.create_entity(ComponentA(), ComponentB())

Expand Down