diff --git a/Sources/FirebladeECS/Entity.swift b/Sources/FirebladeECS/Entity.swift index dec663d..ec3ba7b 100644 --- a/Sources/FirebladeECS/Entity.swift +++ b/Sources/FirebladeECS/Entity.swift @@ -8,9 +8,12 @@ public final class Entity: UniqueEntityIdentifiable { public let uei: UEI + public var name: String? + + @available(*, deprecated: 0.1, message: "replace this with core/context concept") fileprivate var eventDispatcher: EventDispatcher - public private(set) var componentMap: [UCT:Component] + public private(set) var componentMap: [UCT: Component] init(uei: UEI, dispatcher: EventDispatcher) { self.uei = uei @@ -161,7 +164,7 @@ extension Entity { } extension Entity: EventDispatcher { - public func dispatch(_ event: E) where E : Event { + public func dispatch(_ event: E) where E: Event { eventDispatcher.dispatch(event) } diff --git a/Sources/FirebladeECS/EntityHub.swift b/Sources/FirebladeECS/EntityHub.swift index 40ce8d5..b581611 100644 --- a/Sources/FirebladeECS/EntityHub.swift +++ b/Sources/FirebladeECS/EntityHub.swift @@ -10,16 +10,13 @@ public class EntityHub: EventHandler { public lazy var eventHub: DefaultEventHub = { return DefaultEventHub() }() - private(set) var entites: Set - //private(set) var entites: [UEI:Entity] = [:] - private(set) var families: [FamilyTraits:Family] + private(set) var entities: EntityStorage + private(set) var families: FamilyStorage public init() { - entites = Set() - entites.reserveCapacity(512) + entities = DefaultEntityStorage() - families = [FamilyTraits: Family]() - families.reserveCapacity(64) + families = DefaultFamilyStorage() self.delegate = eventHub @@ -60,7 +57,7 @@ extension EntityHub { public func createEntity() -> Entity { let newEntity = Entity(uei: UEI.next, dispatcher: eventHub) // ^ dispatches entity creation event here ^ - let (success, _) = entites.insert(newEntity) + let success: Bool = entities.add(newEntity) assert(success == true, "Entity with the exact identifier already exists") return newEntity @@ -80,8 +77,8 @@ extension EntityHub { let newFamily = Family(traits: traits, eventHub: eventHub) // ^ dispatches family creation event here ^ - let replaced = families.updateValue(newFamily, forKey: traits) - assert(replaced == nil, "Family with the exact traits already exists") + let success = families.add(newFamily) + assert(success, "Family with the exact traits already exists") refreshFamilyCache() @@ -89,8 +86,8 @@ extension EntityHub { } fileprivate func onFamilyCreated(_ newFamily: Family) { - let previousEntities = entites - newFamily.update(membership: previousEntities) + + newFamily.update(membership: entities.iterator) } fileprivate func refreshFamilyCache() { diff --git a/Sources/FirebladeECS/EntityStorage.swift b/Sources/FirebladeECS/EntityStorage.swift new file mode 100644 index 0000000..899534f --- /dev/null +++ b/Sources/FirebladeECS/EntityStorage.swift @@ -0,0 +1,91 @@ +// +// EntityStorage.swift +// FirebladeECS +// +// Created by Christian Treffs on 10.10.17. +// + +public protocol EntityStorage { + @discardableResult func add(_ entity: Entity) -> Bool + + var iterator: AnyIterator { get } + + func has(_ entity: Entity) -> Bool + func has(_ id: UEI) -> Bool + func has(_ named: String) -> Bool + + func get(_ id: UEI) -> Entity? + subscript(_ id: UEI) -> Entity? { get } + + func get(_ named: String) -> Entity? + subscript(_ named: String) -> Entity? { get } + + @discardableResult func remove(_ id: UEI) -> Bool + + func clear() + +} + +class DefaultEntityStorage: EntityStorage { + + fileprivate typealias Index = Set.Index + fileprivate var entities: Set = Set() + + var iterator: AnyIterator { + return AnyIterator(entities.makeIterator()) + } + + @discardableResult + func add(_ entity: Entity) -> Bool { + let (success, _) = entities.insert(entity) + return success + } + + func has(_ entity: Entity) -> Bool { + return entities.contains(entity) + } + + func has(_ id: UEI) -> Bool { + return entities.contains { $0.uei == id } + } + + func has(_ named: String) -> Bool { + return entities.contains { $0.name == named } + } + + func get(_ id: UEI) -> Entity? { + guard let index = index(id) else { return nil } + return entities[index] + } + + subscript(id: UEI) -> Entity? { return get(id) } + + func get(_ named: String) -> Entity? { + guard let index: Index = index(named) else { return nil } + return entities[index] + } + + subscript(named: String) -> Entity? { return get(named) } + + @discardableResult + func remove(_ id: UEI) -> Bool { + guard let index: Index = index(id) else { return false } + entities.remove(at: index) + return true + } + + func clear() { + entities.removeAll() + } + + // MARK: - internal + + fileprivate func index(_ id: UEI) -> Index? { + return entities.index { $0.uei == id } + } + + fileprivate func index(_ named: String) -> Index? { + return entities.index { $0.name == named } + } + +} diff --git a/Sources/FirebladeECS/Family.swift b/Sources/FirebladeECS/Family.swift index b78724b..992e69d 100644 --- a/Sources/FirebladeECS/Family.swift +++ b/Sources/FirebladeECS/Family.swift @@ -54,9 +54,8 @@ public final class Family { // MARK: - update family membership extension Family { - func update(membership entites: C) where C.Iterator.Element == Entity { - var entityIterator = entites.makeIterator() - while let entity: Entity = entityIterator.next() { + func update(membership entities: AnyIterator) { + while let entity: Entity = entities.next() { update(membership: entity) } } @@ -140,7 +139,7 @@ extension Family: Hashable { // MARK: - event dispatcher extension Family: EventDispatcher { - public func dispatch(_ event: E) where E : Event { + public func dispatch(_ event: E) where E: Event { dispatcher.dispatch(event) } diff --git a/Sources/FirebladeECS/FamilyStorage.swift b/Sources/FirebladeECS/FamilyStorage.swift new file mode 100644 index 0000000..b5ace74 --- /dev/null +++ b/Sources/FirebladeECS/FamilyStorage.swift @@ -0,0 +1,86 @@ +// +// FamilyStorage.swift +// FirebladeECS +// +// Created by Christian Treffs on 10.10.17. +// + +public protocol FamilyStorage { + @discardableResult func add(_ family: Family) -> Bool + + var iterator: AnyIterator<(FamilyTraits, Family)> { get } + + func has(_ family: Family) -> Bool + func has(_ traits: FamilyTraits) -> Bool + + func get(_ traits: FamilyTraits) -> Family? + subscript(_ traits: FamilyTraits) -> Family? { get } + + @discardableResult func remove(_ family: Family) -> Bool + @discardableResult func remove(_ traits: FamilyTraits) -> Bool + + func clear() +} + +class DefaultFamilyStorage: FamilyStorage { + + fileprivate typealias Index = Dictionary.Index + fileprivate var families: [FamilyTraits: Family] = [:] + + var iterator: AnyIterator<(FamilyTraits, Family)> { + // see: https://www.raywenderlich.com/139591/building-custom-collection-swift + var iter = families.makeIterator() + return AnyIterator<(FamilyTraits, Family)> { + return iter.next() + } + } + + func add(_ family: Family) -> Bool { + let replaced: Family? = families.updateValue(family, forKey: family.traits) + let success: Bool = replaced == nil + assert(success) + return success + } + + func has(_ family: Family) -> Bool { + return index(family) != nil + } + + func has(_ traits: FamilyTraits) -> Bool { + return index(traits) != nil + } + + func get(_ traits: FamilyTraits) -> Family? { + return families[traits] + } + + subscript(_ traits: FamilyTraits) -> Family? { + return get(traits) + } + + func remove(_ family: Family) -> Bool { + guard let index = index(family) else { return false } + families.remove(at: index) + return true + } + + func remove(_ traits: FamilyTraits) -> Bool { + guard let index = index(traits) else { return false } + families.remove(at: index) + return true + } + + func clear() { + families.removeAll() + } + + // MARK: - private + private func index(_ traits: FamilyTraits) -> Index? { + return families.index(forKey: traits) + } + + private func index(_ family: Family) -> Index? { + return index(family.traits) + } + +} diff --git a/Tests/FirebladeECSTests/EntityHubTests.swift b/Tests/FirebladeECSTests/EntityHubTests.swift index 4d427e9..bbcded4 100644 --- a/Tests/FirebladeECSTests/EntityHubTests.swift +++ b/Tests/FirebladeECSTests/EntityHubTests.swift @@ -21,8 +21,8 @@ class EntityHubTests: XCTestCase { let newEntity: Entity = entityHub.createEntity() XCTAssert(newEntity.hasComponents == false) - //TODO: XCTAssert(entityHub.entites[newEntity.uei] == newEntity) - //TODO: XCTAssert(entityHub.entites[newEntity.uei] === newEntity) + //TODO: XCTAssert(entityHub.entities[newEntity.uei] == newEntity) + //TODO: XCTAssert(entityHub.entities[newEntity.uei] === newEntity) } func testCreateEntityAndAddComponent() { @@ -35,8 +35,8 @@ class EntityHubTests: XCTestCase { XCTAssert(newEntity.hasComponents) XCTAssert(newEntity.numComponents == 1) - //TODO: XCTAssert(entityHub.entites[newEntity.uei] == newEntity) - //TODO: XCTAssert(entityHub.entites[newEntity.uei] === newEntity) + //TODO: XCTAssert(entityHub.entities[newEntity.uei] == newEntity) + //TODO: XCTAssert(entityHub.entities[newEntity.uei] === newEntity) } @@ -51,7 +51,7 @@ extension EntityHubTests: EventSniffer { } - public func dispatched(event: E) where E : Event { + public func dispatched(event: E) where E: Event { } diff --git a/Tests/FirebladeECSTests/FamilyTests.swift b/Tests/FirebladeECSTests/FamilyTests.swift index ae29a86..4cee2a2 100644 --- a/Tests/FirebladeECSTests/FamilyTests.swift +++ b/Tests/FirebladeECSTests/FamilyTests.swift @@ -22,6 +22,8 @@ class FamilyTests: XCTestCase { let (empty, name) = e1.components(EmptyComponent.self, Name.self) + print(empty, name) + e1.components { (empty: EmptyComponent, name: Name) in print(empty, name) }