diff --git a/README.md b/README.md index a5406c2..7ab009f 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ import PackageDescription let package = Package( name: "YourPackageName", dependencies: [ - .package(url: "https://github.com/fireblade-engine/ecs.git", from: "0.15.3") + .package(url: "https://github.com/fireblade-engine/ecs.git", from: "0.15.4") ], targets: [ .target( @@ -71,7 +71,7 @@ then create entities by letting the `Nexus` generate them. let newEntity = nexus.createEntity() ``` -To define components conform your class to the `Component` protocol +To define components, conform your class to the `Component` protocol ```swift final class Position: Component { diff --git a/Sources/FirebladeECS/EntityIdentifier.swift b/Sources/FirebladeECS/EntityIdentifier.swift index f8a649a..6c2e98e 100644 --- a/Sources/FirebladeECS/EntityIdentifier.swift +++ b/Sources/FirebladeECS/EntityIdentifier.swift @@ -5,19 +5,57 @@ // Created by Christian Treffs on 08.10.17. // +/// **EntityIdentifier** +/// +/// An entity identifier represents the unique identity of an entity. public struct EntityIdentifier { - public static let invalid = EntityIdentifier(.max) + /// Entity identifier type. + /// + /// Provides 4294967295 unique identifiers. + public typealias Identifier = UInt32 - public typealias Idx = Int - - /// provides 4294967295 unique identifiers since it's constrained to UInt32 - invalid. - @usableFromInline let id: Idx + /// The entity identifier. + public let id: Identifier @inlinable - public init(_ uint32: UInt32) { - self.id = Idx(uint32) + public init(_ id: Identifier) { + self.init(rawValue: id) } } extension EntityIdentifier: Equatable { } extension EntityIdentifier: Hashable { } + +extension EntityIdentifier: RawRepresentable { + /// The entity identifier represented as a raw value. + @inline(__always) + public var rawValue: Identifier { id } + + @inlinable + public init(rawValue: Identifier) { + self.id = rawValue + } +} + +extension EntityIdentifier: ExpressibleByIntegerLiteral { + public init(integerLiteral value: Identifier) { + self.init(value) + } +} + +extension EntityIdentifier { + /// Invalid entity identifier + /// + /// Used to represent an invalid entity identifier. + public static let invalid = EntityIdentifier(.max) +} + +extension EntityIdentifier { + /// Provides the entity identifier as an index + /// + /// This is a convenience property for collection indexing and does not represent the raw identifier. + /// + /// Use `id` or `rawValue` instead. + @inline(__always) + public var index: Int { Int(id) } +} diff --git a/Sources/FirebladeECS/EntityIdentifierGenerator.swift b/Sources/FirebladeECS/EntityIdentifierGenerator.swift index 8a58673..46fb50d 100644 --- a/Sources/FirebladeECS/EntityIdentifierGenerator.swift +++ b/Sources/FirebladeECS/EntityIdentifierGenerator.swift @@ -32,12 +32,12 @@ public protocol EntityIdentifierGenerator { public struct DefaultEntityIdGenerator: EntityIdentifierGenerator { @usableFromInline final class Storage { - @usableFromInline var stack: [UInt32] + @usableFromInline var stack: [EntityIdentifier.Identifier] @usableFromInline var count: Int { stack.count } @usableFromInline init(inUse entityIds: [EntityIdentifier]) { - stack = entityIds.reversed().map { UInt32($0.id) } + stack = entityIds.reversed().map(\.id) } @usableFromInline @@ -52,7 +52,7 @@ public struct DefaultEntityIdGenerator: EntityIdentifierGenerator { @usableFromInline func markUnused(entityId: EntityIdentifier) { - stack.append(UInt32(entityId.id)) + stack.append(entityId.id) } } diff --git a/Sources/FirebladeECS/Family.swift b/Sources/FirebladeECS/Family.swift index 8178894..ca0804a 100644 --- a/Sources/FirebladeECS/Family.swift +++ b/Sources/FirebladeECS/Family.swift @@ -17,7 +17,7 @@ public struct Family where R: FamilyRequirementsManaging { nexus.onFamilyInit(traits: traits) } - @inlinable var memberIds: UnorderedSparseSet { + @inlinable var memberIds: UnorderedSparseSet { nexus.members(withFamilyTraits: traits) } @@ -75,7 +75,7 @@ extension Family: LazySequenceProtocol { } // MARK: - components iterator extension Family { public struct ComponentsIterator: IteratorProtocol { - @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator + @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator @usableFromInline unowned let nexus: Nexus public init(family: Family) { @@ -102,7 +102,7 @@ extension Family { } public struct EntityIterator: IteratorProtocol { - @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator + @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator @usableFromInline unowned let nexus: Nexus public init(family: Family) { @@ -128,7 +128,7 @@ extension Family { } public struct EntityComponentIterator: IteratorProtocol { - @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator + @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator @usableFromInline unowned let nexus: Nexus public init(family: Family) { diff --git a/Sources/FirebladeECS/Nexus+Component.swift b/Sources/FirebladeECS/Nexus+Component.swift index 4635a97..f45bd7b 100644 --- a/Sources/FirebladeECS/Nexus+Component.swift +++ b/Sources/FirebladeECS/Nexus+Component.swift @@ -14,7 +14,7 @@ extension Nexus { guard let uniforms = componentsByType[componentId] else { return false } - return uniforms.contains(entityId.id) + return uniforms.contains(entityId.index) } public final func count(components entityId: EntityIdentifier) -> Int { @@ -36,13 +36,13 @@ extension Nexus { guard let uniformComponents = componentsByType[componentId] else { return nil } - return uniformComponents.get(at: entityId.id) + return uniformComponents.get(at: entityId.index) } @inlinable public final func get(unsafeComponent componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component { let uniformComponents = componentsByType[componentId].unsafelyUnwrapped - return uniformComponents.get(unsafeAt: entityId.id) + return uniformComponents.get(unsafeAt: entityId.index) } @inlinable @@ -66,7 +66,7 @@ extension Nexus { @discardableResult public final func remove(component componentId: ComponentIdentifier, from entityId: EntityIdentifier) -> Bool { // delete component instance - componentsByType[componentId]?.remove(at: entityId.id) + componentsByType[componentId]?.remove(at: entityId.index) // un-assign component from entity componentIdsByEntity[entityId]?.remove(componentId) @@ -95,6 +95,6 @@ extension Nexus { guard let uniformComponents = componentsByType[componentId] else { return nil } - return uniformComponents.get(at: entityId.id) as? C + return uniformComponents.get(at: entityId.index) as? C } } diff --git a/Sources/FirebladeECS/Nexus+Family.swift b/Sources/FirebladeECS/Nexus+Family.swift index f4357b2..00d81ff 100644 --- a/Sources/FirebladeECS/Nexus+Family.swift +++ b/Sources/FirebladeECS/Nexus+Family.swift @@ -18,8 +18,8 @@ extension Nexus { return traits.isMatch(components: componentIds) } - public func members(withFamilyTraits traits: FamilyTraitSet) -> UnorderedSparseSet { - familyMembersByTraits[traits] ?? UnorderedSparseSet() + public func members(withFamilyTraits traits: FamilyTraitSet) -> UnorderedSparseSet { + familyMembersByTraits[traits] ?? UnorderedSparseSet() } public func isMember(_ entity: Entity, in family: FamilyTraitSet) -> Bool { diff --git a/Sources/FirebladeECS/Nexus+Internal.swift b/Sources/FirebladeECS/Nexus+Internal.swift index d0e570d..43bd5d2 100644 --- a/Sources/FirebladeECS/Nexus+Internal.swift +++ b/Sources/FirebladeECS/Nexus+Internal.swift @@ -52,7 +52,7 @@ extension Nexus { if componentsByType[componentId] == nil { componentsByType[componentId] = ManagedContiguousArray() } - componentsByType[componentId]?.insert(component, at: entityId.id) + componentsByType[componentId]?.insert(component, at: entityId.index) } func assign(_ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) { @@ -86,7 +86,7 @@ extension Nexus { return } - familyMembersByTraits[traits] = UnorderedSparseSet() + familyMembersByTraits[traits] = UnorderedSparseSet() update(familyMembership: traits) } diff --git a/Sources/FirebladeECS/Nexus.swift b/Sources/FirebladeECS/Nexus.swift index df77235..948a7a5 100644 --- a/Sources/FirebladeECS/Nexus.swift +++ b/Sources/FirebladeECS/Nexus.swift @@ -8,7 +8,7 @@ public final class Nexus { /// Main entity storage. /// Entities are tightly packed by EntityIdentifier. - @usableFromInline final var entityStorage: UnorderedSparseSet + @usableFromInline final var entityStorage: UnorderedSparseSet /// - Key: ComponentIdentifier aka component type. /// - Value: Array of component instances of same type (uniform). @@ -22,7 +22,7 @@ public final class Nexus { /// - Key: FamilyTraitSet aka component types that make up one distinct family. /// - Value: Tightly packed EntityIdentifiers that represent the association of an entity to the family. - @usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet] + @usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet] /// The entity identifier generator responsible for providing unique ids for entities during runtime. /// @@ -39,7 +39,7 @@ public final class Nexus { public final weak var delegate: NexusEventDelegate? public convenience init() { - self.init(entityStorage: UnorderedSparseSet(), + self.init(entityStorage: UnorderedSparseSet(), componentsByType: [:], componentsByEntity: [:], entityIdGenerator: DefaultEntityIdGenerator(), @@ -47,11 +47,11 @@ public final class Nexus { codingStrategy: DefaultCodingStrategy()) } - internal init(entityStorage: UnorderedSparseSet, + internal init(entityStorage: UnorderedSparseSet, componentsByType: [ComponentIdentifier: ManagedContiguousArray], componentsByEntity: [EntityIdentifier: Set], entityIdGenerator: EntityIdentifierGenerator, - familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet], + familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet], codingStrategy: CodingStrategy) { self.entityStorage = entityStorage self.componentsByType = componentsByType diff --git a/Tests/FirebladeECSTests/EntityTests.swift b/Tests/FirebladeECSTests/EntityTests.swift index a6103d3..8b3905f 100644 --- a/Tests/FirebladeECSTests/EntityTests.swift +++ b/Tests/FirebladeECSTests/EntityTests.swift @@ -11,15 +11,15 @@ import XCTest class EntityTests: XCTestCase { func testEntityIdentifierAndIndex() { let min = EntityIdentifier(.min) - XCTAssertEqual(min.id, Int(UInt32.min)) + XCTAssertEqual(min.id, UInt32.min) let uRand = UInt32.random(in: UInt32.min...UInt32.max) let rand = EntityIdentifier(uRand) - XCTAssertEqual(rand.id, Int(uRand)) + XCTAssertEqual(rand.id, uRand) let max = EntityIdentifier(.max) XCTAssertEqual(max, EntityIdentifier.invalid) - XCTAssertEqual(max.id, Int(UInt32.max)) + XCTAssertEqual(max.id, UInt32.max) } func testAllComponentsOfEntity() {