Merge branch 'release/0.15.1' into master

This commit is contained in:
Christian Treffs 2020-08-06 22:50:41 +02:00
commit 4bf21efff5
No known key found for this signature in database
GPG Key ID: 49A4B4B460BE3ED4
7 changed files with 84 additions and 38 deletions

View File

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

View File

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

View File

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

View File

@ -64,7 +64,7 @@ extension Nexus {
update(familyMembership: entityId)
}
entityIdGenerator.freeId(entityId)
entityIdGenerator.markUnused(entityId: entityId)
delegate?.nexusEvent(EntityDestroyed(entityId: entityId))
return true

View File

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

View File

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

View File

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