Fix some reference counting
This commit is contained in:
parent
5dd149dd82
commit
78c248ab0a
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Activatable.swift
|
||||
// FirebladeECSPackageDescription
|
||||
//
|
||||
// Created by Christian Treffs on 02.11.17.
|
||||
//
|
||||
|
||||
public protocol Activatable {
|
||||
func activate()
|
||||
func deactivate()
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Christian Treffs on 08.10.17.
|
||||
//
|
||||
|
||||
public protocol Component: class, UniqueComponentIdentifiable {}
|
||||
public protocol Component: class, UniqueComponentIdentifiable, Activatable {}
|
||||
|
||||
// MARK: UCI
|
||||
extension Component {
|
||||
|
|
@ -15,6 +15,12 @@ extension Component {
|
|||
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
|
||||
internal extension Component {
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
public extension Entity {
|
||||
|
||||
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 {
|
||||
return nexus.get(for: identifier)
|
||||
return delegate.get(for: identifier)
|
||||
}
|
||||
|
||||
public func getComponent<A>() -> () -> A? where A: Component {
|
||||
|
|
|
|||
|
|
@ -10,25 +10,35 @@ public final class Entity: UniqueEntityIdentifiable {
|
|||
internal(set) public var identifier: EntityIdentifier = EntityIdentifier.invalid
|
||||
public var name: String?
|
||||
|
||||
internal let nexus: Nexus
|
||||
internal unowned let delegate: Nexus
|
||||
|
||||
internal init(nexus: Nexus, id: EntityIdentifier, name: String? = nil) {
|
||||
self.nexus = nexus
|
||||
self.delegate = nexus
|
||||
self.identifier = id
|
||||
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
|
||||
extension Entity {
|
||||
|
||||
public var isValid: Bool {
|
||||
return nexus.isValid(entity: self)
|
||||
return delegate.isValid(entity: self)
|
||||
}
|
||||
|
||||
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
|
||||
name = nil
|
||||
}
|
||||
|
|
@ -42,7 +52,7 @@ public func ==(lhs: Entity, rhs: Entity) -> Bool {
|
|||
// MARK: - number of components
|
||||
public extension Entity {
|
||||
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 {
|
||||
return nexus.has(componentId: uct, entityIdx: identifier.index)
|
||||
return delegate.has(componentId: uct, entityIdx: identifier.index)
|
||||
}
|
||||
|
||||
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
|
||||
public final func assign(_ component: Component) -> Entity {
|
||||
nexus.assign(component: component, to: self)
|
||||
delegate.assign(component: component, to: self)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -112,12 +122,12 @@ public extension Entity {
|
|||
|
||||
@discardableResult
|
||||
public final func remove(_ uct: ComponentIdentifier) -> Entity {
|
||||
nexus.remove(component: uct, from: identifier)
|
||||
delegate.remove(component: uct, from: identifier)
|
||||
return self
|
||||
}
|
||||
|
||||
public final func clear() {
|
||||
nexus.clear(componentes: identifier)
|
||||
delegate.clear(componentes: identifier)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
|
|
@ -134,6 +144,6 @@ public extension Entity {
|
|||
// MARK: - destroy/deinit entity
|
||||
extension Entity {
|
||||
public final func destroy() {
|
||||
nexus.destroy(entity: self)
|
||||
delegate.destroy(entity: self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ extension Family {
|
|||
public func iterate<A>(components _: A.Type, _ apply: @escaping (EntityIdentifier, A?) -> Void)
|
||||
where A: Component {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let a: A? = self.delegate.get(for: entityId)
|
||||
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)
|
||||
where A: Component, B: Component {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let a: A? = self.delegate.get(for: entityId)
|
||||
let b: B? = self.delegate.get(for: entityId)
|
||||
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)
|
||||
where A: Component, B: Component, C: Component {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
let a: A? = self.delegate.get(for: entityId)
|
||||
let b: B? = self.delegate.get(for: entityId)
|
||||
let c: C? = self.delegate.get(for: entityId)
|
||||
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)
|
||||
where A: Component, B: Component, C: Component, D: Component {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
let d: D? = self.nexus.get(for: entityId)
|
||||
let a: A? = self.delegate.get(for: entityId)
|
||||
let b: B? = self.delegate.get(for: entityId)
|
||||
let c: C? = self.delegate.get(for: entityId)
|
||||
let d: D? = self.delegate.get(for: entityId)
|
||||
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)
|
||||
where A: Component, B: Component, C: Component, D: Component, E: Component {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
let d: D? = self.nexus.get(for: entityId)
|
||||
let e: E? = self.nexus.get(for: entityId)
|
||||
let a: A? = self.delegate.get(for: entityId)
|
||||
let b: B? = self.delegate.get(for: entityId)
|
||||
let c: C? = self.delegate.get(for: entityId)
|
||||
let d: D? = self.delegate.get(for: entityId)
|
||||
let e: E? = self.delegate.get(for: entityId)
|
||||
apply(entityId, a, b, c, d, e)
|
||||
}
|
||||
}
|
||||
|
|
@ -68,12 +68,12 @@ extension Family {
|
|||
_ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?, F?) -> Void)
|
||||
where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
let d: D? = self.nexus.get(for: entityId)
|
||||
let e: E? = self.nexus.get(for: entityId)
|
||||
let f: F? = self.nexus.get(for: entityId)
|
||||
let a: A? = self.delegate.get(for: entityId)
|
||||
let b: B? = self.delegate.get(for: entityId)
|
||||
let c: C? = self.delegate.get(for: entityId)
|
||||
let d: D? = self.delegate.get(for: entityId)
|
||||
let e: E? = self.delegate.get(for: entityId)
|
||||
let f: F? = self.delegate.get(for: entityId)
|
||||
apply(entityId, a, b, c, d, e, f)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,40 +7,42 @@
|
|||
|
||||
// MARK: - family
|
||||
public final class Family {
|
||||
internal var nexus: Nexus
|
||||
internal unowned var delegate: Nexus
|
||||
// members of this Family must conform to these traits
|
||||
public let traits: FamilyTraitSet
|
||||
|
||||
internal init(_ nexus: Nexus, traits: FamilyTraitSet) {
|
||||
self.nexus = nexus
|
||||
self.delegate = nexus
|
||||
self.traits = traits
|
||||
|
||||
defer {
|
||||
nexus.onFamilyCreated(family: self)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
delegate.onFamilyRemove(family: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Family {
|
||||
|
||||
public var count: Int {
|
||||
return nexus.members(of: self).count
|
||||
return delegate.members(of: self).count
|
||||
}
|
||||
|
||||
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 {
|
||||
return nexus.isMember(entity, in: self)
|
||||
return delegate.isMember(entity, in: self)
|
||||
}
|
||||
|
||||
public final func isMember(_ entityId: EntityIdentifier) -> Bool {
|
||||
return nexus.isMember(entityId, in: self)
|
||||
return delegate.isMember(entityId, in: self)
|
||||
}
|
||||
|
||||
internal var memberIds: UniformEntityIdentifiers {
|
||||
return nexus.members(of: self)
|
||||
return delegate.members(of: self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ extension Nexus {
|
|||
|
||||
// relocate remaining indices pointing in the componentsByEntity map
|
||||
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() {
|
||||
let cHash: EntityComponentHash = compId.hashValue(using: entityIdx)
|
||||
assert(cHash != hash)
|
||||
|
|
|
|||
|
|
@ -64,17 +64,24 @@ extension Nexus {
|
|||
let family = Family(self, traits: traits)
|
||||
let replaced = familiyByTraitHash.updateValue(family, forKey: 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))
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class Nexus {
|
|||
|
||||
/// - Key: entity id as index
|
||||
/// - 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
|
||||
/// - 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 {
|
||||
|
|
|
|||
|
|
@ -39,19 +39,19 @@ public class SparseSet<Element>: UniformStorage, Sequence {
|
|||
size += 1
|
||||
}
|
||||
|
||||
public func get(at entityIdx: Index) -> Element? {
|
||||
guard has(entityIdx) else { return nil }
|
||||
return dense[sparse[entityIdx]!]!.value
|
||||
public func get(at index: Index) -> Element? {
|
||||
guard has(index) else { return nil }
|
||||
return dense[sparse[index]!]!.value
|
||||
}
|
||||
|
||||
public func remove(at index: Index) {
|
||||
guard has(index) else { return }
|
||||
let compIdx: DenseIndex = sparse[index]!
|
||||
let removeIdx: DenseIndex = sparse[index]!
|
||||
let lastIdx: DenseIndex = count-1
|
||||
dense.swapAt(compIdx, lastIdx)
|
||||
dense.swapAt(removeIdx, lastIdx)
|
||||
sparse[index] = nil
|
||||
let swapped: Pair = dense[compIdx]!
|
||||
sparse[swapped.key] = compIdx
|
||||
let swapped: Pair = dense[removeIdx]!
|
||||
sparse[swapped.key] = removeIdx
|
||||
_ = dense.popLast()!!
|
||||
size -= 1
|
||||
if size == 0 {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// SparseComponentSetTests.swift
|
||||
// SparseSetTests.swift
|
||||
// FirebladeECSTests
|
||||
//
|
||||
// Created by Christian Treffs on 31.10.17.
|
||||
|
|
@ -8,9 +8,9 @@
|
|||
import XCTest
|
||||
@testable import FirebladeECS
|
||||
|
||||
class SparseComponentSetTests: XCTestCase {
|
||||
class SparseSetTests: XCTestCase {
|
||||
|
||||
func testSet() {
|
||||
func testSparseComponentSet() {
|
||||
let s = SparseComponentSet()
|
||||
|
||||
let num: Int = 100
|
||||
Loading…
Reference in New Issue