Merge pull request #34 from fireblade-engine/feature/entity-advancements

Entity advancements
This commit is contained in:
Christian Treffs 2020-10-19 17:46:56 +02:00 committed by GitHub
commit a60c6304fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 200 additions and 114 deletions

View File

@ -8,12 +8,12 @@
extension Entity { extension Entity {
@inlinable @inlinable
public func get<C>() -> C? where C: Component { public func get<C>() -> C? where C: Component {
nexus.get(for: identifier) nexus.get(safe: identifier)
} }
@inlinable @inlinable
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 {
nexus.get(for: identifier) nexus.get(safe: identifier)
} }
@inlinable @inlinable
@ -32,22 +32,73 @@ extension Entity {
return (compA, compB, compC) return (compA, compB, compC)
} }
/// Get or set component instance by type via subscript.
///
/// **Behavior:**
/// - If `Comp` is a component type that is currently *not* assigned to this entity,
/// the new instance will be assigned to this entity.
/// - If `Comp` is already assinged to this entity nothing happens.
/// - If `Comp` is set to `nil` and an instance of `Comp` is assigned to this entity,
/// `Comp` will be removed from this entity.
@inlinable @inlinable
public subscript<C: Component, Value>(_ componentKeyPath: WritableKeyPath<C, Value>) -> Value? { public subscript<Comp>(_ componentType: Comp.Type) -> Comp? where Comp: Component {
get { self.get(component: componentType) }
nonmutating set { nonmutating set {
guard var comp = self.get(component: C.self), guard let newComponent = newValue else {
let value = newValue else { self.remove(Comp.self)
return return
} }
comp[keyPath: componentKeyPath] = value if self.get(component: componentType) === newComponent {
} return
get { }
self.get(component: C.self)?[keyPath: componentKeyPath] self.assign(newComponent)
} }
} }
/// Get the value of a component using the key Path to the property in the component.
/// - Parameter componentKeyPath: The `KeyPath` to the property of the given component.
@inlinable @inlinable
public subscript<C: Component>(_ componentType: C.Type) -> C? { public func get<Comp, Value>(valueAt componentKeyPath: KeyPath<Comp, Value>) -> Value where Comp: Component {
self.get(component: componentType) self.get(component: Comp.self)![keyPath: componentKeyPath]
}
/// Get the value of a component using the key Path to the property in the component.
@inlinable
public subscript<Comp, Value>(_ componentKeyPath: KeyPath<Comp, Value>) -> Value where Comp: Component {
self.get(valueAt: componentKeyPath)
}
/// Set the value of a component using the key path to the property in the component.
///
/// **Behavior:**
/// - If `Comp` is a component type that is currently *not* assigned to this entity,
/// a new instance of `Comp` will be default initialized and `newValue` will be set at the given keyPath.
///
/// - Parameters:
/// - newValue: The value to set.
/// - componentKeyPath: The `ReferenceWritableKeyPath` to the property of the given component.
/// - Returns: Returns true if an action was performed, false otherwise.
@inlinable
@discardableResult
public func set<Comp, Value>(value newValue: Value, for componentKeyPath: ReferenceWritableKeyPath<Comp, Value>) -> Bool where Comp: Component & DefaultInitializable {
guard has(Comp.self) else {
let newInstance = Comp()
newInstance[keyPath: componentKeyPath] = newValue
return nexus.assign(component: newInstance, entityId: identifier)
}
get(component: Comp.self)![keyPath: componentKeyPath] = newValue
return true
}
/// Set the value of a component using the key path to the property in the component.
///
/// **Behavior:**
/// - If `Comp` is a component type that is currently *not* assigned to this entity,
/// a new instance of `Comp` will be default initialized and `newValue` will be set at the given keyPath.
@inlinable
public subscript<Comp, Value>(_ componentKeyPath: ReferenceWritableKeyPath<Comp, Value>) -> Value where Comp: Component & DefaultInitializable {
get { self.get(valueAt: componentKeyPath) }
nonmutating set { self.set(value: newValue, for: componentKeyPath) }
} }
} }

View File

@ -122,7 +122,7 @@ extension Entity {
@usableFromInline @usableFromInline
init(nexus: Nexus, entityIdentifier: EntityIdentifier) { init(nexus: Nexus, entityIdentifier: EntityIdentifier) {
if let comps = nexus.get(components: entityIdentifier) { if let comps = nexus.get(components: entityIdentifier) {
iterator = AnyIterator<Component>(comps.compactMap { nexus.get(component: $0, for: entityIdentifier) }.makeIterator()) iterator = AnyIterator<Component>(comps.compactMap { nexus.get(unsafe: $0, for: entityIdentifier) }.makeIterator())
} else { } else {
iterator = AnyIterator { nil } iterator = AnyIterator { nil }
} }
@ -133,6 +133,7 @@ extension Entity {
} }
} }
} }
extension Entity.ComponentsIterator: LazySequenceProtocol { }
extension Entity.ComponentsIterator: Sequence { } extension Entity.ComponentsIterator: Sequence { }
extension Entity: Equatable { extension Entity: Equatable {

View File

@ -94,6 +94,7 @@ extension Family {
} }
extension Family.ComponentsIterator: LazySequenceProtocol { } extension Family.ComponentsIterator: LazySequenceProtocol { }
extension Family.ComponentsIterator: Sequence { }
// MARK: - entity iterator // MARK: - entity iterator
extension Family { extension Family {
@ -120,6 +121,7 @@ extension Family {
} }
extension Family.EntityIterator: LazySequenceProtocol { } extension Family.EntityIterator: LazySequenceProtocol { }
extension Family.EntityIterator: Sequence { }
// MARK: - entity component iterator // MARK: - entity component iterator
extension Family { extension Family {
@ -146,6 +148,7 @@ extension Family {
} }
extension Family.EntityComponentIterator: LazySequenceProtocol { } extension Family.EntityComponentIterator: LazySequenceProtocol { }
extension Family.EntityComponentIterator: Sequence { }
// MARK: - member creation // MARK: - member creation
extension Family { extension Family {

View File

@ -23,13 +23,13 @@ public struct Requires1<Comp1>: FamilyRequirementsManaging where Comp1: Componen
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
return (comp1) return (comp1)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
return (entity, comp1) return (entity, comp1)
} }
@ -116,15 +116,15 @@ public struct Requires2<Comp1, Comp2>: FamilyRequirementsManaging where Comp1: C
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
return (comp1, comp2) return (comp1, comp2)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2) return (entity, comp1, comp2)
} }
@ -215,17 +215,17 @@ public struct Requires3<Comp1, Comp2, Comp3>: FamilyRequirementsManaging where C
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
return (comp1, comp2, comp3) return (comp1, comp2, comp3)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2, comp3) return (entity, comp1, comp2, comp3)
} }
@ -320,19 +320,19 @@ public struct Requires4<Comp1, Comp2, Comp3, Comp4>: FamilyRequirementsManaging
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
return (comp1, comp2, comp3, comp4) return (comp1, comp2, comp3, comp4)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2, comp3, comp4) return (entity, comp1, comp2, comp3, comp4)
} }
@ -431,21 +431,21 @@ public struct Requires5<Comp1, Comp2, Comp3, Comp4, Comp5>: FamilyRequirementsMa
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
return (comp1, comp2, comp3, comp4, comp5) return (comp1, comp2, comp3, comp4, comp5)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5) return (entity, comp1, comp2, comp3, comp4, comp5)
} }
@ -548,23 +548,23 @@ public struct Requires6<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6>: FamilyRequire
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) let comp6: Comp6 = nexus.get(unsafe: entityId)
return (comp1, comp2, comp3, comp4, comp5, comp6) return (comp1, comp2, comp3, comp4, comp5, comp6)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) let comp6: Comp6 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5, comp6) return (entity, comp1, comp2, comp3, comp4, comp5, comp6)
} }
@ -671,25 +671,25 @@ public struct Requires7<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7>: Family
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) let comp6: Comp6 = nexus.get(unsafe: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) let comp7: Comp7 = nexus.get(unsafe: entityId)
return (comp1, comp2, comp3, comp4, comp5, comp6, comp7) return (comp1, comp2, comp3, comp4, comp5, comp6, comp7)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) let comp6: Comp6 = nexus.get(unsafe: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) let comp7: Comp7 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7) return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7)
} }
@ -800,27 +800,27 @@ public struct Requires8<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8>:
} }
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) let comp6: Comp6 = nexus.get(unsafe: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) let comp7: Comp7 = nexus.get(unsafe: entityId)
let comp8: Comp8 = nexus.get(unsafeComponentFor: entityId) let comp8: Comp8 = nexus.get(unsafe: entityId)
return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8)
} }
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) {
let entity = Entity(nexus: nexus, id: entityId) let entity = Entity(nexus: nexus, id: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) let comp4: Comp4 = nexus.get(unsafe: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) let comp5: Comp5 = nexus.get(unsafe: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) let comp6: Comp6 = nexus.get(unsafe: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) let comp7: Comp7 = nexus.get(unsafe: entityId)
let comp8: Comp8 = nexus.get(unsafeComponentFor: entityId) let comp8: Comp8 = nexus.get(unsafe: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8)
} }

View File

@ -21,39 +21,45 @@ extension Nexus {
componentIdsByEntity[entityId]?.count ?? 0 componentIdsByEntity[entityId]?.count ?? 0
} }
public final func assign(component: Component, to entity: Entity) { @discardableResult
public final func assign(component: Component, to entity: Entity) -> Bool {
let entityId: EntityIdentifier = entity.identifier let entityId: EntityIdentifier = entity.identifier
assign(component: component, entityId: entityId) defer { delegate?.nexusEvent(ComponentAdded(component: component.identifier, toEntity: entity.identifier)) }
delegate?.nexusEvent(ComponentAdded(component: component.identifier, toEntity: entity.identifier)) return assign(component: component, entityId: entityId)
} }
public final func assign<C>(component: C, to entity: Entity) where C: Component { @discardableResult
public final func assign<C>(component: C, to entity: Entity) -> Bool where C: Component {
assign(component: component, to: entity) assign(component: component, to: entity)
} }
@inlinable @inlinable
public final func get(component componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component? { public final func get(safe componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component? {
guard let uniformComponents = componentsByType[componentId] else { guard let uniformComponents = componentsByType[componentId], uniformComponents.contains(entityId.index) else {
return nil return nil
} }
return uniformComponents.get(at: entityId.index) return uniformComponents.get(at: entityId.index)
} }
@inlinable @inlinable
public final func get(unsafeComponent componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component { public final func get(unsafe componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component {
let uniformComponents = componentsByType[componentId].unsafelyUnwrapped let uniformComponents = componentsByType[componentId].unsafelyUnwrapped
return uniformComponents.get(unsafeAt: entityId.index) return uniformComponents.get(unsafeAt: entityId.index)
} }
@inlinable @inlinable
public final func get<C>(for entityId: EntityIdentifier) -> C? where C: Component { public final func get<C>(safe componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> C? where C: Component {
let componentId: ComponentIdentifier = C.identifier get(safe: componentId, for: entityId) as? C
return get(componentId: componentId, entityId: entityId)
} }
@inlinable @inlinable
public final func get<C>(unsafeComponentFor entityId: EntityIdentifier) -> C where C: Component { public final func get<C>(safe entityId: EntityIdentifier) -> C? where C: Component {
let component: Component = get(unsafeComponent: C.identifier, for: entityId) get(safe: C.identifier, for: entityId)
}
@inlinable
public final func get<C>(unsafe entityId: EntityIdentifier) -> C where C: Component {
let component: Component = get(unsafe: C.identifier, for: entityId)
// components are guaranteed to be reference types so unsafeDowncast is applicable here // components are guaranteed to be reference types so unsafeDowncast is applicable here
return unsafeDowncast(component, to: C.self) return unsafeDowncast(component, to: C.self)
} }
@ -89,12 +95,4 @@ extension Nexus {
} }
return removedAll return removedAll
} }
@inlinable
public final func get<C>(componentId: ComponentIdentifier, entityId: EntityIdentifier) -> C? where C: Component {
guard let uniformComponents = componentsByType[componentId] else {
return nil
}
return uniformComponents.get(at: entityId.index) as? C
}
} }

View File

@ -96,4 +96,5 @@ extension Nexus {
} }
} }
} }
extension Nexus.EntitiesIterator: LazySequenceProtocol { }
extension Nexus.EntitiesIterator: Sequence { } extension Nexus.EntitiesIterator: Sequence { }

View File

@ -6,6 +6,7 @@
// //
extension Nexus { extension Nexus {
@usableFromInline
func assign<C>(components: C, to entityId: EntityIdentifier) where C: Collection, C.Element == Component { func assign<C>(components: C, to entityId: EntityIdentifier) where C: Collection, C.Element == Component {
var iter = components.makeIterator() var iter = components.makeIterator()
while let component = iter.next() { while let component = iter.next() {
@ -28,14 +29,15 @@ extension Nexus {
update(familyMembership: entityId) update(familyMembership: entityId)
} }
func assign(component: Component, entityId: EntityIdentifier) { @usableFromInline
func assign(component: Component, entityId: EntityIdentifier) -> Bool {
let componentId = component.identifier let componentId = component.identifier
// test if component is already assigned // test if component is already assigned
guard !has(componentId: componentId, entityId: entityId) else { guard !has(componentId: componentId, entityId: entityId) else {
delegate?.nexusNonFatalError("ComponentAdd collision: \(entityId) already has a component \(component)") delegate?.nexusNonFatalError("ComponentAdd collision: \(entityId) already has a component \(component)")
assertionFailure("ComponentAdd collision: \(entityId) already has a component \(component)") assertionFailure("ComponentAdd collision: \(entityId) already has a component \(component)")
return return false
} }
// add component instances to uniform component stores // add component instances to uniform component stores
@ -46,8 +48,10 @@ extension Nexus {
// Update entity membership // Update entity membership
update(familyMembership: entityId) update(familyMembership: entityId)
return true
} }
@usableFromInline
func insertComponentInstance(_ component: Component, _ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) { func insertComponentInstance(_ component: Component, _ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) {
if componentsByType[componentId] == nil { if componentsByType[componentId] == nil {
componentsByType[componentId] = ManagedContiguousArray<Component>() componentsByType[componentId] = ManagedContiguousArray<Component>()
@ -55,10 +59,12 @@ extension Nexus {
componentsByType[componentId]?.insert(component, at: entityId.index) componentsByType[componentId]?.insert(component, at: entityId.index)
} }
@usableFromInline
func assign(_ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) { func assign(_ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) {
componentIdsByEntity[entityId]!.insert(componentId) componentIdsByEntity[entityId]!.insert(componentId)
} }
@usableFromInline
func update(familyMembership entityId: EntityIdentifier) { func update(familyMembership entityId: EntityIdentifier) {
// FIXME: iterating all families is costly for many families // FIXME: iterating all families is costly for many families
// FIXME: this could be parallelized // FIXME: this could be parallelized

View File

@ -28,7 +28,7 @@ extension Single where A: SingleComponent {
// Since we guarantee that the component will always be present by managing the complete lifecycle of the entity // Since we guarantee that the component will always be present by managing the complete lifecycle of the entity
// and component assignment we may unsafelyUnwrap here. // and component assignment we may unsafelyUnwrap here.
// Since components will always be of reference type (class) we may use unsafeDowncast here for performance reasons. // Since components will always be of reference type (class) we may use unsafeDowncast here for performance reasons.
nexus.get(unsafeComponentFor: entityId) nexus.get(unsafe: entityId)
} }
public var entity: Entity { public var entity: Entity {

View File

@ -46,7 +46,7 @@ public struct Requires{{ idx }}<{{ CompParams }}>: FamilyRequirementsManaging wh
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> ({{ CompParams }}) { public static func components(nexus: Nexus, entityId: EntityIdentifier) -> ({{ CompParams }}) {
{% for comp in components %} {% for comp in components %}
let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: entityId) let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafe: entityId)
{% endfor %} {% endfor %}
return ({{ CompsLowercased }}) return ({{ CompsLowercased }})
} }
@ -54,7 +54,7 @@ public struct Requires{{ idx }}<{{ CompParams }}>: FamilyRequirementsManaging wh
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, {{ CompParams }}) { public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, {{ CompParams }}) {
let entity: Entity = Entity(nexus: nexus, id: entityId) let entity: Entity = Entity(nexus: nexus, id: entityId)
{% for comp in components %} {% for comp in components %}
let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: entityId) let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafe: entityId)
{% endfor %} {% endfor %}
return (entity, {{ CompsLowercased }}) return (entity, {{ CompsLowercased }})
} }

View File

@ -226,6 +226,8 @@ extension UnorderedSparseSet: Sequence {
} }
} }
} }
extension UnorderedSparseSet.ElementIterator: LazySequenceProtocol { }
extension UnorderedSparseSet.ElementIterator: Sequence { }
// MARK: - Equatable // MARK: - Equatable
extension UnorderedSparseSet.Storage.Entry: Equatable where Element: Equatable { } extension UnorderedSparseSet.Storage.Entry: Equatable where Element: Equatable { }

View File

@ -10,17 +10,25 @@ import FirebladeECS
class EmptyComponent: Component { class EmptyComponent: Component {
} }
class Name: Component { final class Name: Component, DefaultInitializable {
var name: String var name: String
init(name: String) { init(name: String) {
self.name = name self.name = name
} }
convenience init() {
self.init(name: "")
}
} }
final class Position: Component { final class Position: Component, DefaultInitializable {
var x: Int var x: Int
var y: Int var y: Int
convenience init() {
self.init(x: 0, y: 0)
}
init(x: Int, y: Int) { init(x: Int, y: Int) {
self.x = x self.x = x
self.y = y self.y = y
@ -28,11 +36,16 @@ final class Position: Component {
} }
extension Position: Codable { } extension Position: Codable { }
class Velocity: Component { final class Velocity: Component, DefaultInitializable {
var a: Float var a: Float
init(a: Float) { init(a: Float) {
self.a = a self.a = a
} }
convenience init() {
self.init(a: 0)
}
} }
final class Party: Component { final class Party: Component {

View File

@ -101,11 +101,22 @@ class EntityTests: XCTestCase {
XCTAssertEqual(entity[\Name.name], "AnotherName") XCTAssertEqual(entity[\Name.name], "AnotherName")
entity[\Velocity.a] = 123 entity[\Velocity.a] = 123
XCTAssertNil(entity[\Velocity.a]) XCTAssertEqual(entity[\Velocity.a], 123.0)
entity[Position.self]?.x = 1234 entity[Position.self]?.x = 1234
XCTAssertEqual(entity[Position.self]?.x, 1234) XCTAssertEqual(entity[Position.self]?.x, 1234)
XCTAssertNil(entity[Velocity.self]?.a) XCTAssertEqual(entity[Velocity.self]?.a, 123.0)
// remove position component
entity[Position.self] = nil
XCTAssertNil(entity[Position.self])
entity[Position.self] = pos // assign position comp instance
XCTAssertTrue(entity[Position.self] === pos)
entity[Position.self] = pos // re-assign
XCTAssertTrue(entity[Position.self] === pos)
entity[Position.self] = nil // remove position component
XCTAssertNil(entity[Position.self])
} }
} }