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

denniskaselow / dartemis / #220

01 Nov 2024 10:13AM UTC coverage: 70.795% (-2.0%) from 72.782%
#220

push

denniskaselow
version 0.10.0

463 of 654 relevant lines covered (70.8%)

1.44 hits per line

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

89.15
/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
  final _componentTypes = <Type, ComponentType>{};
7
  final _systemIndices = <Type, int>{};
8
  int _systemCount = 0;
9
  int _componentTypeCount = 0;
10

11
  ComponentManager._internal() : _componentInfoByType = Bag<_ComponentInfo>();
2✔
12

13
  /// Register a system to know if it needs to be updated when an entity
14
  /// changed.
15
  @visibleForTesting
1✔
16
  void registerSystem(EntitySystem system) {
17
    final systemBitIndex = _systemIndices.putIfAbsent(
2✔
18
      system.runtimeType,
1✔
19
      () => _systemCount++,
3✔
20
    );
21
    for (final index in system._interestingComponentsIndices) {
2✔
22
      _componentInfoByType._ensureCapacity(index);
2✔
23
      var componentInfo = _componentInfoByType[index];
2✔
24
      if (componentInfo == null) {
25
        componentInfo = _ComponentInfo();
×
26
        _componentInfoByType[index] = componentInfo;
×
27
      }
28

29
      componentInfo.addInterestedSystem(systemBitIndex);
1✔
30
    }
31
  }
32

33
  void _unregisterSystem(EntitySystem system) {
×
34
    final systemBitIndex = _systemIndices.remove(system.runtimeType)!;
×
35
    for (final index in system._interestingComponentsIndices) {
×
36
      _componentInfoByType[index]!.removeInterestedSystem(systemBitIndex);
×
37
    }
38
  }
39

40
  /// Removes all components from the [entity].
41
  @visibleForTesting
1✔
42
  void removeComponentsOfEntity(Entity entity) {
43
    _forComponentsOfEntity(entity, (components) {
2✔
44
      components.remove(entity);
1✔
45
    });
46
  }
47

48
  void _addComponent<T extends Component>(
1✔
49
    Entity entity,
50
    T component,
51
  ) {
52
    // needs the runtimeType instead of T because this method gets called
53
    // in a loop over a list of Components, so T would be Component
54
    final type = getTypeFor(component.runtimeType);
2✔
55
    final index = type.bitIndex;
56
    _componentInfoByType._ensureCapacity(index);
2✔
57
    var componentInfo = _componentInfoByType[index];
2✔
58
    if (componentInfo == null) {
59
      componentInfo = _ComponentInfo<T>();
1✔
60
      _componentInfoByType[index] = componentInfo;
2✔
61
    }
62
    componentInfo[entity] = component;
1✔
63
  }
64

65
  void _removeComponent<T>(Entity entity) {
1✔
66
    final type = getTypeFor(T);
1✔
67
    final typeId = type.bitIndex;
68
    _componentInfoByType[typeId]!.remove(entity);
3✔
69
  }
70

71
  void _moveComponent<T>(Entity entitySrc, Entity entityDst) {
1✔
72
    final type = getTypeFor(T);
1✔
73
    final typeId = type.bitIndex;
74
    _componentInfoByType[typeId]?.move(entitySrc, entityDst);
3✔
75
  }
76

77
  /// Returns all components of [ComponentType type] accessible by their entity
78
  /// id.
79
  List<T?> _getComponentsByType<T extends Component>() {
1✔
80
    final type = getTypeFor(T);
1✔
81
    final index = type.bitIndex;
82
    _componentInfoByType._ensureCapacity(index);
2✔
83

84
    var components = _componentInfoByType[index];
2✔
85
    if (components == null) {
86
      components = _ComponentInfo<T>();
1✔
87
      _componentInfoByType[index] = components;
2✔
88
    } else if (components.components is! List<T?>) {
2✔
89
      // when components get added to an entity as part of a list containing
90
      // multiple different components, the type is infered as Component
91
      // instead of the actual type of the component. So if _addComponent was
92
      // called first a Bag<Component> would have been created and this fixes
93
      // the type
94
      _componentInfoByType[index]!.components =
3✔
95
          components.components.cast<T?>();
2✔
96
      components = _componentInfoByType[index];
2✔
97
    }
98

99
    return components!.components.cast<T?>();
2✔
100
  }
101

102
  /// Returns all components of [ComponentType type].
103
  List<T> getComponentsByType<T extends Component>() =>
1✔
104
      _getComponentsByType<T>().whereType<T>().toList();
3✔
105

106
  /// Returns all components of [entity].
107
  List<Component> getComponentsFor(Entity entity) {
1✔
108
    final result = <Component>[];
1✔
109
    _forComponentsOfEntity(
1✔
110
      entity,
111
      (components) => result.add(components[entity]),
3✔
112
    );
113

114
    return result;
115
  }
116

117
  void _forComponentsOfEntity(
1✔
118
    Entity entity,
119
    void Function(_ComponentInfo components) f,
120
  ) {
121
    for (var index = 0; index < _componentTypeCount; index++) {
3✔
122
      final componentInfo = _componentInfoByType[index];
2✔
123
      if (componentInfo != null &&
124
          componentInfo.entities.length > entity._id &&
3✔
125
          componentInfo.entities[entity._id]) {
2✔
126
        f(componentInfo);
1✔
127
      }
128
    }
129
  }
130

131
  /// Returns true if the list of entities of [system] need to be updated.
132
  bool isUpdateNeededForSystem(EntitySystem system) {
1✔
133
    final systemBitIndex = _systemIndices[system.runtimeType]!;
3✔
134
    for (final interestingComponent in system._interestingComponentsIndices) {
2✔
135
      if (_componentInfoByType[interestingComponent]!
2✔
136
          .systemRequiresUpdate(systemBitIndex)) {
1✔
137
        return true;
138
      }
139
    }
140
    return false;
141
  }
142

143
  /// Marks the [system] as updated for the necessary component types.
144
  void _systemUpdated(EntitySystem system) {
1✔
145
    final systemBitIndex = _systemIndices[system.runtimeType]!;
3✔
146
    for (final interestingComponent in system._interestingComponentsIndices) {
2✔
147
      _componentInfoByType[interestingComponent]!.systemUpdated(systemBitIndex);
3✔
148
    }
149
  }
150

151
  /// Returns every entity that is of interest for [system].
152
  List<Entity> _getEntitiesForSystem(
1✔
153
    EntitySystem system,
154
    int entitiesBitSetLength,
155
  ) {
156
    final baseAll = BitSet(entitiesBitSetLength)..setAll();
2✔
157
    for (final interestingComponent in system._componentIndicesAll) {
2✔
158
      baseAll.and(_componentInfoByType[interestingComponent]!.entities);
4✔
159
    }
160
    final baseOne = BitSet(entitiesBitSetLength);
1✔
161
    if (system._componentIndicesOne.isEmpty) {
2✔
162
      baseOne.setAll();
1✔
163
    } else {
164
      for (final interestingComponent in system._componentIndicesOne) {
2✔
165
        baseOne.or(_componentInfoByType[interestingComponent]!.entities);
4✔
166
      }
167
    }
168
    final baseExclude = BitSet(entitiesBitSetLength);
1✔
169
    for (final interestingComponent in system._componentIndicesExcluded) {
2✔
170
      baseExclude.or(_componentInfoByType[interestingComponent]!.entities);
4✔
171
    }
172
    baseAll
173
      ..and(baseOne)
1✔
174
      ..andNot(baseExclude);
1✔
175
    return baseAll.toIntValues().map(Entity._).toList(growable: false);
3✔
176
  }
177

178
  /// Returns the component of type [T] for the given [entity].
179
  T? getComponent<T extends Component>(
1✔
180
    Entity entity,
181
  ) {
182
    final componentType = getTypeFor(T);
1✔
183
    final index = componentType.bitIndex;
184
    final components = _componentInfoByType[index];
2✔
185
    if (components != null && entity._id < components.components.length) {
3✔
186
      return components.components[entity._id] as T?;
2✔
187
    }
188
    return null;
189
  }
190

191
  /// Returns the [ComponentType] for the runtimeType of a [Component].
192
  ComponentType getTypeFor(Type typeOfComponent) => _componentTypes.putIfAbsent(
3✔
193
        typeOfComponent,
194
        () => ComponentType(_componentTypeCount++),
4✔
195
      );
196

197
  /// Returns the index of the bit of the [componentType].
198
  int getBitIndex(Type componentType) => getTypeFor(componentType).bitIndex;
2✔
199
}
200

201
class _ComponentInfo<T extends Component> {
202
  BitSet entities = BitSet(32);
203
  List<T?> components = List.filled(32, null, growable: true);
204
  BitSet interestedSystems = BitSet(32);
205
  BitSet requiresUpdate = BitSet(32);
206
  bool dirty = false;
207

208
  _ComponentInfo();
1✔
209

210
  void operator []=(Entity entity, T component) {
1✔
211
    if (entity._id >= entities.length) {
3✔
212
      entities = BitSet.fromBitSet(entities, length: entity._id + 1);
4✔
213
      final newCapacity = (entities.length * 3) ~/ 2 + 1;
5✔
214
      final filler = List.filled(newCapacity - components.length, null);
4✔
215
      components.addAll(filler);
2✔
216
    }
217
    entities[entity._id] = true;
2✔
218
    components[entity._id] = component;
2✔
219
    dirty = true;
1✔
220
  }
221

222
  T operator [](Entity entity) => components[entity._id]!;
3✔
223

224
  void remove(Entity entity) {
1✔
225
    if (entities.length > entity._id && entities[entity._id]) {
5✔
226
      entities[entity._id] = false;
2✔
227
      components[entity._id]!._removed();
3✔
228
      components[entity._id] = null;
2✔
229
      dirty = true;
1✔
230
    }
231
  }
232

233
  void move(Entity srcEntity, Entity dstEntity) {
1✔
234
    if (entities.length > srcEntity._id && entities[srcEntity._id]) {
5✔
235
      remove(dstEntity);
1✔
236
      this[dstEntity] = components[srcEntity._id]!;
3✔
237
      entities[srcEntity._id] = false;
2✔
238
      components[srcEntity._id] = null;
2✔
239
      dirty = true;
1✔
240
    }
241
  }
242

243
  void addInterestedSystem(int systemBitIndex) {
1✔
244
    if (systemBitIndex >= interestedSystems.length) {
3✔
245
      interestedSystems =
×
246
          BitSet.fromBitSet(interestedSystems, length: systemBitIndex + 1);
×
247
      requiresUpdate =
×
248
          BitSet.fromBitSet(requiresUpdate, length: systemBitIndex + 1);
×
249
    }
250
    interestedSystems[systemBitIndex] = true;
2✔
251
    requiresUpdate[systemBitIndex] = true;
2✔
252
  }
253

254
  void removeInterestedSystem(int systemBitIndex) {
×
255
    interestedSystems[systemBitIndex] = false;
×
256
    requiresUpdate[systemBitIndex] = false;
×
257
  }
258

259
  bool systemRequiresUpdate(int systemBitIndex) {
1✔
260
    if (dirty) {
1✔
261
      requiresUpdate.or(interestedSystems);
3✔
262
      dirty = false;
1✔
263
    }
264
    return requiresUpdate[systemBitIndex];
2✔
265
  }
266

267
  void systemUpdated(int systemBitIndex) =>
1✔
268
      requiresUpdate[systemBitIndex] = false;
2✔
269

270
  _ComponentInfo<S> cast<S extends Component>() => this as _ComponentInfo<S>;
×
271
}
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