Merge branch 'feature/codegen' into develop

This commit is contained in:
Christian Treffs 2020-08-06 11:10:36 +02:00
commit 32b2ab946b
No known key found for this signature in database
GPG Key ID: 49A4B4B460BE3ED4
15 changed files with 2676 additions and 396 deletions

6
.sourcery.yml Normal file
View File

@ -0,0 +1,6 @@
sources: # you can provide either single path or several paths using `-`
- Sources
templates: # as well as for templates
- Sources/FirebladeECS/Stencils
output: # note that there is no `-` here as only single output path is supported
Sources/FirebladeECS/Generated

6
.sourceryTests.yml Normal file
View File

@ -0,0 +1,6 @@
sources: # you can provide either single path or several paths using `-`
- Sources
templates: # as well as for templates
- Tests/FirebladeECSTests/Stencils
output: # note that there is no `-` here as only single output path is supported
Tests/FirebladeECSTests/Generated

View File

@ -11,7 +11,7 @@ lintErrorOnly:
@swiftlint lint --quiet | grep error
# Git
precommit: lint genLinuxTests
precommit: generateCode generateTestsCode lint genLinuxTests
submodule:
git submodule init
@ -53,4 +53,15 @@ cleanArtifacts:
# Test links in README
# requires <https://github.com/tcort/markdown-link-check>
testReadme:
markdown-link-check -p -v ./README.md
markdown-link-check -p -v ./README.md
setupEnvironment:
brew update
brew install swiftenv
brew install swiftlint
brew install sourcery
generateCode:
sourcery --config ./.sourcery.yml --verbose
generateTestsCode:
sourcery --config ./.sourceryTests.yml --verbose

View File

@ -1,60 +0,0 @@
//
// Family1.swift
//
//
// Created by Christian Treffs on 21.08.19.
//
public typealias Family1<A: Component> = Family<Requires1<A>>
public struct Requires1<A>: FamilyRequirementsManaging where A: Component {
public let componentTypes: [Component.Type]
public init(_ components: A.Type) {
componentTypes = [A.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> A {
let compA: A = nexus.get(unsafeComponentFor: entityId)
return (compA)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let compA: A = nexus.get(unsafeComponentFor: entityId)
return (entity, compA)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: A, child: A) {
let parentCompA: A = nexus.get(unsafeComponentFor: parentId)
let childCompA: A = nexus.get(unsafeComponentFor: childId)
return (parent: parentCompA, child: childCompA)
}
public static func createMember(nexus: Nexus, components: A) -> Entity {
nexus.createEntity(with: components)
}
}
extension Requires1: FamilyDecoding where A: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> A {
try container.decode(A.self, forKey: strategy.codingKey(for: A.self))
}
}
extension Requires1: FamilyEncoding where A: Encodable {
public static func encode(components: Components, into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components, forKey: strategy.codingKey(for: A.self))
}
}
extension Nexus {
public func family<A>(
requires componentA: A.Type,
excludesAll excludedComponents: Component.Type...
) -> Family1<A> where A: Component {
Family1<A>(nexus: self,
requiresAll: componentA,
excludesAll: excludedComponents)
}
}

View File

@ -1,72 +0,0 @@
//
// Family2.swift
//
//
// Created by Christian Treffs on 21.08.19.
//
// swiftlint:disable large_tuple
public typealias Family2<A: Component, B: Component> = Family<Requires2<A, B>>
public struct Requires2<A, B>: FamilyRequirementsManaging where A: Component, B: Component {
public let componentTypes: [Component.Type]
public init(_ components: (A.Type, B.Type)) {
componentTypes = [ A.self, B.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B) {
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
return (compA, compB)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
return (entity, compA, compB)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (A, B), child: (A, B)) {
let pcA: A = nexus.get(unsafeComponentFor: parentId)
let pcB: B = nexus.get(unsafeComponentFor: parentId)
let ccA: A = nexus.get(unsafeComponentFor: childId)
let ccB: B = nexus.get(unsafeComponentFor: childId)
return (parent: (pcA, pcB), child: (ccA, ccB))
}
public static func createMember(nexus: Nexus, components: (A, B)) -> Entity {
nexus.createEntity(with: components.0, components.1)
}
}
extension Requires2: FamilyEncoding where A: Encodable, B: Encodable {
public static func encode(components: (A, B), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: A.self))
try container.encode(components.1, forKey: strategy.codingKey(for: B.self))
}
}
extension Requires2: FamilyDecoding where A: Decodable, B: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (A, B) {
let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self))
let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self))
return Components(compA, compB)
}
}
extension Nexus {
public func family<A, B>(
requiresAll componentA: A.Type,
_ componentB: B.Type,
excludesAll excludedComponents: Component.Type...
) -> Family2<A, B> where A: Component, B: Component {
Family2<A, B>(
nexus: self,
requiresAll: (componentA, componentB),
excludesAll: excludedComponents
)
}
}

View File

@ -1,79 +0,0 @@
//
// Family3.swift
//
//
// Created by Christian Treffs on 21.08.19.
//
// swiftlint:disable large_tuple
public typealias Family3<A: Component, B: Component, C: Component> = Family<Requires3<A, B, C>>
public struct Requires3<A, B, C>: FamilyRequirementsManaging where A: Component, B: Component, C: Component {
public let componentTypes: [Component.Type]
public init(_ types: (A.Type, B.Type, C.Type)) {
componentTypes = [A.self, B.self, C.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B, C) {
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
let compC: C = nexus.get(unsafeComponentFor: entityId)
return (compA, compB, compC)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B, C) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
let compC: C = nexus.get(unsafeComponentFor: entityId)
return (entity, compA, compB, compC)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) ->
(parent: (A, B, C), child: (A, B, C)) {
let pcA: A = nexus.get(unsafeComponentFor: parentId)
let pcB: B = nexus.get(unsafeComponentFor: parentId)
let pcC: C = nexus.get(unsafeComponentFor: parentId)
let ccA: A = nexus.get(unsafeComponentFor: childId)
let ccB: B = nexus.get(unsafeComponentFor: childId)
let ccC: C = nexus.get(unsafeComponentFor: childId)
return (parent: (pcA, pcB, pcC), child: (ccA, ccB, ccC))
}
public static func createMember(nexus: Nexus, components: (A, B, C)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2)
}
}
extension Requires3: FamilyEncoding where A: Encodable, B: Encodable, C: Encodable {
public static func encode(components: (A, B, C), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: A.self))
try container.encode(components.1, forKey: strategy.codingKey(for: B.self))
try container.encode(components.2, forKey: strategy.codingKey(for: C.self))
}
}
extension Requires3: FamilyDecoding where A: Decodable, B: Decodable, C: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (A, B, C) {
let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self))
let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self))
let compC = try container.decode(C.self, forKey: strategy.codingKey(for: C.self))
return Components(compA, compB, compC)
}
}
extension Nexus {
public func family<A, B, C>(
requiresAll componentA: A.Type,
_ componentB: B.Type,
_ componentC: C.Type,
excludesAll excludedComponents: Component.Type...
) -> Family3<A, B, C> where A: Component, B: Component, C: Component {
Family3(
nexus: self,
requiresAll: (componentA, componentB, componentC),
excludesAll: excludedComponents
)
}
}

View File

@ -1,87 +0,0 @@
//
// Family4.swift
//
//
// Created by Christian Treffs on 21.08.19.
//
// swiftlint:disable large_tuple
public typealias Family4<A: Component, B: Component, C: Component, D: Component> = Family<Requires4<A, B, C, D>>
public struct Requires4<A, B, C, D>: FamilyRequirementsManaging where A: Component, B: Component, C: Component, D: Component {
public let componentTypes: [Component.Type]
public init(_ types: (A.Type, B.Type, C.Type, D.Type)) {
componentTypes = [A.self, B.self, C.self, D.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B, C, D) {
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
let compC: C = nexus.get(unsafeComponentFor: entityId)
let compD: D = nexus.get(unsafeComponentFor: entityId)
return (compA, compB, compC, compD)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B, C, D) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
let compC: C = nexus.get(unsafeComponentFor: entityId)
let compD: D = nexus.get(unsafeComponentFor: entityId)
return (entity, compA, compB, compC, compD)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) ->
(parent: (A, B, C, D), child: (A, B, C, D)) {
let pcA: A = nexus.get(unsafeComponentFor: parentId)
let pcB: B = nexus.get(unsafeComponentFor: parentId)
let pcC: C = nexus.get(unsafeComponentFor: parentId)
let pcD: D = nexus.get(unsafeComponentFor: parentId)
let ccA: A = nexus.get(unsafeComponentFor: childId)
let ccB: B = nexus.get(unsafeComponentFor: childId)
let ccC: C = nexus.get(unsafeComponentFor: childId)
let ccD: D = nexus.get(unsafeComponentFor: childId)
return (parent: (pcA, pcB, pcC, pcD), child: (ccA, ccB, ccC, ccD))
}
public static func createMember(nexus: Nexus, components: (A, B, C, D)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3)
}
}
extension Requires4: FamilyEncoding where A: Encodable, B: Encodable, C: Encodable, D: Encodable {
public static func encode(components: (A, B, C, D), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: A.self))
try container.encode(components.1, forKey: strategy.codingKey(for: B.self))
try container.encode(components.2, forKey: strategy.codingKey(for: C.self))
try container.encode(components.3, forKey: strategy.codingKey(for: D.self))
}
}
extension Requires4: FamilyDecoding where A: Decodable, B: Decodable, C: Decodable, D: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (A, B, C, D) {
let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self))
let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self))
let compC = try container.decode(C.self, forKey: strategy.codingKey(for: C.self))
let compD = try container.decode(D.self, forKey: strategy.codingKey(for: D.self))
return Components(compA, compB, compC, compD)
}
}
extension Nexus {
public func family<A, B, C, D>(
requiresAll componentA: A.Type,
_ componentB: B.Type,
_ componentC: C.Type,
_ componentD: D.Type,
excludesAll excludedComponents: Component.Type...
) -> Family4<A, B, C, D> where A: Component, B: Component, C: Component, D: Component {
Family4(
nexus: self,
requiresAll: (componentA, componentB, componentC, componentD),
excludesAll: excludedComponents
)
}
}

View File

@ -1,96 +0,0 @@
//
// Family5.swift
//
//
// Created by Christian Treffs on 21.08.19.
//
// swiftlint:disable large_tuple
public typealias Family5<A: Component, B: Component, C: Component, D: Component, E: Component> = Family<Requires5<A, B, C, D, E>>
public struct Requires5<A, B, C, D, E>: FamilyRequirementsManaging where A: Component, B: Component, C: Component, D: Component, E: Component {
public let componentTypes: [Component.Type]
public init(_ types: (A.Type, B.Type, C.Type, D.Type, E.Type)) {
componentTypes = [A.self, B.self, C.self, D.self, E.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B, C, D, E) {
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
let compC: C = nexus.get(unsafeComponentFor: entityId)
let compD: D = nexus.get(unsafeComponentFor: entityId)
let compE: E = nexus.get(unsafeComponentFor: entityId)
return (compA, compB, compC, compD, compE)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B, C, D, E) {
let entity = nexus.get(unsafeEntity: entityId)
let compA: A = nexus.get(unsafeComponentFor: entityId)
let compB: B = nexus.get(unsafeComponentFor: entityId)
let compC: C = nexus.get(unsafeComponentFor: entityId)
let compD: D = nexus.get(unsafeComponentFor: entityId)
let compE: E = nexus.get(unsafeComponentFor: entityId)
return (entity, compA, compB, compC, compD, compE)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) ->
(parent: (A, B, C, D, E), child: (A, B, C, D, E)) {
let pcA: A = nexus.get(unsafeComponentFor: parentId)
let pcB: B = nexus.get(unsafeComponentFor: parentId)
let pcC: C = nexus.get(unsafeComponentFor: parentId)
let pcD: D = nexus.get(unsafeComponentFor: parentId)
let pcE: E = nexus.get(unsafeComponentFor: parentId)
let ccA: A = nexus.get(unsafeComponentFor: childId)
let ccB: B = nexus.get(unsafeComponentFor: childId)
let ccC: C = nexus.get(unsafeComponentFor: childId)
let ccD: D = nexus.get(unsafeComponentFor: childId)
let ccE: E = nexus.get(unsafeComponentFor: childId)
return (parent: (pcA, pcB, pcC, pcD, pcE),
child: (ccA, ccB, ccC, ccD, ccE))
}
public static func createMember(nexus: Nexus, components: (A, B, C, D, E)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4)
}
}
extension Requires5: FamilyEncoding where A: Encodable, B: Encodable, C: Encodable, D: Encodable, E: Encodable {
public static func encode(components: (A, B, C, D, E), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: A.self))
try container.encode(components.1, forKey: strategy.codingKey(for: B.self))
try container.encode(components.2, forKey: strategy.codingKey(for: C.self))
try container.encode(components.3, forKey: strategy.codingKey(for: D.self))
try container.encode(components.4, forKey: strategy.codingKey(for: E.self))
}
}
extension Requires5: FamilyDecoding where A: Decodable, B: Decodable, C: Decodable, D: Decodable, E: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (A, B, C, D, E) {
let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self))
let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self))
let compC = try container.decode(C.self, forKey: strategy.codingKey(for: C.self))
let compD = try container.decode(D.self, forKey: strategy.codingKey(for: D.self))
let compE = try container.decode(E.self, forKey: strategy.codingKey(for: E.self))
return Components(compA, compB, compC, compD, compE)
}
}
extension Nexus {
// swiftlint:disable function_parameter_count
public func family<A, B, C, D, E>(
requiresAll componentA: A.Type,
_ componentB: B.Type,
_ componentC: C.Type,
_ componentD: D.Type,
_ componentE: E.Type,
excludesAll excludedComponents: Component.Type...
) -> Family5<A, B, C, D, E> where A: Component, B: Component, C: Component, D: Component, E: Component {
Family5(
nexus: self,
requiresAll: (componentA, componentB, componentC, componentD, componentE),
excludesAll: excludedComponents
)
}
}

View File

View File

@ -0,0 +1,892 @@
// Generated using Sourcery 0.18.0 https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable file_length
// swiftlint:disable function_parameter_count
// swiftlint:disable large_tuple
// swiftlint:disable line_length
// swiftlint:disable multiline_parameters
// MARK: - Family 1
public typealias Family1<Comp1> = Family<Requires1<Comp1>> where Comp1: Component
public struct Requires1<Comp1>: FamilyRequirementsManaging where Comp1: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type)) {
componentTypes = [Comp1.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
return (comp1)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1)
}
public static func createMember(nexus: Nexus, components: (Comp1)) -> Entity {
nexus.createEntity(with: components)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1), child: (Comp1)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1), child: (childcomp1))
}
}
extension Requires1: FamilyEncoding where Comp1: Encodable {
public static func encode(components: (Comp1), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components, forKey: strategy.codingKey(for: Comp1.self))
}
}
extension Requires1: FamilyDecoding where Comp1: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
return comp1
}
}
extension Nexus {
/// Create a family of entities (aka members) having 1 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 1 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requires: Comp1.self)
/// // iterate each entity's components
/// family.forEach { (comp1) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 1 required components each.
public func family<Comp1>(
requires comp1: Comp1.Type,
excludesAll excludedComponents: Component.Type...
) -> Family1<Comp1> where Comp1: Component {
Family1<Comp1>(
nexus: self,
requiresAll: (comp1),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 2
public typealias Family2<Comp1, Comp2> = Family<Requires2<Comp1, Comp2>> where Comp1: Component, Comp2: Component
public struct Requires2<Comp1, Comp2>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type)) {
componentTypes = [Comp1.self, Comp2.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
return (comp1, comp2)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2)) -> Entity {
nexus.createEntity(with: components.0, components.1)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2), child: (Comp1, Comp2)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2), child: (childcomp1, childcomp2))
}
}
extension Requires2: FamilyEncoding where Comp1: Encodable, Comp2: Encodable {
public static func encode(components: (Comp1, Comp2), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
}
}
extension Requires2: FamilyDecoding where Comp1: Decodable, Comp2: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
return Components(comp1, comp2)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 2 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 2 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 2 required components each.
public func family<Comp1, Comp2>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type,
excludesAll excludedComponents: Component.Type...
) -> Family2<Comp1, Comp2> where Comp1: Component, Comp2: Component {
Family2<Comp1, Comp2>(
nexus: self,
requiresAll: (comp1, comp2),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 3
public typealias Family3<Comp1, Comp2, Comp3> = Family<Requires3<Comp1, Comp2, Comp3>> where Comp1: Component, Comp2: Component, Comp3: Component
public struct Requires3<Comp1, Comp2, Comp3>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type)) {
componentTypes = [Comp1.self, Comp2.self, Comp3.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
return (comp1, comp2, comp3)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2, comp3)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3), child: (Comp1, Comp2, Comp3)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2, parentcomp3), child: (childcomp1, childcomp2, childcomp3))
}
}
extension Requires3: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable {
public static func encode(components: (Comp1, Comp2, Comp3), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self))
}
}
extension Requires3: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self))
return Components(comp1, comp2, comp3)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 3 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 3 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2, comp3) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - comp3: Component type 3 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 3 required components each.
public func family<Comp1, Comp2, Comp3>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type,
excludesAll excludedComponents: Component.Type...
) -> Family3<Comp1, Comp2, Comp3> where Comp1: Component, Comp2: Component, Comp3: Component {
Family3<Comp1, Comp2, Comp3>(
nexus: self,
requiresAll: (comp1, comp2, comp3),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 4
public typealias Family4<Comp1, Comp2, Comp3, Comp4> = Family<Requires4<Comp1, Comp2, Comp3, Comp4>> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component
public struct Requires4<Comp1, Comp2, Comp3, Comp4>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type)) {
componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
return (comp1, comp2, comp3, comp4)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2, comp3, comp4)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4), child: (Comp1, Comp2, Comp3, Comp4)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId)
let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId)
let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4), child: (childcomp1, childcomp2, childcomp3, childcomp4))
}
}
extension Requires4: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable {
public static func encode(components: (Comp1, Comp2, Comp3, Comp4), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self))
try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self))
}
}
extension Requires4: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self))
let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self))
return Components(comp1, comp2, comp3, comp4)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 4 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 4 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2, comp3, comp4) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - comp3: Component type 3 required by members of this family.
/// - comp4: Component type 4 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 4 required components each.
public func family<Comp1, Comp2, Comp3, Comp4>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type,
excludesAll excludedComponents: Component.Type...
) -> Family4<Comp1, Comp2, Comp3, Comp4> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component {
Family4<Comp1, Comp2, Comp3, Comp4>(
nexus: self,
requiresAll: (comp1, comp2, comp3, comp4),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 5
public typealias Family5<Comp1, Comp2, Comp3, Comp4, Comp5> = Family<Requires5<Comp1, Comp2, Comp3, Comp4, Comp5>> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component
public struct Requires5<Comp1, Comp2, Comp3, Comp4, Comp5>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type)) {
componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
return (comp1, comp2, comp3, comp4, comp5)
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5), child: (Comp1, Comp2, Comp3, Comp4, Comp5)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId)
let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId)
let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId)
let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId)
let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5))
}
}
extension Requires5: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable {
public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self))
try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self))
try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self))
}
}
extension Requires5: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self))
let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self))
let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self))
return Components(comp1, comp2, comp3, comp4, comp5)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 5 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 5 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2, comp3, comp4, comp5) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - comp3: Component type 3 required by members of this family.
/// - comp4: Component type 4 required by members of this family.
/// - comp5: Component type 5 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 5 required components each.
public func family<Comp1, Comp2, Comp3, Comp4, Comp5>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type,
excludesAll excludedComponents: Component.Type...
) -> Family5<Comp1, Comp2, Comp3, Comp4, Comp5> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component {
Family5<Comp1, Comp2, Comp3, Comp4, Comp5>(
nexus: self,
requiresAll: (comp1, comp2, comp3, comp4, comp5),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 6
public typealias Family6<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6> = Family<Requires6<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6>> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component
public struct Requires6<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type)) {
componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId)
return (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.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5, comp6)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6), child: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId)
let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId)
let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId)
let parentcomp6: Comp6 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId)
let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId)
let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId)
let childcomp6: Comp6 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5, parentcomp6), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5, childcomp6))
}
}
extension Requires6: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable {
public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self))
try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self))
try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self))
try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self))
}
}
extension Requires6: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self))
let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self))
let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self))
let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self))
return Components(comp1, comp2, comp3, comp4, comp5, comp6)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 6 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 6 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - comp3: Component type 3 required by members of this family.
/// - comp4: Component type 4 required by members of this family.
/// - comp5: Component type 5 required by members of this family.
/// - comp6: Component type 6 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 6 required components each.
public func family<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type,
excludesAll excludedComponents: Component.Type...
) -> Family6<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component {
Family6<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6>(
nexus: self,
requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 7
public typealias Family7<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7> = Family<Requires7<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7>> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component
public struct Requires7<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type)) {
componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId)
return (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.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7), child: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId)
let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId)
let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId)
let parentcomp6: Comp6 = nexus.get(unsafeComponentFor: parentId)
let parentcomp7: Comp7 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId)
let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId)
let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId)
let childcomp6: Comp6 = nexus.get(unsafeComponentFor: childId)
let childcomp7: Comp7 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5, parentcomp6, parentcomp7), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5, childcomp6, childcomp7))
}
}
extension Requires7: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable {
public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self))
try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self))
try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self))
try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self))
try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self))
}
}
extension Requires7: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self))
let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self))
let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self))
let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self))
let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self))
return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 7 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 7 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - comp3: Component type 3 required by members of this family.
/// - comp4: Component type 4 required by members of this family.
/// - comp5: Component type 5 required by members of this family.
/// - comp6: Component type 6 required by members of this family.
/// - comp7: Component type 7 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 7 required components each.
public func family<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type,
excludesAll excludedComponents: Component.Type...
) -> Family7<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component {
Family7<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7>(
nexus: self,
requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7),
excludesAll: excludedComponents
)
}
}
// MARK: - Family 8
public typealias Family8<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8> = Family<Requires8<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8>> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component
public struct Requires8<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8>: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component {
public let componentTypes: [Component.Type]
public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type)) {
componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) {
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId)
let comp8: Comp8 = nexus.get(unsafeComponentFor: entityId)
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) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId)
let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId)
let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId)
let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId)
let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId)
let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId)
let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId)
let comp8: Comp8 = nexus.get(unsafeComponentFor: entityId)
return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8)
}
public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8)) -> Entity {
nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7)
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8), child: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8)) {
let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId)
let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId)
let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId)
let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId)
let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId)
let parentcomp6: Comp6 = nexus.get(unsafeComponentFor: parentId)
let parentcomp7: Comp7 = nexus.get(unsafeComponentFor: parentId)
let parentcomp8: Comp8 = nexus.get(unsafeComponentFor: parentId)
let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId)
let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId)
let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId)
let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId)
let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId)
let childcomp6: Comp6 = nexus.get(unsafeComponentFor: childId)
let childcomp7: Comp7 = nexus.get(unsafeComponentFor: childId)
let childcomp8: Comp8 = nexus.get(unsafeComponentFor: childId)
return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5, parentcomp6, parentcomp7, parentcomp8), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5, childcomp6, childcomp7, childcomp8))
}
}
extension Requires8: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable {
public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self))
try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self))
try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self))
try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self))
try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self))
try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self))
try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self))
try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self))
}
}
extension Requires8: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) {
let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self))
let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self))
let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self))
let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self))
let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self))
let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self))
let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self))
let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self))
return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8)
}
}
extension Nexus {
/// Create a family of entities (aka members) having 8 required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the 8 required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self)
/// // iterate each entity's components
/// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
/// - comp1: Component type 1 required by members of this family.
/// - comp2: Component type 2 required by members of this family.
/// - comp3: Component type 3 required by members of this family.
/// - comp4: Component type 4 required by members of this family.
/// - comp5: Component type 5 required by members of this family.
/// - comp6: Component type 6 required by members of this family.
/// - comp7: Component type 7 required by members of this family.
/// - comp8: Component type 8 required by members of this family.
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having 8 required components each.
public func family<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8>(
requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type,
excludesAll excludedComponents: Component.Type...
) -> Family8<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component {
Family8<Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8>(
nexus: self,
requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8),
excludesAll: excludedComponents
)
}
}

View File

@ -0,0 +1,138 @@
// swiftlint:disable file_length
// swiftlint:disable function_parameter_count
// swiftlint:disable large_tuple
// swiftlint:disable line_length
// swiftlint:disable multiline_parameters
{% for idx in 1...8 %}
{% map 1...idx into components using index %}Comp{{ index }}{% endmap %}
{% set CompParams %}{{components|join: ", "}}{% endset %}
{% map components into compWhere using comp %}{{ comp }}: Component{% endmap %}
{% set CompsWhere %}{{compWhere|join: ", "}}{% endset %}
{% map components into compEncodable using comp %}{{ comp }}: Encodable{% endmap %}
{% set CompsWhereEncodable %}{{compEncodable|join: ", "}}{% endset %}
{% map components into compsDecodable using comp %}{{ comp }}: Decodable{% endmap %}
{% set CompsWhereDecodable %}{{compsDecodable|join: ", "}}{% endset %}
{% map components into compTypes using comp %}{{ comp }}.Type{% endmap %}
{% set CompsTypes %}{{compTypes|join: ", "}}{% endset %}
{% map components into compSelf using comp %}{{ comp }}.self{% endmap %}
{% set CompsSelf %}{{compSelf|join: ", "}}{% endset %}
{% map components into compsLowercased using comp %}{{ comp|lowercase }}{% endmap %}
{% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %}
{% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %}
{% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %}
{% map components into compsTypeParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %}
{% set CompsTypeParams %}{{compsTypeParams|join: ", "}}{% endset %}
{% map components into compsNamedParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}{% endmap %}
{% set CompsNamedParams %}{{compsNamedParams|join: ", "}}{% endset %}
// MARK: - Family {{ idx }}
public typealias Family{{ idx }}<{{ CompParams }}> = Family<Requires{{ idx }}<{{ CompParams }}>> where {{ CompsWhere }}
public struct Requires{{ idx }}<{{ CompParams }}>: FamilyRequirementsManaging where {{ CompsWhere }} {
public let componentTypes: [Component.Type]
public init(_ components: ({{ CompsTypes }})) {
componentTypes = [{{ CompsSelf}}]
}
public static func components(nexus: Nexus, entityId: EntityIdentifier) -> ({{ CompParams }}) {
{% for comp in components %}
let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: entityId)
{% endfor %}
return ({{ CompsLowercased }})
}
public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, {{ CompParams }}) {
let entity: Entity = nexus.get(unsafeEntity: entityId)
{% for comp in components %}
let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: entityId)
{% endfor %}
return (entity, {{ CompsLowercased }})
}
public static func createMember(nexus: Nexus, components: ({{ CompParams }})) -> Entity {
{% if compEncodable.count == 1 %}nexus.createEntity(with: components){% else %}nexus.createEntity(with: {{ CompsTuple }}){% endif %}
}
public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: ({{ CompParams }}), child: ({{ CompParams }})) {
{% for comp in components %}
let parent{{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: parentId)
{% endfor %}
{% for comp in components %}
let child{{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: childId)
{% endfor %}
{% map compsLowercased into compsParent using comp %}parent{{ comp }}{% endmap %}
{% map compsLowercased into compsChild using comp %}child{{ comp }}{% endmap %}
{% set CompsParentChild %}parent: ({{compsParent|join: ", "}}), child: ({{compsChild|join: ", "}}){% endset %}
return ({{ CompsParentChild }})
}
}
extension Requires{{ idx }}: FamilyEncoding where {{ CompsWhereEncodable }} {
public static func encode(components: ({{ CompParams }}), into container: inout KeyedEncodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws {
{% if compEncodable.count == 1 %}
try container.encode(components, forKey: strategy.codingKey(for: {{ CompsSelf }}))
{% else %}
{% for comp in compSelf %}
try container.encode(components.{{ forloop.counter0 }}, forKey: strategy.codingKey(for: {{ comp }}))
{% endfor %}
{% endif %}
}
}
extension Requires{{ idx }}: FamilyDecoding where {{ CompsWhereDecodable }} {
public static func decode(componentsIn container: KeyedDecodingContainer<DynamicCodingKey>, using strategy: CodingStrategy) throws -> ({{ CompParams }}) {
{% for comp in components %}
let {{ comp|lowercase }} = try container.decode({{ comp }}.self, forKey: strategy.codingKey(for: {{ comp }}.self))
{% endfor %}
{% if compEncodable.count == 1 %}
return {{ CompsLowercased }}
{% else %}
return Components({{ CompsLowercased }})
{% endif %}
}
}
extension Nexus {
/// Create a family of entities (aka members) having {{ components.count }} required components.
///
/// A family is a collection of entities with uniform component types per entity.
/// Entities that are be part of this family will have at least the {{ components.count }} required components,
/// but may have more components assigned.
///
/// A family is just a view on (component) data, creating them is cheap.
/// Use them to iterate efficiently over entities with the same components assigned.
/// Families with the same requirements provide a view on the same collection of entities (aka members).
/// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence.
///
/// **General usage**
/// ```swift
/// let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
/// // iterate each entity's components
/// family.forEach { ({{ CompsLowercased }}) in
/// ...
/// }
/// ```
/// **Caveats**
/// - Component types must be unique per family
/// - Component type order is arbitrary
///
/// - Parameters:
{% for comp in compsLowercased %}
/// - {{ comp }}: Component type {{ forloop.counter }} required by members of this family.
{% endfor %}
/// - excludedComponents: All component types that must not be assigned to an entity in this family.
/// - Returns: The family of entities having {{ components.count }} required components each.
public func family<{{ CompParams }}>(
{% if components.count == 1 %}requires{% else %}requiresAll{%endif%} {{ CompsTypeParams }},
excludesAll excludedComponents: Component.Type...
) -> Family{{ idx }}<{{ CompParams }}> where {{ CompsWhere }} {
Family{{ idx }}<{{ CompParams }}>(
nexus: self,
requiresAll: ({{ CompsLowercased }}),
excludesAll: excludedComponents
)
}
}
{% endfor %}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
import FirebladeECS
import XCTest
{% for idx in 1...8 %}
{% map 1...idx into components using index %}Comp{{ index }}{% endmap %}
{% set CompParams %}{{components|join: ", "}}{% endset %}
{% map components into compWhere using comp %}{{ comp }}: Component{% endmap %}
{% set CompsWhere %}{{compWhere|join: ", "}}{% endset %}
{% map components into compEncodable using comp %}{{ comp }}: Encodable{% endmap %}
{% set CompsWhereEncodable %}{{compEncodable|join: ", "}}{% endset %}
{% map components into compsDecodable using comp %}{{ comp }}: Decodable{% endmap %}
{% set CompsWhereDecodable %}{{compsDecodable|join: ", "}}{% endset %}
{% map components into compTypes using comp %}{{ comp }}.Type{% endmap %}
{% set CompsTypes %}{{compTypes|join: ", "}}{% endset %}
{% map components into compSelf using comp %}{{ comp }}.self{% endmap %}
{% set CompsSelf %}{{compSelf|join: ", "}}{% endset %}
{% map components into compsLowercased using comp %}{{ comp|lowercase }}{% endmap %}
{% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %}
{% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %}
{% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %}
{% map components into compsParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %}
{% set CompsParams %}{{compsParams|join: ", "}}{% endset %}
{% map components into compsInstances using comp %}{{ comp }}({{ maploop.counter }}){% endmap %}
{% set CompsInstances %}{{compsInstances|join: ", "}}{% endset %}
{% map components into compsIndexedInstances using comp %}{{ comp }}({{ maploop.counter }}_000_000 + i){% endmap %}
{% set CompsIndexesInstances %}{{compsIndexedInstances|join: ", "}}{% endset %}
{% map components into compsJsonInner using comp %}"{{ comp }}":{ "value" : {{ maploop.counter }} }{% endmap %}
{% map 0...2 into compsJson %}{ {{compsJsonInner|join: ","}} }{% endmap %}
// MARK: - Family {{ idx }} test case
final class Family{{ idx }}Tests: XCTestCase {
var nexus: Nexus!
override func setUp() {
super.setUp()
nexus = Nexus()
}
func testMemberCreation() {
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
let entity = family.createMember(with: ({{ CompsInstances }}))
XCTAssertEqual(family.count, 1)
XCTAssertEqual(entity.numComponents, {{ idx }})
XCTAssertEqual(nexus.numFamilies, 1)
XCTAssertEqual(nexus.numEntities, 1)
XCTAssertEqual(nexus.numComponents, {{ idx }})
{% for comp in components %}
XCTAssertEqual(entity[\{{ comp }}.value], {{ forloop.counter0 }})
{% endfor %}
}
func testComponentIteration() {
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
for i in 0..<10_000 {
family.createMember(with: ({{ CompsIndexesInstances }}))
}
XCTAssertEqual(family.count, 10_000)
var idx: Int = 0
family.forEach { ({{ CompsLowercased }}) in
{% for comp in compsLowercased %}
XCTAssertEqual({{ comp }}.value, {{ forloop.counter0 }}_000_000 + idx)
{% endfor %}
idx += 1
}
}
func testEntityIteration() {
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
for i in 0..<10_000 {
family.createMember(with: ({{ CompsIndexesInstances }}))
}
XCTAssertEqual(family.count, 10_000)
var idx: Int = 0
family.entities.forEach { (entity) in
XCTAssertEqual(entity.numComponents, {{ idx }})
{% for comp in components %}
XCTAssertNotNil(entity[\{{ comp }}.self])
XCTAssertEqual(entity[\{{ comp }}.value], {{ forloop.counter0 }}_000_000 + idx)
{% endfor %}
idx += 1
}
}
func testEntityComponentIteration() {
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
for i in 0..<10_000 {
family.createMember(with: ({{ CompsIndexesInstances }}))
}
XCTAssertEqual(family.count, 10_000)
var idx: Int = 0
family.entityAndComponents.forEach { (entity, {{ CompsLowercased }}) in
XCTAssertEqual(entity.numComponents, {{ idx }})
{% for comp in components %}
XCTAssertEqual({{ comp|lowercase }}.value, {{ forloop.counter0 }}_000_000 + idx)
XCTAssertEqual(entity[\{{ comp }}.self], {{ comp|lowercase }})
{% endfor %}
idx += 1
}
}
func testFamilyEncoding() throws {
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
for i in 0..<100 {
family.createMember(with: ({{ CompsIndexesInstances }}))
}
XCTAssertEqual(family.count, 100)
var jsonEncoder = JSONEncoder()
let encodedData = try family.encodeMembers(using: &jsonEncoder)
XCTAssertGreaterThan(encodedData.count, 10)
guard let jsonString = String(data: encodedData, encoding: .utf8) else {
XCTFail("Failed to read string from encoded data \(encodedData.count)")
return
}
let expectedStart = "[{"
XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart))
let expectedEnd = "}]"
XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd))
}
func testFamilyDecoding() throws {
let jsonString: String = """
[ {{compsJson|join: ", "}} ]
"""
guard let jsonData = jsonString.data(using: .utf8) else {
XCTFail("Failed to read data from json string \(jsonString.count)")
return
}
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
var jsonDecoder = JSONDecoder()
let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder)
XCTAssertEqual(newEntities.count, 3)
XCTAssertEqual(family.count, 3)
}
func testFamilyFailDecoding() {
let jsonString = """
[{ "SomeOtherComp": { "someValue": "fail" } }]
"""
guard let jsonData = jsonString.data(using: .utf8) else {
XCTFail("Failed to read data from json string \(jsonString.count)")
return
}
let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }})
XCTAssertTrue(family.isEmpty)
var jsonDecoder = JSONDecoder()
XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in
switch error {
case let decodingError as DecodingError:
switch decodingError {
case .keyNotFound:
break
default:
XCTFail("Wrong error provided \(error)")
}
default:
XCTFail("Wrong error provided \(error)")
}
}
}
}
{% endfor %}
// MARK: - Components
{% for idx in 1...8 %}
final class Comp{{ idx }}: Component {
var value: Int
init(_ value: Int) { self.value = value }
}
extension Comp{{ idx }}: Equatable {
static func == (lhs: Comp{{ idx }}, rhs: Comp{{ idx }}) -> Bool {
lhs === rhs && lhs.value == rhs.value
}
}
extension Comp{{ idx }}: Codable { }
{% endfor %}

View File

@ -46,6 +46,126 @@ extension EntityTests {
]
}
extension Family1Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family1Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family2Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family2Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family3Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family3Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family4Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family4Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family5Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family5Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family6Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family6Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family7Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family7Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension Family8Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Family8Tests = [
("testComponentIteration", testComponentIteration),
("testEntityComponentIteration", testEntityComponentIteration),
("testEntityIteration", testEntityIteration),
("testFamilyDecoding", testFamilyDecoding),
("testFamilyEncoding", testFamilyEncoding),
("testFamilyFailDecoding", testFamilyFailDecoding),
("testMemberCreation", testMemberCreation)
]
}
extension FamilyCodingTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
@ -177,6 +297,14 @@ public func __allTests() -> [XCTestCaseEntry] {
testCase(ComponentTests.__allTests__ComponentTests),
testCase(EntityCreationTests.__allTests__EntityCreationTests),
testCase(EntityTests.__allTests__EntityTests),
testCase(Family1Tests.__allTests__Family1Tests),
testCase(Family2Tests.__allTests__Family2Tests),
testCase(Family3Tests.__allTests__Family3Tests),
testCase(Family4Tests.__allTests__Family4Tests),
testCase(Family5Tests.__allTests__Family5Tests),
testCase(Family6Tests.__allTests__Family6Tests),
testCase(Family7Tests.__allTests__Family7Tests),
testCase(Family8Tests.__allTests__Family8Tests),
testCase(FamilyCodingTests.__allTests__FamilyCodingTests),
testCase(FamilyTests.__allTests__FamilyTests),
testCase(FamilyTraitsTests.__allTests__FamilyTraitsTests),