Refine entity identifier

This commit is contained in:
Christian Treffs 2020-08-21 08:26:15 +02:00
parent e770a53a87
commit f3cfe64b7d
No known key found for this signature in database
GPG Key ID: 49A4B4B460BE3ED4
7 changed files with 66 additions and 28 deletions

View File

@ -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) }
}

View File

@ -17,7 +17,7 @@ public struct Family<R> where R: FamilyRequirementsManaging {
nexus.onFamilyInit(traits: traits)
}
@inlinable var memberIds: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx> {
@inlinable var memberIds: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier> {
nexus.members(withFamilyTraits: traits)
}
@ -75,7 +75,7 @@ extension Family: LazySequenceProtocol { }
// MARK: - components iterator
extension Family {
public struct ComponentsIterator: IteratorProtocol {
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>.ElementIterator
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>.ElementIterator
@usableFromInline unowned let nexus: Nexus
public init(family: Family<R>) {
@ -102,7 +102,7 @@ extension Family {
}
public struct EntityIterator: IteratorProtocol {
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>.ElementIterator
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>.ElementIterator
@usableFromInline unowned let nexus: Nexus
public init(family: Family<R>) {
@ -128,7 +128,7 @@ extension Family {
}
public struct EntityComponentIterator: IteratorProtocol {
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>.ElementIterator
@usableFromInline var memberIdsIterator: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>.ElementIterator
@usableFromInline unowned let nexus: Nexus
public init(family: Family<R>) {

View File

@ -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
}
}

View File

@ -18,8 +18,8 @@ extension Nexus {
return traits.isMatch(components: componentIds)
}
public func members(withFamilyTraits traits: FamilyTraitSet) -> UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx> {
familyMembersByTraits[traits] ?? UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>()
public func members(withFamilyTraits traits: FamilyTraitSet) -> UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier> {
familyMembersByTraits[traits] ?? UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>()
}
public func isMember(_ entity: Entity, in family: FamilyTraitSet) -> Bool {

View File

@ -52,7 +52,7 @@ extension Nexus {
if componentsByType[componentId] == nil {
componentsByType[componentId] = ManagedContiguousArray<Component>()
}
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<EntityIdentifier, EntityIdentifier.Idx>()
familyMembersByTraits[traits] = UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>()
update(familyMembership: traits)
}

View File

@ -8,7 +8,7 @@
public final class Nexus {
/// Main entity storage.
/// Entities are tightly packed by EntityIdentifier.
@usableFromInline final var entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>
@usableFromInline final var entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>
/// - 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<EntityIdentifier, EntityIdentifier.Idx>]
@usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>]
/// 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<EntityIdentifier, EntityIdentifier.Idx>(),
self.init(entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>(),
componentsByType: [:],
componentsByEntity: [:],
entityIdGenerator: DefaultEntityIdGenerator(),
@ -47,11 +47,11 @@ public final class Nexus {
codingStrategy: DefaultCodingStrategy())
}
internal init(entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>,
internal init(entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>,
componentsByType: [ComponentIdentifier: ManagedContiguousArray<Component>],
componentsByEntity: [EntityIdentifier: Set<ComponentIdentifier>],
entityIdGenerator: EntityIdentifierGenerator,
familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>],
familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Identifier>],
codingStrategy: CodingStrategy) {
self.entityStorage = entityStorage
self.componentsByType = componentsByType

View File

@ -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() {