• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

denniskaselow / dartemis / #189

pending completion
#189

push

denniskaselow
updated CHANGELOG.md

487 of 669 relevant lines covered (72.8%)

1.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.63
/lib/src/core/component_manager.dart
1
part of '../../dartemis.dart';
2

3
/// Manages als components of all entities.
4
class ComponentManager extends Manager {
5
  final Bag<_ComponentInfo> _componentInfoByType;
6

7
  ComponentManager._internal() : _componentInfoByType = Bag<_ComponentInfo>();
2✔
8

9
  @override
1✔
10
  void initialize() {}
11

12
  /// Register a system to know if it needs to be updated when an entity
13
  /// changed.
14
  void _registerSystem(EntitySystem system) {
1✔
15
    final systemBitIndex = system._systemBitIndex;
1✔
16
    for (final index in system._interestingComponentsIndices) {
2✔
17
      _componentInfoByType._ensureCapacity(index);
2✔
18
      var componentInfo = _componentInfoByType[index];
2✔
19
      if (componentInfo == null) {
20
        componentInfo = _ComponentInfo();
1✔
21
        _componentInfoByType[index] = componentInfo;
2✔
22
      }
23

24
      componentInfo.addInterestedSystem(systemBitIndex);
1✔
25
    }
26
  }
27

28
  void _unregisterSystem(EntitySystem system) {
×
29
    final systemBitIndex = system._systemBitIndex;
×
30
    for (final index in system._interestingComponentsIndices) {
×
31
      _componentInfoByType[index]!.removeInterestedSystem(systemBitIndex);
×
32
    }
33
  }
34

35
  void _removeComponentsOfEntity(int entity) {
1✔
36
    _forComponentsOfEntity(entity, (components, typeId) {
2✔
37
      components.remove(entity);
1✔
38
    });
39
  }
40

41
  void _addComponent<T extends Component>(
1✔
42
    int entity,
43
    ComponentType type,
44
    T component,
45
  ) {
46
    final index = type._bitIndex;
1✔
47
    _componentInfoByType._ensureCapacity(index);
2✔
48
    var componentInfo = _componentInfoByType[index];
2✔
49
    if (componentInfo == null) {
50
      componentInfo = _ComponentInfo<T>();
1✔
51
      _componentInfoByType[index] = componentInfo;
2✔
52
    }
53
    componentInfo[entity] = component;
1✔
54
  }
55

56
  void _removeComponent(int entity, ComponentType type) {
1✔
57
    final typeId = type._bitIndex;
1✔
58
    _componentInfoByType[typeId]!.remove(entity);
3✔
59
  }
60

61
  void _moveComponent(int entitySrc, int entityDst, ComponentType type) {
1✔
62
    final typeId = type._bitIndex;
1✔
63
    _componentInfoByType[typeId]?.move(entitySrc, entityDst);
3✔
64
  }
65

66
  /// Returns all components of [ComponentType type] accessible by their entity
67
  /// id.
68
  List<T?> _getComponentsByType<T extends Component>(ComponentType type) {
1✔
69
    final index = type._bitIndex;
1✔
70
    _componentInfoByType._ensureCapacity(index);
2✔
71

72
    var components = _componentInfoByType[index];
2✔
73
    if (components == null) {
74
      components = _ComponentInfo<T>();
1✔
75
      _componentInfoByType[index] = components;
2✔
76
    } else if (components.components is! List<T?>) {
2✔
77
      // when components get added to an entity as part of a list containing
78
      // multiple different components, the type is infered as Component
79
      // instead of the actual type of the component. So if _addComponent was
80
      // called first a Bag<Component> would have been created and this fixes
81
      // the type
82
      _componentInfoByType[index]!.components =
3✔
83
          components.components.cast<T?>();
2✔
84
      components = _componentInfoByType[index];
2✔
85
    }
86

87
    return components!.components.cast<T?>();
2✔
88
  }
89

90
  /// Returns all components of [ComponentType type].
91
  List<T> getComponentsByType<T extends Component>(ComponentType type) =>
1✔
92
      _getComponentsByType(type).whereType<T>().toList();
3✔
93

94
  /// Returns all components of [entity].
95
  List<Component> getComponentsFor(int entity) {
1✔
96
    final result = <Component>[];
1✔
97
    _forComponentsOfEntity(
1✔
98
      entity,
99
      (components, _) => result.add(components[entity]),
3✔
100
    );
101

102
    return result;
103
  }
104

105
  void _forComponentsOfEntity(
1✔
106
    int entity,
107
    void Function(_ComponentInfo components, int index) f,
108
  ) {
109
    for (var index = 0; index < ComponentType._nextBitIndex; index++) {
2✔
110
      final componentInfo = _componentInfoByType[index];
2✔
111
      if (componentInfo != null &&
112
          componentInfo.entities.length > entity &&
3✔
113
          componentInfo.entities[entity]) {
2✔
114
        f(componentInfo, entity);
1✔
115
      }
116
    }
117
  }
118

119
  /// Returns true if the list of entities of [system] need to be updated.
120
  bool isUpdateNeededForSystem(EntitySystem system) {
1✔
121
    final systemBitIndex = system._systemBitIndex;
1✔
122
    for (final interestingComponent in system._interestingComponentsIndices) {
2✔
123
      if (_componentInfoByType[interestingComponent]!
2✔
124
          .systemRequiresUpdate(systemBitIndex)) {
1✔
125
        return true;
126
      }
127
    }
128
    return false;
129
  }
130

131
  /// Marks the [system] as updated for the necessary component types.
132
  void _systemUpdated(EntitySystem system) {
1✔
133
    final systemBitIndex = system._systemBitIndex;
1✔
134
    for (final interestingComponent in system._interestingComponentsIndices) {
2✔
135
      _componentInfoByType[interestingComponent]!.systemUpdated(systemBitIndex);
3✔
136
    }
137
  }
138

139
  /// Returns every entity that is of interest for [system].
140
  List<int> _getEntitiesForSystem(
1✔
141
    EntitySystem system,
142
    int entitiesBitSetLength,
143
  ) {
144
    final baseAll = BitSet(entitiesBitSetLength)..setAll();
2✔
145
    for (final interestingComponent in system._componentIndicesAll) {
2✔
146
      baseAll.and(_componentInfoByType[interestingComponent]!.entities);
4✔
147
    }
148
    final baseOne = BitSet(entitiesBitSetLength);
1✔
149
    if (system._componentIndicesOne.isEmpty) {
2✔
150
      baseOne.setAll();
1✔
151
    } else {
152
      for (final interestingComponent in system._componentIndicesOne) {
2✔
153
        baseOne.or(_componentInfoByType[interestingComponent]!.entities);
4✔
154
      }
155
    }
156
    final baseExclude = BitSet(entitiesBitSetLength);
1✔
157
    for (final interestingComponent in system._componentIndicesExcluded) {
2✔
158
      baseExclude.or(_componentInfoByType[interestingComponent]!.entities);
4✔
159
    }
160
    baseAll
161
      ..and(baseOne)
1✔
162
      ..andNot(baseExclude);
1✔
163
    return baseAll.toIntValues();
1✔
164
  }
165

166
  /// Returns the component of type [T] for the given [entity].
167
  T? getComponent<T extends Component>(
1✔
168
    int entity,
169
    ComponentType componentType,
170
  ) {
171
    final index = componentType._bitIndex;
1✔
172
    final components = _componentInfoByType[index];
2✔
173
    if (components != null && entity < components.components.length) {
3✔
174
      return components.components[entity] as T?;
2✔
175
    }
176
    return null;
177
  }
178
}
179

180
class _ComponentInfo<T extends Component> {
181
  BitSet entities = BitSet(32);
182
  List<T?> components = List.filled(32, null, growable: true);
183
  BitSet interestedSystems = BitSet(32);
184
  BitSet requiresUpdate = BitSet(32);
185
  bool dirty = false;
186

187
  _ComponentInfo();
1✔
188

189
  void operator []=(int entity, T component) {
1✔
190
    if (entity >= entities.length) {
3✔
191
      entities = BitSet.fromBitSet(entities, length: entity + 1);
4✔
192
      final newCapacity = (entities.length * 3) ~/ 2 + 1;
5✔
193
      final filler = List.filled(newCapacity - components.length, null);
4✔
194
      components.addAll(filler);
2✔
195
    }
196
    entities[entity] = true;
2✔
197
    components[entity] = component;
2✔
198
    dirty = true;
1✔
199
  }
200

201
  T operator [](int entity) => components[entity]!;
3✔
202

203
  void remove(int entity) {
1✔
204
    if (entities.length > entity && entities[entity]) {
5✔
205
      entities[entity] = false;
2✔
206
      components[entity]!._removed();
3✔
207
      components[entity] = null;
2✔
208
      dirty = true;
1✔
209
    }
210
  }
211

212
  void move(int srcEntity, int dstEntity) {
1✔
213
    if (entities.length > srcEntity && entities[srcEntity]) {
5✔
214
      remove(dstEntity);
1✔
215
      entities[dstEntity] = true;
2✔
216
      entities[srcEntity] = false;
2✔
217
      components[dstEntity] = components[srcEntity];
4✔
218
      components[srcEntity] = null;
2✔
219
      dirty = true;
1✔
220
    }
221
  }
222

223
  void addInterestedSystem(int systemBitIndex) {
1✔
224
    if (systemBitIndex >= interestedSystems.length) {
3✔
225
      interestedSystems =
×
226
          BitSet.fromBitSet(interestedSystems, length: systemBitIndex + 1);
×
227
      requiresUpdate =
×
228
          BitSet.fromBitSet(requiresUpdate, length: systemBitIndex + 1);
×
229
    }
230
    interestedSystems[systemBitIndex] = true;
2✔
231
    requiresUpdate[systemBitIndex] = true;
2✔
232
  }
233

234
  void removeInterestedSystem(int systemBitIndex) {
×
235
    interestedSystems[systemBitIndex] = false;
×
236
    requiresUpdate[systemBitIndex] = false;
×
237
  }
238

239
  bool systemRequiresUpdate(int systemBitIndex) {
1✔
240
    if (dirty) {
1✔
241
      requiresUpdate.or(interestedSystems);
3✔
242
      dirty = false;
1✔
243
    }
244
    return requiresUpdate[systemBitIndex];
2✔
245
  }
246

247
  void systemUpdated(int systemBitIndex) =>
1✔
248
      requiresUpdate[systemBitIndex] = false;
2✔
249

250
  _ComponentInfo<S> cast<S extends Component>() => this as _ComponentInfo<S>;
×
251
}
252

253
/// For Testing.
254
@visibleForTesting
255
mixin MockComponentManagerMixin implements ComponentManager {
256
  @override
257
  late World _world;
258
  @override
1✔
259
  void _registerSystem(EntitySystem system) {}
260
  @override
1✔
261
  void _removeComponentsOfEntity(int entity) {}
262
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc