Add Entity and Family storage implementations
This commit is contained in:
parent
fb2d011c8d
commit
e16759f9f1
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue