Fix some reference counting

This commit is contained in:
Christian Treffs 2017-11-02 17:48:46 +01:00
parent 5dd149dd82
commit 78c248ab0a
11 changed files with 105 additions and 64 deletions

View File

@ -0,0 +1,11 @@
//
// Activatable.swift
// FirebladeECSPackageDescription
//
// Created by Christian Treffs on 02.11.17.
//
public protocol Activatable {
func activate()
func deactivate()
}

View File

@ -5,7 +5,7 @@
// Created by Christian Treffs on 08.10.17. // Created by Christian Treffs on 08.10.17.
// //
public protocol Component: class, UniqueComponentIdentifiable {} public protocol Component: class, UniqueComponentIdentifiable, Activatable {}
// MARK: UCI // MARK: UCI
extension Component { extension Component {
@ -15,6 +15,12 @@ extension Component {
public var identifier: ComponentIdentifier { return Self.identifier } public var identifier: ComponentIdentifier { return Self.identifier }
} }
// MARK: - activatable protocol
extension Component {
public func activate() { /* default does nothing */ }
public func deactivate() { /* default does nothing */ }
}
// MARK: - entity component hashable // MARK: - entity component hashable
internal extension Component { internal extension Component {

View File

@ -9,11 +9,11 @@
public extension Entity { public extension Entity {
public final func get<C>() -> C? where C: Component { public final func get<C>() -> C? where C: Component {
return nexus.get(for: identifier) return delegate.get(for: identifier)
} }
public func get<A>(component compType: A.Type = A.self) -> A? where A: Component { public func get<A>(component compType: A.Type = A.self) -> A? where A: Component {
return nexus.get(for: identifier) return delegate.get(for: identifier)
} }
public func getComponent<A>() -> () -> A? where A: Component { public func getComponent<A>() -> () -> A? where A: Component {

View File

@ -10,25 +10,35 @@ public final class Entity: UniqueEntityIdentifiable {
internal(set) public var identifier: EntityIdentifier = EntityIdentifier.invalid internal(set) public var identifier: EntityIdentifier = EntityIdentifier.invalid
public var name: String? public var name: String?
internal let nexus: Nexus internal unowned let delegate: Nexus
internal init(nexus: Nexus, id: EntityIdentifier, name: String? = nil) { internal init(nexus: Nexus, id: EntityIdentifier, name: String? = nil) {
self.nexus = nexus self.delegate = nexus
self.identifier = id self.identifier = id
self.name = name self.name = name
} }
} }
// MARK: - activatable protocol
extension Entity: Activatable {
public func activate() {
//TODO: nexus.activate(entity: self)
}
public func deactivate() {
//TODO: nexus.deactivate(entity: self)
}
}
// MARK: - Invalidate // MARK: - Invalidate
extension Entity { extension Entity {
public var isValid: Bool { public var isValid: Bool {
return nexus.isValid(entity: self) return delegate.isValid(entity: self)
} }
internal func invalidate() { internal func invalidate() {
assert(nexus.isValid(entity: identifier), "Invalid entity \(self) is being invalidated.") assert(delegate.isValid(entity: identifier), "Invalid entity \(self) is being invalidated.")
identifier = EntityIdentifier.invalid identifier = EntityIdentifier.invalid
name = nil name = nil
} }
@ -42,7 +52,7 @@ public func ==(lhs: Entity, rhs: Entity) -> Bool {
// MARK: - number of components // MARK: - number of components
public extension Entity { public extension Entity {
public final var numComponents: Int { public final var numComponents: Int {
return nexus.count(components: identifier) return delegate.count(components: identifier)
} }
} }
@ -54,11 +64,11 @@ public extension Entity {
} }
public final func has(_ uct: ComponentIdentifier) -> Bool { public final func has(_ uct: ComponentIdentifier) -> Bool {
return nexus.has(componentId: uct, entityIdx: identifier.index) return delegate.has(componentId: uct, entityIdx: identifier.index)
} }
public final var hasComponents: Bool { public final var hasComponents: Bool {
return nexus.count(components: identifier) > 0 return delegate.count(components: identifier) > 0
} }
} }
@ -76,13 +86,13 @@ public extension Entity {
@discardableResult @discardableResult
public final func assign(_ component: Component) -> Entity { public final func assign(_ component: Component) -> Entity {
nexus.assign(component: component, to: self) delegate.assign(component: component, to: self)
return self return self
} }
@discardableResult @discardableResult
public final func assign<C>(_ component: C) -> Entity where C: Component { public final func assign<C>(_ component: C) -> Entity where C: Component {
nexus.assign(component: component, to: self) delegate.assign(component: component, to: self)
return self return self
} }
@ -112,12 +122,12 @@ public extension Entity {
@discardableResult @discardableResult
public final func remove(_ uct: ComponentIdentifier) -> Entity { public final func remove(_ uct: ComponentIdentifier) -> Entity {
nexus.remove(component: uct, from: identifier) delegate.remove(component: uct, from: identifier)
return self return self
} }
public final func clear() { public final func clear() {
nexus.clear(componentes: identifier) delegate.clear(componentes: identifier)
} }
@discardableResult @discardableResult
@ -134,6 +144,6 @@ public extension Entity {
// MARK: - destroy/deinit entity // MARK: - destroy/deinit entity
extension Entity { extension Entity {
public final func destroy() { public final func destroy() {
nexus.destroy(entity: self) delegate.destroy(entity: self)
} }
} }

View File

@ -18,7 +18,7 @@ extension Family {
public func iterate<A>(components _: A.Type, _ apply: @escaping (EntityIdentifier, A?) -> Void) public func iterate<A>(components _: A.Type, _ apply: @escaping (EntityIdentifier, A?) -> Void)
where A: Component { where A: Component {
for entityId in memberIds { for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId) let a: A? = self.delegate.get(for: entityId)
apply(entityId, a) apply(entityId, a)
} }
} }
@ -26,8 +26,8 @@ extension Family {
public func iterate<A, B>(components _: A.Type, _: B.Type, _ apply: @escaping (EntityIdentifier, A?, B?) -> Void) public func iterate<A, B>(components _: A.Type, _: B.Type, _ apply: @escaping (EntityIdentifier, A?, B?) -> Void)
where A: Component, B: Component { where A: Component, B: Component {
for entityId in memberIds { for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId) let a: A? = self.delegate.get(for: entityId)
let b: B? = self.nexus.get(for: entityId) let b: B? = self.delegate.get(for: entityId)
apply(entityId, a, b) apply(entityId, a, b)
} }
} }
@ -35,9 +35,9 @@ extension Family {
public func iterate<A, B, C>(components _: A.Type, _: B.Type, _: C.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?) -> Void) public func iterate<A, B, C>(components _: A.Type, _: B.Type, _: C.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?) -> Void)
where A: Component, B: Component, C: Component { where A: Component, B: Component, C: Component {
for entityId in memberIds { for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId) let a: A? = self.delegate.get(for: entityId)
let b: B? = self.nexus.get(for: entityId) let b: B? = self.delegate.get(for: entityId)
let c: C? = self.nexus.get(for: entityId) let c: C? = self.delegate.get(for: entityId)
apply(entityId, a, b, c) apply(entityId, a, b, c)
} }
} }
@ -45,21 +45,21 @@ extension Family {
public func iterate<A, B, C, D>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?) -> Void) public func iterate<A, B, C, D>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?) -> Void)
where A: Component, B: Component, C: Component, D: Component { where A: Component, B: Component, C: Component, D: Component {
for entityId in memberIds { for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId) let a: A? = self.delegate.get(for: entityId)
let b: B? = self.nexus.get(for: entityId) let b: B? = self.delegate.get(for: entityId)
let c: C? = self.nexus.get(for: entityId) let c: C? = self.delegate.get(for: entityId)
let d: D? = self.nexus.get(for: entityId) let d: D? = self.delegate.get(for: entityId)
apply(entityId, a, b, c, d) apply(entityId, a, b, c, d)
} }
} }
public func iterate<A, B, C, D, E>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?) -> Void) public func iterate<A, B, C, D, E>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?) -> Void)
where A: Component, B: Component, C: Component, D: Component, E: Component { where A: Component, B: Component, C: Component, D: Component, E: Component {
for entityId in memberIds { for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId) let a: A? = self.delegate.get(for: entityId)
let b: B? = self.nexus.get(for: entityId) let b: B? = self.delegate.get(for: entityId)
let c: C? = self.nexus.get(for: entityId) let c: C? = self.delegate.get(for: entityId)
let d: D? = self.nexus.get(for: entityId) let d: D? = self.delegate.get(for: entityId)
let e: E? = self.nexus.get(for: entityId) let e: E? = self.delegate.get(for: entityId)
apply(entityId, a, b, c, d, e) apply(entityId, a, b, c, d, e)
} }
} }
@ -68,12 +68,12 @@ extension Family {
_ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?, F?) -> Void) _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?, F?) -> Void)
where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component { where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
for entityId in memberIds { for entityId in memberIds {
let a: A? = self.nexus.get(for: entityId) let a: A? = self.delegate.get(for: entityId)
let b: B? = self.nexus.get(for: entityId) let b: B? = self.delegate.get(for: entityId)
let c: C? = self.nexus.get(for: entityId) let c: C? = self.delegate.get(for: entityId)
let d: D? = self.nexus.get(for: entityId) let d: D? = self.delegate.get(for: entityId)
let e: E? = self.nexus.get(for: entityId) let e: E? = self.delegate.get(for: entityId)
let f: F? = self.nexus.get(for: entityId) let f: F? = self.delegate.get(for: entityId)
apply(entityId, a, b, c, d, e, f) apply(entityId, a, b, c, d, e, f)
} }
} }

View File

@ -7,40 +7,42 @@
// MARK: - family // MARK: - family
public final class Family { public final class Family {
internal var nexus: Nexus internal unowned var delegate: Nexus
// members of this Family must conform to these traits // members of this Family must conform to these traits
public let traits: FamilyTraitSet public let traits: FamilyTraitSet
internal init(_ nexus: Nexus, traits: FamilyTraitSet) { internal init(_ nexus: Nexus, traits: FamilyTraitSet) {
self.nexus = nexus self.delegate = nexus
self.traits = traits self.traits = traits
defer {
nexus.onFamilyCreated(family: self)
}
} }
deinit { deinit {
delegate.onFamilyRemove(family: self)
} }
} }
extension Family { extension Family {
public var count: Int { public var count: Int {
return nexus.members(of: self).count return delegate.members(of: self).count
} }
public final func canBecomeMember(_ entity: Entity) -> Bool { public final func canBecomeMember(_ entity: Entity) -> Bool {
return nexus.canBecomeMember(entity, in: self) return delegate.canBecomeMember(entity, in: self)
} }
public final func isMember(_ entity: Entity) -> Bool { public final func isMember(_ entity: Entity) -> Bool {
return nexus.isMember(entity, in: self) return delegate.isMember(entity, in: self)
} }
public final func isMember(_ entityId: EntityIdentifier) -> Bool { public final func isMember(_ entityId: EntityIdentifier) -> Bool {
return nexus.isMember(entityId, in: self) return delegate.isMember(entityId, in: self)
} }
internal var memberIds: UniformEntityIdentifiers { internal var memberIds: UniformEntityIdentifiers {
return nexus.members(of: self) return delegate.members(of: self)
} }
} }

View File

@ -108,7 +108,7 @@ extension Nexus {
// relocate remaining indices pointing in the componentsByEntity map // relocate remaining indices pointing in the componentsByEntity map
if let remainingComponents: ComponentIdentifiers = componentIdsByEntity[entityIdx] { if let remainingComponents: ComponentIdentifiers = componentIdsByEntity[entityIdx] {
// FIXME: may be expensive but is cheap for small entities // FIXME: may be expensive but is cheap for small entities -> may be fixed with a sparse set?!
for (index, compId) in remainingComponents.enumerated() { for (index, compId) in remainingComponents.enumerated() {
let cHash: EntityComponentHash = compId.hashValue(using: entityIdx) let cHash: EntityComponentHash = compId.hashValue(using: entityIdx)
assert(cHash != hash) assert(cHash != hash)

View File

@ -64,17 +64,24 @@ extension Nexus {
let family = Family(self, traits: traits) let family = Family(self, traits: traits)
let replaced = familiyByTraitHash.updateValue(family, forKey: traitHash) let replaced = familiyByTraitHash.updateValue(family, forKey: traitHash)
assert(replaced == nil, "Family with exact trait hash already exists: \(traitHash)") assert(replaced == nil, "Family with exact trait hash already exists: \(traitHash)")
// FIXME: this is costly for many entities
for entity: Entity in entityStorage {
update(membership: family, for: entity.identifier)
}
notify(FamilyCreated(family: traits)) notify(FamilyCreated(family: traits))
return family return family
} }
// FIXME: remove families?! /// will be called on family init defer
internal func onFamilyCreated(family: Family) {
// FIXME: this is costly for many entities
for entity: Entity in entityStorage {
update(membership: family, for: entity.identifier)
}
}
internal func onFamilyRemove(family: Family) {
let traitHash: FamilyTraitSetHash = family.traits.hashValue
for member in members(of: family) {
remove(from: traitHash, entityId: member, entityIdx: member.index)
}
}
// MARK: - update family membership // MARK: - update family membership

View File

@ -33,7 +33,7 @@ public class Nexus {
/// - Key: entity id as index /// - Key: entity id as index
/// - Value: each element is a component identifier associated with this entity /// - Value: each element is a component identifier associated with this entity
var componentIdsByEntity: [EntityIndex: ComponentIdentifiers] var componentIdsByEntity: [EntityIndex: ComponentIdentifiers] // TODO: sparse set?!
/// - Key 'entity id' - 'component type' hash that uniquely links both /// - Key 'entity id' - 'component type' hash that uniquely links both
/// - Value: each element is an index pointing to the component identifier per entity in the componentIdsByEntity map /// - Value: each element is an index pointing to the component identifier per entity in the componentIdsByEntity map
@ -56,6 +56,11 @@ public class Nexus {
} }
deinit {
// FIXME: clear all things and cleanup
print("nexus deinit")
}
} }
extension Nexus { extension Nexus {

View File

@ -39,19 +39,19 @@ public class SparseSet<Element>: UniformStorage, Sequence {
size += 1 size += 1
} }
public func get(at entityIdx: Index) -> Element? { public func get(at index: Index) -> Element? {
guard has(entityIdx) else { return nil } guard has(index) else { return nil }
return dense[sparse[entityIdx]!]!.value return dense[sparse[index]!]!.value
} }
public func remove(at index: Index) { public func remove(at index: Index) {
guard has(index) else { return } guard has(index) else { return }
let compIdx: DenseIndex = sparse[index]! let removeIdx: DenseIndex = sparse[index]!
let lastIdx: DenseIndex = count-1 let lastIdx: DenseIndex = count-1
dense.swapAt(compIdx, lastIdx) dense.swapAt(removeIdx, lastIdx)
sparse[index] = nil sparse[index] = nil
let swapped: Pair = dense[compIdx]! let swapped: Pair = dense[removeIdx]!
sparse[swapped.key] = compIdx sparse[swapped.key] = removeIdx
_ = dense.popLast()!! _ = dense.popLast()!!
size -= 1 size -= 1
if size == 0 { if size == 0 {

View File

@ -1,5 +1,5 @@
// //
// SparseComponentSetTests.swift // SparseSetTests.swift
// FirebladeECSTests // FirebladeECSTests
// //
// Created by Christian Treffs on 31.10.17. // Created by Christian Treffs on 31.10.17.
@ -8,9 +8,9 @@
import XCTest import XCTest
@testable import FirebladeECS @testable import FirebladeECS
class SparseComponentSetTests: XCTestCase { class SparseSetTests: XCTestCase {
func testSet() { func testSparseComponentSet() {
let s = SparseComponentSet() let s = SparseComponentSet()
let num: Int = 100 let num: Int = 100