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.
|
// 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 {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue