Cleanups
This commit is contained in:
parent
00bb739880
commit
41745a1fa7
|
|
@ -194,85 +194,3 @@ public extension Entity {
|
||||||
return (a, b, c, d, e, f)
|
return (a, b, c, d, e, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
extension Entity: EventDispatcher {
|
|
||||||
public func dispatch<E>(_ event: E) where E: Event {
|
|
||||||
eventDispatcher.dispatch(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func unowned(_ closure: @escaping (Entity) -> Void) {
|
|
||||||
#if DEBUG
|
|
||||||
let preActionCount: Int = retainCount(self)
|
|
||||||
#endif
|
|
||||||
let unownedClosure = { [unowned self] in
|
|
||||||
closure(self)
|
|
||||||
}
|
|
||||||
unownedClosure()
|
|
||||||
#if DEBUG
|
|
||||||
let postActionCount: Int = retainCount(self)
|
|
||||||
assert(postActionCount == preActionCount, "retain count missmatch [\(preActionCount)] -> [\(postActionCount)]")
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private func notifyInit() {
|
|
||||||
unowned {
|
|
||||||
$0.dispatch(EntityCreated(entity: $0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func notify<C>(add component: C) {
|
|
||||||
unowned {
|
|
||||||
$0.dispatch(ComponentAdded(to: $0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func notify<C>(update newComponent: C, previous previousComponent: C) {
|
|
||||||
unowned {
|
|
||||||
$0.dispatch(ComponentUpdated(at: $0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func notify<C>(removed component: C) {
|
|
||||||
unowned {
|
|
||||||
$0.dispatch(ComponentRemoved(from: $0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func notify(removed component) {
|
|
||||||
//unowned { /* this keeps a reference since we need it */
|
|
||||||
dispatch(ComponentRemoved(from: self))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func notifyDestoryed() {
|
|
||||||
//unowned {
|
|
||||||
//$0.dispatch(event: EntityDestroyed(entity: $0))
|
|
||||||
//TODO: here entity is already dead
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - debugging and string representation
|
|
||||||
|
|
||||||
extension Entity: CustomStringConvertible {
|
|
||||||
|
|
||||||
fileprivate var componentsString: String {
|
|
||||||
let compTypes: [String] = componentMap.map { String(describing: $0.value.uct.type) }
|
|
||||||
return compTypes.joined(separator: ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
public var description: String {
|
|
||||||
return "Entity[\(uei)][\(numComponents):\(componentsString)]"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Entity: CustomPlaygroundQuickLookable {
|
|
||||||
public var customPlaygroundQuickLook: PlaygroundQuickLook {
|
|
||||||
return .text(self.description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
//
|
|
||||||
// EventHandling.swift
|
|
||||||
// FirebladeECS
|
|
||||||
//
|
|
||||||
// Created by Christian Treffs on 08.10.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
// MARK: - event
|
|
||||||
public protocol Event: UniqueEventIdentifiable { }
|
|
||||||
public extension Event {
|
|
||||||
static var uet: UET { return UET(Self.self) }
|
|
||||||
var uet: UET { return Self.uet }
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - event handler
|
|
||||||
public struct EventHandlerRef {
|
|
||||||
unowned var eventHandlerClassRefUnowned: EventHandler
|
|
||||||
let eventHandler: (Event) -> Void
|
|
||||||
}
|
|
||||||
|
|
||||||
public protocol EventHandler: class {
|
|
||||||
func subscribe<E: Event>(event eventHandler: @escaping (E) -> Void)
|
|
||||||
func unsubscribe<E: Event>(event eventHandler: @escaping (E) -> Void)
|
|
||||||
|
|
||||||
weak var delegate: EventHub? { get set }
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension EventHandler {
|
|
||||||
|
|
||||||
fileprivate func unowned(_ closure: @escaping (EventHandler) -> Void) {
|
|
||||||
#if DEBUG
|
|
||||||
let preActionCount: Int = retainCount(self)
|
|
||||||
#endif
|
|
||||||
let unownedClosure = { [unowned self] in
|
|
||||||
closure(self)
|
|
||||||
}
|
|
||||||
unownedClosure()
|
|
||||||
#if DEBUG
|
|
||||||
let postActionCount: Int = retainCount(self)
|
|
||||||
assert(postActionCount == preActionCount, "retain count missmatch [\(preActionCount)] -> [\(postActionCount)]")
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Subscribe with an event handler closure to receive events of type T
|
|
||||||
///
|
|
||||||
/// - Parameter eventHandler: event handler closure
|
|
||||||
public func subscribe<E: Event>(event eventHandler: @escaping (E) -> Void) {
|
|
||||||
unowned {
|
|
||||||
self.delegate?.subscribe(classRef: $0, eventHandler: eventHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unsubscribe from an event handler closure to stop receiving events of type T
|
|
||||||
///
|
|
||||||
/// - Parameter eventHandler: event handler closure
|
|
||||||
public func unsubscribe<E: Event>(event eventHandler: @escaping (E) -> Void) {
|
|
||||||
unowned {
|
|
||||||
self.delegate?.unsubscribe(classRef: $0, eventHandler: eventHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public extension ContiguousArray where Element == EventHandlerRef {
|
|
||||||
public func index(is eventHandler: EventHandler) -> Int? { // FIXME: this my be costly
|
|
||||||
return index { (eventHandlerRef: EventHandlerRef) -> Bool in
|
|
||||||
return eventHandlerRef.eventHandlerClassRefUnowned === eventHandler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - event dispatcher
|
|
||||||
public protocol EventDispatcher: class {
|
|
||||||
func dispatch<E: Event>(_ event: E)
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
//
|
|
||||||
// EventHub.swift
|
|
||||||
// FirebladeECS
|
|
||||||
//
|
|
||||||
// Created by Christian Treffs on 09.10.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
public protocol EventHub: class {
|
|
||||||
func subscribe<E: Event>(classRef eventHandlerRefUnowned: EventHandler, eventHandler: @escaping (E) -> Void)
|
|
||||||
func unsubscribe<E: Event>(classRef eventHandlerRefUnowned: EventHandler, eventHandler: @escaping (E) -> Void)
|
|
||||||
|
|
||||||
weak var sniffer: EventSniffer? { get set }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DefaultEventHub: EventHub, EventDispatcher {
|
|
||||||
|
|
||||||
public var sniffer: EventSniffer?
|
|
||||||
|
|
||||||
public init() { }
|
|
||||||
|
|
||||||
private var listeners: [UET: ContiguousArray<EventHandlerRef>] = [:]
|
|
||||||
|
|
||||||
private func typeEvent<E: Event>(opaqueEvent: Event, eventHandler: @escaping (E) -> Void ) {
|
|
||||||
guard let typedEvent: E = opaqueEvent as? E else {
|
|
||||||
fatalError() // TODO: meaningful message
|
|
||||||
}
|
|
||||||
eventHandler(typedEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func push(listener newListener: EventHandlerRef, `for` uet: UET) {
|
|
||||||
if listeners[uet] == nil {
|
|
||||||
listeners[uet] = []
|
|
||||||
listeners.reserveCapacity(1)
|
|
||||||
}
|
|
||||||
listeners[uet]?.append(newListener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - event center
|
|
||||||
extension DefaultEventHub {
|
|
||||||
|
|
||||||
final public func subscribe<E: Event>(classRef unownedListenerRef: EventHandler, eventHandler handler: @escaping (E) -> Void) {
|
|
||||||
let eventListener: EventHandlerRef = EventHandlerRef(eventHandlerClassRefUnowned: unownedListenerRef,
|
|
||||||
eventHandler: { self.typeEvent(opaqueEvent: $0, eventHandler: handler) })
|
|
||||||
|
|
||||||
push(listener: eventListener, for: E.uet)
|
|
||||||
sniffer?.subscriber(subsribed: E.uet)
|
|
||||||
}
|
|
||||||
|
|
||||||
final public func unsubscribe<E: Event>(classRef listenerRef: EventHandler, eventHandler handler: @escaping (E) -> Void) {
|
|
||||||
let uet: UET = E.uet
|
|
||||||
|
|
||||||
if let removeIdx: Int = listeners[uet]?.index(is: listenerRef) {
|
|
||||||
let removed = listeners[uet]?.remove(at: removeIdx)
|
|
||||||
assert(removed != nil)
|
|
||||||
sniffer?.subscriber(unsubsribed: uet)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - event dispatcher delegate
|
|
||||||
extension DefaultEventHub {
|
|
||||||
final public func dispatch<E: Event>(_ event: E) {
|
|
||||||
let uet: UET = E.uet
|
|
||||||
listeners[uet]?.forEach {
|
|
||||||
$0.eventHandler(event)
|
|
||||||
}
|
|
||||||
sniffer?.dispatched(event: event)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - event dumper
|
|
||||||
public protocol EventSniffer: class {
|
|
||||||
func subscriber(subsribed to: UET)
|
|
||||||
func subscriber(unsubsribed from: UET)
|
|
||||||
func dispatched<E: Event>(event: E)
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// Created by Christian Treffs on 08.10.17.
|
// Created by Christian Treffs on 08.10.17.
|
||||||
//
|
//
|
||||||
|
protocol Event { }
|
||||||
public struct EntityCreated: Event {
|
public struct EntityCreated: Event {
|
||||||
let entityId: EntityIdentifier
|
let entityId: EntityIdentifier
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,8 @@ extension Family {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func iterate<A, B, C, D, E, F>(_ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?, () -> F?) -> Void) where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
|
public func iterate<A, B, C, D, E, F>(_ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?, () -> F?) -> Void)
|
||||||
|
where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
|
||||||
iterateMembers { (entityId, getEntityInstance) in
|
iterateMembers { (entityId, getEntityInstance) in
|
||||||
func getComponent<Z>() -> Z? where Z: Component {
|
func getComponent<Z>() -> Z? where Z: Component {
|
||||||
return self.nexus.get(component: Z.identifier, for: entityId) as? Z
|
return self.nexus.get(component: Z.identifier, for: entityId) as? Z
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ extension Family {
|
||||||
return nexus.isMember(entity, in: self)
|
return nexus.isMember(entity, in: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final func isMember(_ entityId: EntityIdentifier) -> Bool {
|
||||||
|
return nexus.isMember(entityId, in: self)
|
||||||
|
}
|
||||||
|
|
||||||
internal var members: LazyMapCollection<LazyFilterCollection<LazyMapCollection<EntityIdSet, Entity?>>, Entity> {
|
internal var members: LazyMapCollection<LazyFilterCollection<LazyMapCollection<EntityIdSet, Entity?>>, Entity> {
|
||||||
return nexus.members(of: self)
|
return nexus.members(of: self)
|
||||||
}
|
}
|
||||||
|
|
@ -37,98 +41,3 @@ extension Family {
|
||||||
return nexus.members(of: self)
|
return nexus.members(of: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - member iterator
|
|
||||||
extension Family {
|
|
||||||
/*
|
|
||||||
func makeIterator<A>() -> AnyIterator<(Entity, A)> where A: Component {
|
|
||||||
var members = self.members.makeIterator()
|
|
||||||
return AnyIterator<(Entity, A)> { [unowned self] in
|
|
||||||
let entityId: EntityIdentifier = members.next()!
|
|
||||||
let entity: Entity = self.nexus.get(entity: entityId)!
|
|
||||||
let a: A = entity.get()!
|
|
||||||
return (entity, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeIterator<A, B>() -> AnyIterator<(Entity, A, B)> where A: Component, B: Component {
|
|
||||||
var members = self.members.makeIterator()
|
|
||||||
return AnyIterator<(Entity, A, B)> { [unowned self] in
|
|
||||||
let entityId: EntityIdentifier = members.next()!
|
|
||||||
let entity: Entity = self.nexus.get(entity: entityId)!
|
|
||||||
let a: A = entity.get()!
|
|
||||||
let b: B = entity.get()!
|
|
||||||
return (entity, a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeIterator<A, B, C>() -> AnyIterator<(Entity, A, B, C)> where A: Component, B: Component, C: Component {
|
|
||||||
var members = self.members.makeIterator()
|
|
||||||
return AnyIterator<(Entity, A, B, C)> { [unowned self] in
|
|
||||||
let entityId: EntityIdentifier = members.next()!
|
|
||||||
let entity: Entity = self.nexus.get(entity: entityId)!
|
|
||||||
let a: A = entity.get()!
|
|
||||||
let b: B = entity.get()!
|
|
||||||
let c: C = entity.get()!
|
|
||||||
return (entity, a, b, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// MARK: - Equatable
|
|
||||||
extension Family: Equatable {
|
|
||||||
public static func ==(lhs: Family, rhs: Family) -> Bool {
|
|
||||||
return lhs.traits == rhs.traits
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Hashable
|
|
||||||
extension Family: Hashable {
|
|
||||||
public var hashValue: Int {
|
|
||||||
return traits.hashValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
// MARK: - event dispatcher
|
|
||||||
extension Family: EventDispatcher {
|
|
||||||
public func dispatch<E>(_ event: E) where E: Event {
|
|
||||||
dispatcher.dispatch(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func notifyCreated() {
|
|
||||||
dispatch(FamilyCreated(family: traits))
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func notify(added newEntity: EntityIdentifier) {
|
|
||||||
dispatch(FamilyMemberAdded(member: newEntity, to: traits))
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func notify(removed removedEntity: EntityIdentifier) {
|
|
||||||
dispatch(FamilyMemberRemoved(member: removedEntity, from: traits))
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func notifyDestroyed() {
|
|
||||||
dispatch(FamilyDestroyed(family: traits))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - event handler
|
|
||||||
extension Family: EventHandler {
|
|
||||||
|
|
||||||
fileprivate final func handleComponentAddedToEntity(event: ComponentAdded) {
|
|
||||||
update(membership: event.to)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate final func handleComponentUpdatedAtEntity(event: ComponentUpdated) {
|
|
||||||
update(membership: event.at)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate final func handleComponentRemovedFromEntity(event: ComponentRemoved) {
|
|
||||||
update(membership: event.from)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -70,47 +70,6 @@ extension FamilyTraitSet {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FamilyTraitSet {
|
|
||||||
|
|
||||||
/*/// needs to have all of the given components
|
|
||||||
fileprivate func matches(all entity: Entity) -> Bool {
|
|
||||||
var all = requiresAll
|
|
||||||
while let compId: ComponentIdentifier = all.next() {
|
|
||||||
guard entity.has(compId) else { return false }
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// needs to have none of the given (excluded) components
|
|
||||||
fileprivate func matches(none entity: Entity) -> Bool {
|
|
||||||
var none = excludesAll
|
|
||||||
while let compId: ComponentIdentifier = none.next() {
|
|
||||||
guard !entity.has(compId) else { return false }
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// needs to have at lease one of the given components
|
|
||||||
fileprivate func matches(any entity: Entity) -> Bool {
|
|
||||||
guard !isEmptyAny else { return true }
|
|
||||||
var any = needsAtLeastOne
|
|
||||||
while let compId: ComponentIdentifier = any.next() {
|
|
||||||
if entity.has(compId) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMatch(_ entity: Entity) -> Bool {
|
|
||||||
guard matches(all: entity) else { return false }
|
|
||||||
guard matches(none: entity) else { return false }
|
|
||||||
guard matches(any: entity) else { return false }
|
|
||||||
return true
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Equatable
|
// MARK: - Equatable
|
||||||
extension FamilyTraitSet: Equatable {
|
extension FamilyTraitSet: Equatable {
|
||||||
public static func ==(lhs: FamilyTraitSet, rhs: FamilyTraitSet) -> Bool {
|
public static func ==(lhs: FamilyTraitSet, rhs: FamilyTraitSet) -> Bool {
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
//
|
|
||||||
// Logging.swift
|
|
||||||
// FirebladeECS
|
|
||||||
//
|
|
||||||
// Created by Christian Treffs on 08.10.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
struct Log {
|
|
||||||
|
|
||||||
private init() { }
|
|
||||||
|
|
||||||
enum Level {
|
|
||||||
case info, debug, warn, error
|
|
||||||
|
|
||||||
var toString: String {
|
|
||||||
switch self {
|
|
||||||
case .info: return "INFO"
|
|
||||||
case .debug: return "DEBUG"
|
|
||||||
case .warn: return "WARN"
|
|
||||||
case .error: return "ERROR"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func info(_ args: Any?...) { Log.log(level: .info, args: args) }
|
|
||||||
static func debug(_ args: Any?...) { Log.log(level: .debug, args: args) }
|
|
||||||
static func warn(_ args: Any?...) { Log.log(level: .warn, args: args) }
|
|
||||||
static func error(_ args: Any?...) { Log.log(level: .error, args: args) }
|
|
||||||
|
|
||||||
private static func log(level: Log.Level, args: [Any?]) {
|
|
||||||
let entry: String = Log.serialize(level: level, args: args)
|
|
||||||
Swift.print(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func serialize(level: Log.Level, args: [Any?]) -> String {
|
|
||||||
let argStrings: [String] = args.flatMap { arg in
|
|
||||||
if let arg = arg {
|
|
||||||
return String(describing: arg)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let argString: String = argStrings.joined(separator: " ")
|
|
||||||
let levelString: String = level.toString
|
|
||||||
|
|
||||||
return ["[", levelString, "]\t", argString].joined()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -59,6 +59,12 @@ extension Nexus {
|
||||||
// assign entity / component to index
|
// assign entity / component to index
|
||||||
componentIndexByEntityComponentHash[hash] = newComponentIndex
|
componentIndexByEntityComponentHash[hash] = newComponentIndex
|
||||||
|
|
||||||
|
// FIXME: this is costly for many families
|
||||||
|
let entityId: EntityIdentifier = entity.identifier
|
||||||
|
familiyByTraitHash.forEach { (_, family) in
|
||||||
|
update(membership: family, for: entityId)
|
||||||
|
}
|
||||||
|
|
||||||
notify(ComponentAdded(component: componentId, to: entity.identifier))
|
notify(ComponentAdded(component: componentId, to: entity.identifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,7 +85,6 @@ extension Nexus {
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func get<C>(_ hash: EntityComponentHash) -> C? where C: Component {
|
fileprivate func get<C>(_ hash: EntityComponentHash) -> C? where C: Component {
|
||||||
Log.info("GETTING: \(C.self)")
|
|
||||||
let componentId: ComponentIdentifier = C.identifier
|
let componentId: ComponentIdentifier = C.identifier
|
||||||
guard let componentIdx: ComponentIndex = componentIndexByEntityComponentHash[hash] else { return nil }
|
guard let componentIdx: ComponentIndex = componentIndexByEntityComponentHash[hash] else { return nil }
|
||||||
guard let uniformComponents: UniformComponents = componentsByType[componentId] else { return nil }
|
guard let uniformComponents: UniformComponents = componentsByType[componentId] else { return nil }
|
||||||
|
|
@ -136,6 +141,11 @@ extension Nexus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: this is costly for many families
|
||||||
|
familiyByTraitHash.forEach { (_, family) in
|
||||||
|
update(membership: family, for: entityId)
|
||||||
|
}
|
||||||
|
|
||||||
notify(ComponentRemoved(component: componentId, from: entityId))
|
notify(ComponentRemoved(component: componentId, from: entityId))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,12 @@ extension Nexus {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isMember(_ entity: Entity, in family: Family) -> Bool {
|
public func isMember(_ entity: Entity, in family: Family) -> Bool {
|
||||||
|
return isMember(entity.identifier, in: family)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func isMember(_ entityId: EntityIdentifier, in family: Family) -> Bool {
|
||||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||||
let entityId = entity.identifier
|
// FIXME: this may be costly for many entities in family
|
||||||
return familyMembersByTraitHash[traitHash]?.contains(entityId) ?? false
|
return familyMembersByTraitHash[traitHash]?.contains(entityId) ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,8 +62,13 @@ 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
|
||||||
|
entities.forEach {
|
||||||
|
update(membership: family, for: $0.identifier)
|
||||||
|
}
|
||||||
|
|
||||||
notify(FamilyCreated(family: traits))
|
notify(FamilyCreated(family: traits))
|
||||||
// FIXME: update memberships for prior entites
|
|
||||||
return family
|
return family
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,21 +76,23 @@ extension Nexus {
|
||||||
|
|
||||||
// MARK: - update family membership
|
// MARK: - update family membership
|
||||||
|
|
||||||
func update(membership family: Family, for entity: Entity) {
|
func update(membership family: Family, for entityId: EntityIdentifier) {
|
||||||
let entityIdx: EntityIndex = entity.identifier.index
|
let entityIdx: EntityIndex = entityId.index
|
||||||
guard let componentsSet: ComponentSet = componentIdsSetByEntity[entityIdx] else { return }
|
guard let componentsSet: ComponentSet = componentIdsSetByEntity[entityIdx] else { return }
|
||||||
|
let isMember: Bool = family.isMember(entityId)
|
||||||
let isMatch: Bool = family.traits.isMatch(components: componentsSet)
|
let isMatch: Bool = family.traits.isMatch(components: componentsSet)
|
||||||
switch isMatch {
|
switch (isMatch, isMember) {
|
||||||
case true:
|
case (true, false):
|
||||||
add(to: family, entity: entity)
|
add(to: family, entityId: entityId)
|
||||||
case false:
|
case (false, true):
|
||||||
remove(from: family, entity: entity)
|
remove(from: family, entityId: entityId)
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func add(to family: Family, entity: Entity) {
|
fileprivate func add(to family: Family, entityId: EntityIdentifier) {
|
||||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||||
let entityId: EntityIdentifier = entity.identifier
|
|
||||||
if familyMembersByTraitHash[traitHash] != nil {
|
if familyMembersByTraitHash[traitHash] != nil {
|
||||||
let (inserted, _) = familyMembersByTraitHash[traitHash]!.insert(entityId)
|
let (inserted, _) = familyMembersByTraitHash[traitHash]!.insert(entityId)
|
||||||
assert(inserted, "entity with id \(entityId) already in family")
|
assert(inserted, "entity with id \(entityId) already in family")
|
||||||
|
|
@ -93,9 +104,8 @@ extension Nexus {
|
||||||
notify(FamilyMemberAdded(member: entityId, to: family.traits))
|
notify(FamilyMemberAdded(member: entityId, to: family.traits))
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func remove(from family: Family, entity: Entity) {
|
fileprivate func remove(from family: Family, entityId: EntityIdentifier) {
|
||||||
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
let traitHash: FamilyTraitSetHash = family.traits.hashValue
|
||||||
let entityId: EntityIdentifier = entity.identifier
|
|
||||||
|
|
||||||
guard let removed = familyMembersByTraitHash[traitHash]?.remove(entityId) else {
|
guard let removed = familyMembersByTraitHash[traitHash]?.remove(entityId) else {
|
||||||
assert(false, "removing entity id \(entityId) that is not in family \(family)")
|
assert(false, "removing entity id \(entityId) that is not in family \(family)")
|
||||||
|
|
|
||||||
|
|
@ -69,32 +69,10 @@ extension Nexus {
|
||||||
func notify(_ event: Event) {
|
func notify(_ event: Event) {
|
||||||
//Log.debug(event)
|
//Log.debug(event)
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func report(_ message: String) {
|
func report(_ message: String) {
|
||||||
Log.warn(message)
|
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// MARK: - event handler
|
|
||||||
extension Nexus {
|
|
||||||
func handleEntityCreated(_ e: EntityCreated) { print(e) }
|
|
||||||
func handleEntityDestroyed(_ e: EntityDestroyed) { print(e) }
|
|
||||||
|
|
||||||
func handleComponentAdded(_ e: ComponentAdded) { print(e) }
|
|
||||||
func handleComponentUpdated(_ e: ComponentUpdated) { print(e) }
|
|
||||||
func handleComponentRemoved(_ e: ComponentRemoved) { print(e) }
|
|
||||||
|
|
||||||
func handleFamilyCreated(_ e: FamilyCreated) {
|
|
||||||
print(e)
|
|
||||||
let newFamily: Family = e.family
|
|
||||||
onFamilyCreated(newFamily)
|
|
||||||
|
|
||||||
}
|
|
||||||
func handleFamilyMemberAdded(_ e: FamilyMemberAdded) { print(e) }
|
|
||||||
func handleFamilyMemberRemoved(_ e: FamilyMemberRemoved) { print(e) }
|
|
||||||
func handleFamilyDestroyed(_ e: FamilyDestroyed) { print(e) }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
//
|
|
||||||
// System.swift
|
|
||||||
// FirebladeECS
|
|
||||||
//
|
|
||||||
// Created by Christian Treffs on 08.10.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
public enum SystemState {
|
|
||||||
case running, paused, inactive
|
|
||||||
}
|
|
||||||
|
|
||||||
public protocol System: class {
|
|
||||||
//var state: SystemState { set get }
|
|
||||||
func startup()
|
|
||||||
func shutdown()
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
//
|
|
||||||
// UET.swift
|
|
||||||
// FirebladeECS
|
|
||||||
//
|
|
||||||
// Created by Christian Treffs on 09.10.17.
|
|
||||||
//
|
|
||||||
|
|
||||||
// MARK: Unique Event Type
|
|
||||||
/// Unique Event Type
|
|
||||||
public struct UET {
|
|
||||||
let objectIdentifier: ObjectIdentifier
|
|
||||||
let type: Event.Type
|
|
||||||
|
|
||||||
init(_ eventType: Event.Type) {
|
|
||||||
objectIdentifier = ObjectIdentifier(eventType)
|
|
||||||
type = eventType
|
|
||||||
}
|
|
||||||
|
|
||||||
init(_ event: Event) {
|
|
||||||
let eventType: Event.Type = event.uet.type
|
|
||||||
self.init(eventType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UET: Equatable {
|
|
||||||
public static func ==(lhs: UET, rhs: UET) -> Bool {
|
|
||||||
return lhs.objectIdentifier == rhs.objectIdentifier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UET: Hashable {
|
|
||||||
public var hashValue: Int {
|
|
||||||
return objectIdentifier.hashValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Unique Event Identifiable
|
|
||||||
public protocol UniqueEventIdentifiable {
|
|
||||||
static var uet: UET { get }
|
|
||||||
var uet: UET { get }
|
|
||||||
}
|
|
||||||
|
|
@ -67,14 +67,11 @@ class FamilyTests: XCTestCase {
|
||||||
|
|
||||||
let nexus = Nexus()
|
let nexus = Nexus()
|
||||||
|
|
||||||
let a = nexus.create(entity: "a").assign(Position(x: 1, y: 2), Name(name: "myName"), Velocity(a: 3.14), EmptyComponent())
|
nexus.create(entity: "a").assign(Position(x: 1, y: 2), Name(name: "myName"), Velocity(a: 3.14), EmptyComponent())
|
||||||
let b = nexus.create(entity: "b").assign(Position(x: 3, y: 4), Velocity(a: 5.23), EmptyComponent())
|
nexus.create(entity: "b").assign(Position(x: 3, y: 4), Velocity(a: 5.23), EmptyComponent())
|
||||||
|
|
||||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||||
|
|
||||||
nexus.update(membership: family, for: a)
|
|
||||||
nexus.update(membership: family, for: b)
|
|
||||||
|
|
||||||
var index: Int = 0
|
var index: Int = 0
|
||||||
|
|
||||||
family.iterate { (e: () -> Entity, p: () -> Position!, v: () -> Velocity!, n: () -> Name?) in
|
family.iterate { (e: () -> Entity, p: () -> Position!, v: () -> Velocity!, n: () -> Name?) in
|
||||||
|
|
@ -122,8 +119,6 @@ class FamilyTests: XCTestCase {
|
||||||
|
|
||||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||||
|
|
||||||
nexus.entities.forEach { nexus.update(membership: family, for: $0) }
|
|
||||||
|
|
||||||
XCTAssert(family.members.count == number)
|
XCTAssert(family.members.count == number)
|
||||||
XCTAssert(family.memberIds.count == number)
|
XCTAssert(family.memberIds.count == number)
|
||||||
XCTAssert(nexus.entities.count == number)
|
XCTAssert(nexus.entities.count == number)
|
||||||
|
|
@ -152,8 +147,6 @@ class FamilyTests: XCTestCase {
|
||||||
|
|
||||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||||
|
|
||||||
nexus.entities.forEach { nexus.update(membership: family, for: $0) }
|
|
||||||
|
|
||||||
XCTAssert(family.members.count == number)
|
XCTAssert(family.members.count == number)
|
||||||
XCTAssert(family.memberIds.count == number)
|
XCTAssert(family.memberIds.count == number)
|
||||||
XCTAssert(nexus.entities.count == number)
|
XCTAssert(nexus.entities.count == number)
|
||||||
|
|
@ -182,8 +175,6 @@ class FamilyTests: XCTestCase {
|
||||||
|
|
||||||
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
let family = nexus.family(requiresAll: [Position.self, Velocity.self], excludesAll: [Party.self], needsAtLeastOne: [Name.self, EmptyComponent.self])
|
||||||
|
|
||||||
nexus.entities.forEach { nexus.update(membership: family, for: $0) }
|
|
||||||
|
|
||||||
measure {
|
measure {
|
||||||
family.memberIds.forEach { (e) in
|
family.memberIds.forEach { (e) in
|
||||||
_ = e
|
_ = e
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue