Merge branch 'release/0.15.1' into master
This commit is contained in:
commit
4bf21efff5
|
|
@ -36,7 +36,7 @@ import PackageDescription
|
|||
let package = Package(
|
||||
name: "YourPackageName",
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/fireblade-engine/ecs.git", from: "0.15.0")
|
||||
.package(url: "https://github.com/fireblade-engine/ecs.git", from: "0.15.1")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@
|
|||
//
|
||||
|
||||
public struct EntityIdentifier {
|
||||
static let invalid = EntityIdentifier(.max)
|
||||
public static let invalid = EntityIdentifier(.max)
|
||||
|
||||
public typealias Idx = Int
|
||||
|
||||
/// provides 4294967295 unique identifiers since it's constrained to UInt32 - invalid.
|
||||
@usableFromInline let id: Idx
|
||||
|
||||
@usableFromInline
|
||||
init(_ uint32: UInt32) {
|
||||
@inlinable
|
||||
public init(_ uint32: UInt32) {
|
||||
self.id = Idx(uint32)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,31 +5,78 @@
|
|||
// Created by Christian Treffs on 26.06.20.
|
||||
//
|
||||
|
||||
internal final class EntityIdentifierGenerator {
|
||||
private var stack: [UInt32]
|
||||
/// An entity identifier generator provides new entity
|
||||
/// identifiers on entity creation.
|
||||
/// It also allows entity ids to be marked for re-use.
|
||||
/// Entity identifiers must be unique.
|
||||
public protocol EntityIdentifierGenerator {
|
||||
/// Initialize the generator with entity ids already in use.
|
||||
/// - Parameter entityIds: The entity ids already in use. Default should be an empty array.
|
||||
init(inUse entityIds: [EntityIdentifier])
|
||||
|
||||
var count: Int {
|
||||
stack.count
|
||||
}
|
||||
/// Provides the next unused entity identifier.
|
||||
///
|
||||
/// The provided entity identifier is at least unique during runtime.
|
||||
func nextId() -> EntityIdentifier
|
||||
|
||||
convenience init() {
|
||||
self.init([EntityIdentifier(0)])
|
||||
}
|
||||
/// Marks the given entity identifier as free and ready for re-use.
|
||||
///
|
||||
/// Unused entity identifiers will again be provided with `nextId()`.
|
||||
/// - Parameter entityId: The entity id to be marked as unused.
|
||||
func markUnused(entityId: EntityIdentifier)
|
||||
}
|
||||
|
||||
init(_ entityIds: [EntityIdentifier]) {
|
||||
stack = entityIds.reversed().map { UInt32($0.id) }
|
||||
}
|
||||
/// A default entity identifier generator implementation.
|
||||
///
|
||||
/// Provides entity ids starting at `0` incrementing until `UInt32.max`.
|
||||
public struct DefaultEntityIdGenerator: EntityIdentifierGenerator {
|
||||
@usableFromInline
|
||||
final class Storage {
|
||||
@usableFromInline var stack: [UInt32]
|
||||
@usableFromInline var count: Int { stack.count }
|
||||
|
||||
func nextId() -> EntityIdentifier {
|
||||
if stack.count == 1 {
|
||||
defer { stack[0] += 1 }
|
||||
return EntityIdentifier(stack[0])
|
||||
} else {
|
||||
return EntityIdentifier(stack.removeLast())
|
||||
@usableFromInline
|
||||
init(inUse entityIds: [EntityIdentifier]) {
|
||||
stack = entityIds.reversed().map { UInt32($0.id) }
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func nextId() -> EntityIdentifier {
|
||||
if stack.count == 1 {
|
||||
defer { stack[0] += 1 }
|
||||
return EntityIdentifier(stack[0])
|
||||
} else {
|
||||
return EntityIdentifier(stack.removeLast())
|
||||
}
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
func markUnused(entityId: EntityIdentifier) {
|
||||
stack.append(UInt32(entityId.id))
|
||||
}
|
||||
}
|
||||
|
||||
func freeId(_ entityId: EntityIdentifier) {
|
||||
stack.append(UInt32(entityId.id))
|
||||
@usableFromInline let storage: Storage
|
||||
|
||||
@usableFromInline var count: Int { storage.count }
|
||||
|
||||
@inlinable
|
||||
public init() {
|
||||
self.init(inUse: [EntityIdentifier(0)])
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public init(inUse entityIds: [EntityIdentifier]) {
|
||||
self.storage = Storage(inUse: entityIds)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func nextId() -> EntityIdentifier {
|
||||
storage.nextId()
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func markUnused(entityId: EntityIdentifier) {
|
||||
storage.markUnused(entityId: entityId)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ extension Nexus {
|
|||
update(familyMembership: entityId)
|
||||
}
|
||||
|
||||
entityIdGenerator.freeId(entityId)
|
||||
entityIdGenerator.markUnused(entityId: entityId)
|
||||
|
||||
delegate?.nexusEvent(EntityDestroyed(entityId: entityId))
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@ public final class Nexus {
|
|||
/// Entities are tightly packed by EntityIdentifier.
|
||||
@usableFromInline final var entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>
|
||||
|
||||
/// Entity ids that are currently not used.
|
||||
let entityIdGenerator: EntityIdentifierGenerator
|
||||
|
||||
/// - Key: ComponentIdentifier aka component type.
|
||||
/// - Value: Array of component instances of same type (uniform).
|
||||
/// New component instances are appended.
|
||||
|
|
@ -27,6 +24,16 @@ public final class Nexus {
|
|||
/// - Value: Tightly packed EntityIdentifiers that represent the association of an entity to the family.
|
||||
@usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>]
|
||||
|
||||
/// The entity identifier generator responsible for providing unique ids for entities during runtime.
|
||||
///
|
||||
/// Provide a custom implementation prior to entity creation.
|
||||
/// Defaults to `DefaultEntityIdGenerator`.
|
||||
public final var entityIdGenerator: EntityIdentifierGenerator
|
||||
|
||||
/// The coding strategy used to encode/decode entities from/into families.
|
||||
///
|
||||
/// Provide a custom implementation prior to encoding/decoding.
|
||||
/// Defaults to `DefaultCodingStrategy`.
|
||||
public final var codingStrategy: CodingStrategy
|
||||
|
||||
public final weak var delegate: NexusEventDelegate?
|
||||
|
|
@ -35,7 +42,7 @@ public final class Nexus {
|
|||
self.init(entityStorage: UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Idx>(),
|
||||
componentsByType: [:],
|
||||
componentsByEntity: [:],
|
||||
entityIdGenerator: EntityIdentifierGenerator(),
|
||||
entityIdGenerator: DefaultEntityIdGenerator(),
|
||||
familyMembersByTraits: [:],
|
||||
codingStrategy: DefaultCodingStrategy())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class EntityTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testEntityIdGenerator() {
|
||||
let generator = EntityIdentifierGenerator()
|
||||
let generator = DefaultEntityIdGenerator()
|
||||
|
||||
XCTAssertEqual(generator.count, 1)
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ class EntityTests: XCTestCase {
|
|||
XCTAssertEqual(generator.count, 1)
|
||||
|
||||
for i in 10..<60 {
|
||||
generator.freeId(EntityIdentifier(UInt32(i)))
|
||||
generator.markUnused(entityId: EntityIdentifier(UInt32(i)))
|
||||
}
|
||||
|
||||
XCTAssertEqual(generator.count, 51)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.numEntities, 0)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, 0)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, 0)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1)
|
||||
XCTAssertEqual(nexus.familyMembersByTraits[posTraits]?.count, 0)
|
||||
|
||||
batchCreateEntities(count: num)
|
||||
|
|
@ -47,7 +46,6 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.familyMembersByTraits[posTraits]?.count, num)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1)
|
||||
|
||||
colorSystem.update()
|
||||
positionSystem.update()
|
||||
|
|
@ -56,7 +54,6 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.familyMembersByTraits[posTraits]?.count, num)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1)
|
||||
|
||||
batchCreateEntities(count: num)
|
||||
|
||||
|
|
@ -64,7 +61,6 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.familyMembersByTraits[posTraits]?.count, num * 2)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num * 2)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num * 2)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1)
|
||||
|
||||
colorSystem.update()
|
||||
positionSystem.update()
|
||||
|
|
@ -73,12 +69,10 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.familyMembersByTraits[posTraits]?.count, num * 2)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num * 2)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num * 2)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1)
|
||||
|
||||
batchDestroyEntities(count: num)
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits[posTraits]?.count, num)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1 + num)
|
||||
XCTAssertEqual(nexus.numEntities, num)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num)
|
||||
|
|
@ -90,7 +84,6 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.numEntities, num)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1 + num)
|
||||
|
||||
batchCreateEntities(count: num)
|
||||
|
||||
|
|
@ -98,7 +91,6 @@ class SystemsTests: XCTestCase {
|
|||
XCTAssertEqual(nexus.numEntities, num * 2)
|
||||
XCTAssertEqual(colorSystem.colors.memberIds.count, num * 2)
|
||||
XCTAssertEqual(positionSystem.positions.memberIds.count, num * 2)
|
||||
XCTAssertEqual(nexus.entityIdGenerator.count, 1)
|
||||
}
|
||||
|
||||
func createDefaultEntity() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue