Conform Component + Entity Identifier to Identifiable protocol
This commit is contained in:
parent
2270191f2e
commit
031db2c1e3
|
|
@ -6,11 +6,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
/// Identifies a component by it's meta type
|
/// Identifies a component by it's meta type
|
||||||
public struct ComponentIdentifier {
|
public struct ComponentIdentifier: Identifiable {
|
||||||
@usableFromInline let objectIdentifier: ObjectIdentifier
|
public let id: ObjectIdentifier
|
||||||
|
|
||||||
init<T>(_ type: T.Type) where T: Component {
|
init<T>(_ type: T.Type) where T: Component {
|
||||||
self.objectIdentifier = ObjectIdentifier(type)
|
self.id = ObjectIdentifier(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,17 @@
|
||||||
// Created by Christian Treffs on 08.10.17.
|
// Created by Christian Treffs on 08.10.17.
|
||||||
//
|
//
|
||||||
|
|
||||||
public struct EntityIdentifier {
|
public struct EntityIdentifier: Identifiable {
|
||||||
public static let invalid = EntityIdentifier(.max)
|
|
||||||
|
|
||||||
/// provides 4294967295 unique identifiers since it's constrained to UInt32 - invalid.
|
/// provides 4294967295 unique identifiers since it's constrained to UInt32 - invalid.
|
||||||
public let index: Int
|
public let id: Int
|
||||||
|
|
||||||
public init(_ uint32: UInt32) {
|
public init(_ uint32: UInt32) {
|
||||||
self.index = Int(uint32)
|
self.id = Int(uint32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
extension EntityIdentifier {
|
||||||
|
public static let invalid = EntityIdentifier(.max)
|
||||||
|
}
|
||||||
|
|
||||||
extension EntityIdentifier: Equatable { }
|
extension EntityIdentifier: Equatable { }
|
||||||
extension EntityIdentifier: Hashable { }
|
extension EntityIdentifier: Hashable { }
|
||||||
|
|
@ -22,6 +23,6 @@ extension EntityIdentifier: Codable { }
|
||||||
extension EntityIdentifier: Comparable {
|
extension EntityIdentifier: Comparable {
|
||||||
@inlinable
|
@inlinable
|
||||||
public static func < (lhs: EntityIdentifier, rhs: EntityIdentifier) -> Bool {
|
public static func < (lhs: EntityIdentifier, rhs: EntityIdentifier) -> Bool {
|
||||||
return lhs.index < rhs.index
|
return lhs.id < rhs.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,14 @@ public func hash<H: Sequence>(combine hashables: H) -> Int where H.Element: Hash
|
||||||
// MARK: - entity component hash
|
// MARK: - entity component hash
|
||||||
extension EntityComponentHash {
|
extension EntityComponentHash {
|
||||||
internal static func compose(entityId: EntityIdentifier, componentTypeHash: ComponentTypeHash) -> EntityComponentHash {
|
internal static func compose(entityId: EntityIdentifier, componentTypeHash: ComponentTypeHash) -> EntityComponentHash {
|
||||||
let entityIdSwapped = UInt(entityId.index).byteSwapped // needs to be 64 bit
|
let entityIdSwapped = UInt(entityId.id).byteSwapped // needs to be 64 bit
|
||||||
let componentTypeHashUInt = UInt(bitPattern: componentTypeHash)
|
let componentTypeHashUInt = UInt(bitPattern: componentTypeHash)
|
||||||
let hashUInt: UInt = componentTypeHashUInt ^ entityIdSwapped
|
let hashUInt: UInt = componentTypeHashUInt ^ entityIdSwapped
|
||||||
return Int(bitPattern: hashUInt)
|
return Int(bitPattern: hashUInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static func decompose(_ hash: EntityComponentHash, with entityId: EntityIdentifier) -> ComponentTypeHash {
|
internal static func decompose(_ hash: EntityComponentHash, with entityId: EntityIdentifier) -> ComponentTypeHash {
|
||||||
let entityIdSwapped = UInt(entityId.index).byteSwapped
|
let entityIdSwapped = UInt(entityId.id).byteSwapped
|
||||||
let entityIdSwappedInt = Int(bitPattern: entityIdSwapped)
|
let entityIdSwappedInt = Int(bitPattern: entityIdSwapped)
|
||||||
return hash ^ entityIdSwappedInt
|
return hash ^ entityIdSwappedInt
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// Identifiable.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Christian Treffs on 05.10.19.
|
||||||
|
//
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#if swift(<5.1)
|
||||||
|
/// A class of types whose instances hold the value of an entity with stable identity.
|
||||||
|
public protocol Identifiable {
|
||||||
|
/// A type representing the stable identity of the entity associated with `self`.
|
||||||
|
associatedtype ID: Hashable
|
||||||
|
|
||||||
|
/// The stable identity of the entity associated with `self`.
|
||||||
|
var id: ID { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Identifiable where Self: AnyObject {
|
||||||
|
public var id: ObjectIdentifier {
|
||||||
|
return ObjectIdentifier(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -14,7 +14,7 @@ extension Nexus {
|
||||||
guard let uniforms = componentsByType[componentId] else {
|
guard let uniforms = componentsByType[componentId] else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return uniforms.contains(entityId.index)
|
return uniforms.contains(entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
public final func count(components entityId: EntityIdentifier) -> Int {
|
public final func count(components entityId: EntityIdentifier) -> Int {
|
||||||
|
|
@ -36,7 +36,7 @@ extension Nexus {
|
||||||
if componentsByType[componentId] == nil {
|
if componentsByType[componentId] == nil {
|
||||||
componentsByType[componentId] = ManagedContiguousArray<Component>()
|
componentsByType[componentId] = ManagedContiguousArray<Component>()
|
||||||
}
|
}
|
||||||
componentsByType[componentId]?.insert(component, at: entityId.index)
|
componentsByType[componentId]?.insert(component, at: entityId.id)
|
||||||
|
|
||||||
// assigns the component id to the entity id
|
// assigns the component id to the entity id
|
||||||
if componentIdsByEntity[entityId] == nil {
|
if componentIdsByEntity[entityId] == nil {
|
||||||
|
|
@ -58,13 +58,13 @@ extension Nexus {
|
||||||
guard let uniformComponents = componentsByType[componentId] else {
|
guard let uniformComponents = componentsByType[componentId] else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return uniformComponents.get(at: entityId.index)
|
return uniformComponents.get(at: entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
public final func get(unsafeComponent componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component {
|
public final func get(unsafeComponent componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component {
|
||||||
let uniformComponents = componentsByType[componentId].unsafelyUnwrapped
|
let uniformComponents = componentsByType[componentId].unsafelyUnwrapped
|
||||||
return uniformComponents.get(unsafeAt: entityId.index)
|
return uniformComponents.get(unsafeAt: entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
|
|
@ -88,7 +88,7 @@ extension Nexus {
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public final func remove(component componentId: ComponentIdentifier, from entityId: EntityIdentifier) -> Bool {
|
public final func remove(component componentId: ComponentIdentifier, from entityId: EntityIdentifier) -> Bool {
|
||||||
// delete component instance
|
// delete component instance
|
||||||
componentsByType[componentId]?.remove(at: entityId.index)
|
componentsByType[componentId]?.remove(at: entityId.id)
|
||||||
// unasign component from entity
|
// unasign component from entity
|
||||||
componentIdsByEntity[entityId]?.remove(componentId)
|
componentIdsByEntity[entityId]?.remove(componentId)
|
||||||
|
|
||||||
|
|
@ -117,6 +117,6 @@ extension Nexus {
|
||||||
guard let uniformComponents = componentsByType[componentId] else {
|
guard let uniformComponents = componentsByType[componentId] else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return uniformComponents.get(at: entityId.index) as? C
|
return uniformComponents.get(at: entityId.id) as? C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ extension Nexus {
|
||||||
public func createEntity() -> Entity {
|
public func createEntity() -> Entity {
|
||||||
let newEntityIdentifier: EntityIdentifier = nextEntityId()
|
let newEntityIdentifier: EntityIdentifier = nextEntityId()
|
||||||
let newEntity = Entity(nexus: self, id: newEntityIdentifier)
|
let newEntity = Entity(nexus: self, id: newEntityIdentifier)
|
||||||
entityStorage.insert(newEntity, at: newEntityIdentifier.index)
|
entityStorage.insert(newEntity, at: newEntityIdentifier.id)
|
||||||
delegate?.nexusEvent(EntityCreated(entityId: newEntityIdentifier))
|
delegate?.nexusEvent(EntityCreated(entityId: newEntityIdentifier))
|
||||||
return newEntity
|
return newEntity
|
||||||
}
|
}
|
||||||
|
|
@ -36,22 +36,22 @@ extension Nexus {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func exists(entity entityId: EntityIdentifier) -> Bool {
|
public func exists(entity entityId: EntityIdentifier) -> Bool {
|
||||||
return entityStorage.contains(entityId.index)
|
return entityStorage.contains(entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func get(entity entityId: EntityIdentifier) -> Entity? {
|
public func get(entity entityId: EntityIdentifier) -> Entity? {
|
||||||
return entityStorage.get(at: entityId.index)
|
return entityStorage.get(at: entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func get(unsafeEntity entityId: EntityIdentifier) -> Entity {
|
public func get(unsafeEntity entityId: EntityIdentifier) -> Entity {
|
||||||
return entityStorage.get(unsafeAt: entityId.index)
|
return entityStorage.get(unsafeAt: entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func destroy(entity: Entity) -> Bool {
|
public func destroy(entity: Entity) -> Bool {
|
||||||
let entityId: EntityIdentifier = entity.identifier
|
let entityId: EntityIdentifier = entity.identifier
|
||||||
|
|
||||||
guard entityStorage.remove(at: entityId.index) != nil else {
|
guard entityStorage.remove(at: entityId.id) != nil else {
|
||||||
delegate?.nexusNonFatalError("EntityRemove failure: no entity \(entityId) to remove")
|
delegate?.nexusNonFatalError("EntityRemove failure: no entity \(entityId) to remove")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,6 @@ extension Nexus {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isMember(entity entityId: EntityIdentifier, inFamilyWithTraits traits: FamilyTraitSet) -> Bool {
|
public func isMember(entity entityId: EntityIdentifier, inFamilyWithTraits traits: FamilyTraitSet) -> Bool {
|
||||||
return members(withFamilyTraits: traits).contains(entityId.index)
|
return members(withFamilyTraits: traits).contains(entityId.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,11 @@ extension Nexus {
|
||||||
|
|
||||||
final func add(entityWithId entityId: EntityIdentifier, toFamilyWithTraits traits: FamilyTraitSet) {
|
final func add(entityWithId entityId: EntityIdentifier, toFamilyWithTraits traits: FamilyTraitSet) {
|
||||||
precondition(familyMembersByTraits[traits] != nil)
|
precondition(familyMembersByTraits[traits] != nil)
|
||||||
familyMembersByTraits[traits].unsafelyUnwrapped.insert(entityId, at: entityId.index)
|
familyMembersByTraits[traits].unsafelyUnwrapped.insert(entityId, at: entityId.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
final func remove(entityWithId entityId: EntityIdentifier, fromFamilyWithTraits traits: FamilyTraitSet) {
|
final func remove(entityWithId entityId: EntityIdentifier, fromFamilyWithTraits traits: FamilyTraitSet) {
|
||||||
precondition(familyMembersByTraits[traits] != nil)
|
precondition(familyMembersByTraits[traits] != nil)
|
||||||
familyMembersByTraits[traits].unsafelyUnwrapped.remove(at: entityId.index)
|
familyMembersByTraits[traits].unsafelyUnwrapped.remove(at: entityId.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@ import XCTest
|
||||||
class EntityTests: XCTestCase {
|
class EntityTests: XCTestCase {
|
||||||
func testEntityIdentifierAndIndex() {
|
func testEntityIdentifierAndIndex() {
|
||||||
let min = EntityIdentifier(.min)
|
let min = EntityIdentifier(.min)
|
||||||
XCTAssertEqual(min.index, Int(UInt32.min))
|
XCTAssertEqual(min.id, Int(UInt32.min))
|
||||||
|
|
||||||
let uRand = UInt32.random(in: UInt32.min...UInt32.max)
|
let uRand = UInt32.random(in: UInt32.min...UInt32.max)
|
||||||
let rand = EntityIdentifier(uRand)
|
let rand = EntityIdentifier(uRand)
|
||||||
XCTAssertEqual(rand.index, Int(uRand))
|
XCTAssertEqual(rand.id, Int(uRand))
|
||||||
|
|
||||||
let max = EntityIdentifier(.max)
|
let max = EntityIdentifier(.max)
|
||||||
XCTAssertEqual(max, EntityIdentifier.invalid)
|
XCTAssertEqual(max, EntityIdentifier.invalid)
|
||||||
XCTAssertEqual(max.index, Int(UInt32.max))
|
XCTAssertEqual(max.id, Int(UInt32.max))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEntityIdentifierComparison() {
|
func testEntityIdentifierComparison() {
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@ class NexusTests: XCTestCase {
|
||||||
|
|
||||||
let e0 = nexus.createEntity()
|
let e0 = nexus.createEntity()
|
||||||
|
|
||||||
XCTAssertEqual(e0.identifier.index, 0)
|
XCTAssertEqual(e0.identifier.id, 0)
|
||||||
XCTAssertEqual(nexus.numEntities, 1)
|
XCTAssertEqual(nexus.numEntities, 1)
|
||||||
|
|
||||||
let e1 = nexus.createEntity(with: Name(name: "Entity 1"))
|
let e1 = nexus.createEntity(with: Name(name: "Entity 1"))
|
||||||
|
|
||||||
XCTAssert(e1.identifier.index == 1)
|
XCTAssert(e1.identifier.id == 1)
|
||||||
XCTAssert(nexus.numEntities == 2)
|
XCTAssert(nexus.numEntities == 2)
|
||||||
|
|
||||||
//FIXME: XCTAssertNil(e0.name)
|
//FIXME: XCTAssertNil(e0.name)
|
||||||
|
|
@ -43,7 +43,7 @@ class NexusTests: XCTestCase {
|
||||||
XCTAssertEqual(nexus.numEntities, 2)
|
XCTAssertEqual(nexus.numEntities, 2)
|
||||||
|
|
||||||
let e1: Entity = nexus.get(entity: EntityIdentifier(1))!
|
let e1: Entity = nexus.get(entity: EntityIdentifier(1))!
|
||||||
XCTAssertEqual(e1.identifier.index, 1)
|
XCTAssertEqual(e1.identifier.id, 1)
|
||||||
|
|
||||||
XCTAssertTrue(nexus.destroy(entity: e1))
|
XCTAssertTrue(nexus.destroy(entity: e1))
|
||||||
XCTAssertFalse(nexus.destroy(entity: e1))
|
XCTAssertFalse(nexus.destroy(entity: e1))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue