Add Entity and Family storage implementations

This commit is contained in:
Christian Treffs 2017-10-10 22:18:14 +02:00
parent fb2d011c8d
commit e16759f9f1
7 changed files with 201 additions and 23 deletions

View File

@ -8,9 +8,12 @@
public final class Entity: UniqueEntityIdentifiable { public final class Entity: UniqueEntityIdentifiable {
public let uei: UEI public let uei: UEI
public var name: String?
@available(*, deprecated: 0.1, message: "replace this with core/context concept")
fileprivate var eventDispatcher: EventDispatcher fileprivate var eventDispatcher: EventDispatcher
public private(set) var componentMap: [UCT:Component] public private(set) var componentMap: [UCT: Component]
init(uei: UEI, dispatcher: EventDispatcher) { init(uei: UEI, dispatcher: EventDispatcher) {
self.uei = uei self.uei = uei
@ -161,7 +164,7 @@ extension Entity {
} }
extension Entity: EventDispatcher { extension Entity: EventDispatcher {
public func dispatch<E>(_ event: E) where E : Event { public func dispatch<E>(_ event: E) where E: Event {
eventDispatcher.dispatch(event) eventDispatcher.dispatch(event)
} }

View File

@ -10,16 +10,13 @@ public class EntityHub: EventHandler {
public lazy var eventHub: DefaultEventHub = { return DefaultEventHub() }() public lazy var eventHub: DefaultEventHub = { return DefaultEventHub() }()
private(set) var entites: Set<Entity> private(set) var entities: EntityStorage
//private(set) var entites: [UEI:Entity] = [:] private(set) var families: FamilyStorage
private(set) var families: [FamilyTraits:Family]
public init() { public init() {
entites = Set<Entity>() entities = DefaultEntityStorage()
entites.reserveCapacity(512)
families = [FamilyTraits: Family]() families = DefaultFamilyStorage()
families.reserveCapacity(64)
self.delegate = eventHub self.delegate = eventHub
@ -60,7 +57,7 @@ extension EntityHub {
public func createEntity() -> Entity { public func createEntity() -> Entity {
let newEntity = Entity(uei: UEI.next, dispatcher: eventHub) let newEntity = Entity(uei: UEI.next, dispatcher: eventHub)
// ^ dispatches entity creation event here ^ // ^ 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") assert(success == true, "Entity with the exact identifier already exists")
return newEntity return newEntity
@ -80,8 +77,8 @@ extension EntityHub {
let newFamily = Family(traits: traits, eventHub: eventHub) let newFamily = Family(traits: traits, eventHub: eventHub)
// ^ dispatches family creation event here ^ // ^ dispatches family creation event here ^
let replaced = families.updateValue(newFamily, forKey: traits) let success = families.add(newFamily)
assert(replaced == nil, "Family with the exact traits already exists") assert(success, "Family with the exact traits already exists")
refreshFamilyCache() refreshFamilyCache()
@ -89,8 +86,8 @@ extension EntityHub {
} }
fileprivate func onFamilyCreated(_ newFamily: Family) { fileprivate func onFamilyCreated(_ newFamily: Family) {
let previousEntities = entites
newFamily.update(membership: previousEntities) newFamily.update(membership: entities.iterator)
} }
fileprivate func refreshFamilyCache() { fileprivate func refreshFamilyCache() {

View File

@ -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<Entity> { 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<Entity>.Index
fileprivate var entities: Set<Entity> = Set<Entity>()
var iterator: AnyIterator<Entity> {
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 }
}
}

View File

@ -54,9 +54,8 @@ public final class Family {
// MARK: - update family membership // MARK: - update family membership
extension Family { extension Family {
func update<C: Collection>(membership entites: C) where C.Iterator.Element == Entity { func update(membership entities: AnyIterator<Entity>) {
var entityIterator = entites.makeIterator() while let entity: Entity = entities.next() {
while let entity: Entity = entityIterator.next() {
update(membership: entity) update(membership: entity)
} }
} }
@ -140,7 +139,7 @@ extension Family: Hashable {
// MARK: - event dispatcher // MARK: - event dispatcher
extension Family: EventDispatcher { extension Family: EventDispatcher {
public func dispatch<E>(_ event: E) where E : Event { public func dispatch<E>(_ event: E) where E: Event {
dispatcher.dispatch(event) dispatcher.dispatch(event)
} }

View File

@ -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<FamilyTraits, Family>.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)
}
}

View File

@ -21,8 +21,8 @@ class EntityHubTests: XCTestCase {
let newEntity: Entity = entityHub.createEntity() let newEntity: Entity = entityHub.createEntity()
XCTAssert(newEntity.hasComponents == false) XCTAssert(newEntity.hasComponents == false)
//TODO: XCTAssert(entityHub.entites[newEntity.uei] == newEntity) //TODO: XCTAssert(entityHub.entities[newEntity.uei] == newEntity)
//TODO: XCTAssert(entityHub.entites[newEntity.uei] === newEntity) //TODO: XCTAssert(entityHub.entities[newEntity.uei] === newEntity)
} }
func testCreateEntityAndAddComponent() { func testCreateEntityAndAddComponent() {
@ -35,8 +35,8 @@ class EntityHubTests: XCTestCase {
XCTAssert(newEntity.hasComponents) XCTAssert(newEntity.hasComponents)
XCTAssert(newEntity.numComponents == 1) XCTAssert(newEntity.numComponents == 1)
//TODO: XCTAssert(entityHub.entites[newEntity.uei] == newEntity) //TODO: XCTAssert(entityHub.entities[newEntity.uei] == newEntity)
//TODO: XCTAssert(entityHub.entites[newEntity.uei] === newEntity) //TODO: XCTAssert(entityHub.entities[newEntity.uei] === newEntity)
} }
@ -51,7 +51,7 @@ extension EntityHubTests: EventSniffer {
} }
public func dispatched<E>(event: E) where E : Event { public func dispatched<E>(event: E) where E: Event {
} }

View File

@ -22,6 +22,8 @@ class FamilyTests: XCTestCase {
let (empty, name) = e1.components(EmptyComponent.self, Name.self) let (empty, name) = e1.components(EmptyComponent.self, Name.self)
print(empty, name)
e1.components { (empty: EmptyComponent, name: Name) in e1.components { (empty: EmptyComponent, name: Name) in
print(empty, name) print(empty, name)
} }