diff --git a/Sources/FirebladeECS/Nexus+Family.swift b/Sources/FirebladeECS/Nexus+Family.swift index 0f5bd91..b7f096e 100644 --- a/Sources/FirebladeECS/Nexus+Family.swift +++ b/Sources/FirebladeECS/Nexus+Family.swift @@ -39,86 +39,3 @@ public extension Nexus { return members.contains(entityId.index) } } - -// MARK: - internal extensions -extension Nexus { - internal func update(familyMembership entityId: EntityIdentifier) { - // FIXME: iterating all families is costly for many families - familyMembersByTraits.forEach { familyTraits, _ in update(membership: familyTraits, for: entityId) } - } - - internal enum UpdateState { - case noComponents(id: EntityIdentifier, traits: FamilyTraitSet) - case added(id: EntityIdentifier, traits: FamilyTraitSet) - case removedDeleted(id: EntityIdentifier, traits: FamilyTraitSet) - case removed(id: EntityIdentifier, traits: FamilyTraitSet) - case unchanged(id: EntityIdentifier, traits: FamilyTraitSet) - } - - internal func update(membership traits: FamilyTraitSet, for entityId: EntityIdentifier) { - let entityIdx: EntityIndex = entityId.index - guard let componentIds: SparseComponentIdentifierSet = componentIdsByEntity[entityIdx] else { - // no components - so skip - return - } - - let isMember: Bool = self.isMember(entity: entityId, inFamilyWithTraits: traits) - if !exists(entity: entityId) && isMember { - remove(entityWithId: entityId, andIndex: entityIdx, fromFamilyWithTraits: traits) - return - } - - // TODO: get rid of set creation for comparison - let componentsSet = ComponentSet(componentIds) - let isMatch: Bool = traits.isMatch(components: componentsSet) - - switch (isMatch, isMember) { - case (true, false): - add(entityWithId: entityId, andIndex: entityIdx, toFamilyWithTraits: traits) - notify(FamilyMemberAdded(member: entityId, toFamily: traits)) - return - - case (false, true): - remove(entityWithId: entityId, andIndex: entityIdx, fromFamilyWithTraits: traits) - notify(FamilyMemberRemoved(member: entityId, from: traits)) - return - - default: - return - } - } - - /// will be called on family init defer - internal func onFamilyInit(traits: FamilyTraitSet) { - if familyMembersByTraits[traits] == nil { - familyMembersByTraits[traits] = UniformEntityIdentifiers() - } - - // FIXME: this is costly for many entities - for entity: Entity in entityStorage { - update(membership: traits, for: entity.identifier) - } - } - - internal func onFamilyDeinit(traits: FamilyTraitSet) { - // nothing todo here - } -} - -// MARK: - fileprivate extensions -private extension Nexus { - final func calculateTraitEntityIdHash(traitHash: FamilyTraitSetHash, entityIdx: EntityIndex) -> TraitEntityIdHash { - return hash(combine: traitHash, entityIdx) - } - - final func add(entityWithId entityId: EntityIdentifier, andIndex entityIdx: EntityIndex, toFamilyWithTraits traits: FamilyTraitSet) { - if familyMembersByTraits[traits] == nil { - familyMembersByTraits[traits] = UniformEntityIdentifiers() - } - familyMembersByTraits[traits]?.insert(entityId, at: entityIdx) - } - - final func remove(entityWithId entityId: EntityIdentifier, andIndex entityIdx: EntityIndex, fromFamilyWithTraits traits: FamilyTraitSet) { - familyMembersByTraits[traits]?.remove(at: entityIdx) - } -} diff --git a/Sources/FirebladeECS/Nexus+FamilyUpdate.swift b/Sources/FirebladeECS/Nexus+FamilyUpdate.swift new file mode 100644 index 0000000..a5bf3e4 --- /dev/null +++ b/Sources/FirebladeECS/Nexus+FamilyUpdate.swift @@ -0,0 +1,75 @@ +// +// Nexus+FamilyUpdate.swift +// FirebladeECS +// +// Created by Christian Treffs on 14.02.19. +// + +extension Nexus { + /// will be called on family init + final func onFamilyInit(traits: FamilyTraitSet) { + guard familyMembersByTraits[traits] == nil else { + return + } + + familyMembersByTraits[traits] = UniformEntityIdentifiers() + update(familyMembership: traits) + } + + final func update(familyMembership traits: FamilyTraitSet) { + // FIXME: iterating all entities is costly for many entities + for entity: Entity in entityStorage { + update(membership: traits, for: entity.identifier) + } + } + + final func update(familyMembership entityId: EntityIdentifier) { + // FIXME: iterating all families is costly for many families + for (traits, _) in familyMembersByTraits { + update(membership: traits, for: entityId) + } + } + + final func update(membership traits: FamilyTraitSet, for entityId: EntityIdentifier) { + let entityIdx: EntityIndex = entityId.index + guard let componentIds: SparseComponentIdentifierSet = componentIdsByEntity[entityIdx] else { + // no components - so skip + return + } + + let isMember: Bool = self.isMember(entity: entityId, inFamilyWithTraits: traits) + if !exists(entity: entityId) && isMember { + remove(entityWithId: entityId, andIndex: entityIdx, fromFamilyWithTraits: traits) + return + } + + // TODO: get rid of set creation for comparison by conforming UnorderedSparseSet to SetAlgebra + let componentsSet = ComponentSet(componentIds) + let isMatch: Bool = traits.isMatch(components: componentsSet) + + switch (isMatch, isMember) { + case (true, false): + add(entityWithId: entityId, andIndex: entityIdx, toFamilyWithTraits: traits) + notify(FamilyMemberAdded(member: entityId, toFamily: traits)) + return + + case (false, true): + remove(entityWithId: entityId, andIndex: entityIdx, fromFamilyWithTraits: traits) + notify(FamilyMemberRemoved(member: entityId, from: traits)) + return + + default: + return + } + } + + final func add(entityWithId entityId: EntityIdentifier, andIndex entityIdx: EntityIndex, toFamilyWithTraits traits: FamilyTraitSet) { + precondition(familyMembersByTraits[traits] != nil) + familyMembersByTraits[traits].unsafelyUnwrapped.insert(entityId, at: entityIdx) + } + + final func remove(entityWithId entityId: EntityIdentifier, andIndex entityIdx: EntityIndex, fromFamilyWithTraits traits: FamilyTraitSet) { + precondition(familyMembersByTraits[traits] != nil) + familyMembersByTraits[traits].unsafelyUnwrapped.remove(at: entityIdx) + } +}