Merge branch 'feature/identifiable' into 'master'
Identifiable See merge request fireblade/ecs!4
This commit is contained in:
commit
65755b3c65
|
|
@ -6,11 +6,11 @@
|
|||
//
|
||||
|
||||
/// Identifies a component by it's meta type
|
||||
public struct ComponentIdentifier {
|
||||
@usableFromInline let objectIdentifier: ObjectIdentifier
|
||||
public struct ComponentIdentifier: Identifiable {
|
||||
public let id: ObjectIdentifier
|
||||
|
||||
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.
|
||||
//
|
||||
|
||||
public struct EntityIdentifier {
|
||||
public static let invalid = EntityIdentifier(.max)
|
||||
|
||||
public struct EntityIdentifier: Identifiable {
|
||||
/// provides 4294967295 unique identifiers since it's constrained to UInt32 - invalid.
|
||||
public let index: Int
|
||||
public let id: Int
|
||||
|
||||
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: Hashable { }
|
||||
|
|
@ -22,6 +23,6 @@ extension EntityIdentifier: Codable { }
|
|||
extension EntityIdentifier: Comparable {
|
||||
@inlinable
|
||||
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
|
||||
extension 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 hashUInt: UInt = componentTypeHashUInt ^ entityIdSwapped
|
||||
return Int(bitPattern: hashUInt)
|
||||
}
|
||||
|
||||
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)
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
return uniforms.contains(entityId.index)
|
||||
return uniforms.contains(entityId.id)
|
||||
}
|
||||
|
||||
public final func count(components entityId: EntityIdentifier) -> Int {
|
||||
|
|
@ -36,7 +36,7 @@ extension Nexus {
|
|||
if componentsByType[componentId] == nil {
|
||||
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
|
||||
if componentIdsByEntity[entityId] == nil {
|
||||
|
|
@ -58,13 +58,13 @@ extension Nexus {
|
|||
guard let uniformComponents = componentsByType[componentId] else {
|
||||
return nil
|
||||
}
|
||||
return uniformComponents.get(at: entityId.index)
|
||||
return uniformComponents.get(at: entityId.id)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public final func get(unsafeComponent componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component {
|
||||
let uniformComponents = componentsByType[componentId].unsafelyUnwrapped
|
||||
return uniformComponents.get(unsafeAt: entityId.index)
|
||||
return uniformComponents.get(unsafeAt: entityId.id)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
|
|
@ -88,7 +88,7 @@ extension Nexus {
|
|||
@discardableResult
|
||||
public final func remove(component componentId: ComponentIdentifier, from entityId: EntityIdentifier) -> Bool {
|
||||
// delete component instance
|
||||
componentsByType[componentId]?.remove(at: entityId.index)
|
||||
componentsByType[componentId]?.remove(at: entityId.id)
|
||||
// unasign component from entity
|
||||
componentIdsByEntity[entityId]?.remove(componentId)
|
||||
|
||||
|
|
@ -117,6 +117,6 @@ extension Nexus {
|
|||
guard let uniformComponents = componentsByType[componentId] else {
|
||||
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 {
|
||||
let newEntityIdentifier: EntityIdentifier = nextEntityId()
|
||||
let newEntity = Entity(nexus: self, id: newEntityIdentifier)
|
||||
entityStorage.insert(newEntity, at: newEntityIdentifier.index)
|
||||
entityStorage.insert(newEntity, at: newEntityIdentifier.id)
|
||||
delegate?.nexusEvent(EntityCreated(entityId: newEntityIdentifier))
|
||||
return newEntity
|
||||
}
|
||||
|
|
@ -36,22 +36,22 @@ extension Nexus {
|
|||
}
|
||||
|
||||
public func exists(entity entityId: EntityIdentifier) -> Bool {
|
||||
return entityStorage.contains(entityId.index)
|
||||
return entityStorage.contains(entityId.id)
|
||||
}
|
||||
|
||||
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 {
|
||||
return entityStorage.get(unsafeAt: entityId.index)
|
||||
return entityStorage.get(unsafeAt: entityId.id)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public func destroy(entity: Entity) -> Bool {
|
||||
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")
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,6 @@ extension Nexus {
|
|||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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 {
|
||||
func testEntityIdentifierAndIndex() {
|
||||
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 rand = EntityIdentifier(uRand)
|
||||
XCTAssertEqual(rand.index, Int(uRand))
|
||||
XCTAssertEqual(rand.id, Int(uRand))
|
||||
|
||||
let max = EntityIdentifier(.max)
|
||||
XCTAssertEqual(max, EntityIdentifier.invalid)
|
||||
XCTAssertEqual(max.index, Int(UInt32.max))
|
||||
XCTAssertEqual(max.id, Int(UInt32.max))
|
||||
}
|
||||
|
||||
func testEntityIdentifierComparison() {
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ class NexusTests: XCTestCase {
|
|||
|
||||
let e0 = nexus.createEntity()
|
||||
|
||||
XCTAssertEqual(e0.identifier.index, 0)
|
||||
XCTAssertEqual(e0.identifier.id, 0)
|
||||
XCTAssertEqual(nexus.numEntities, 1)
|
||||
|
||||
let e1 = nexus.createEntity(with: Name(name: "Entity 1"))
|
||||
|
||||
XCTAssert(e1.identifier.index == 1)
|
||||
XCTAssert(e1.identifier.id == 1)
|
||||
XCTAssert(nexus.numEntities == 2)
|
||||
|
||||
//FIXME: XCTAssertNil(e0.name)
|
||||
|
|
@ -43,7 +43,7 @@ class NexusTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.numEntities, 2)
|
||||
|
||||
let e1: Entity = nexus.get(entity: EntityIdentifier(1))!
|
||||
XCTAssertEqual(e1.identifier.index, 1)
|
||||
XCTAssertEqual(e1.identifier.id, 1)
|
||||
|
||||
XCTAssertTrue(nexus.destroy(entity: e1))
|
||||
XCTAssertFalse(nexus.destroy(entity: e1))
|
||||
|
|
|
|||
Loading…
Reference in New Issue