Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions Sources/UntoldEngine/Systems/RegistrationSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -855,8 +855,28 @@ func getMeshesForEntity(entityId: EntityID) -> [Mesh]? {
}

public func setEntityName(entityId: EntityID, name: String) {
if let previousName = entityNameMap[entityId], !previousName.isEmpty {
if var list = reverseEntityNameMap[previousName] {
list.removeAll { $0 == entityId }
if list.isEmpty {
reverseEntityNameMap.removeValue(forKey: previousName)
} else {
reverseEntityNameMap[previousName] = list
}
}
}

if name.isEmpty {
entityNameMap.removeValue(forKey: entityId)
return
}

entityNameMap[entityId] = name
reverseEntityNameMap[name] = entityId
var list = reverseEntityNameMap[name] ?? []
if list.contains(entityId) == false {
list.append(entityId)
}
reverseEntityNameMap[name] = list
}

public func getEntityName(entityId: EntityID) -> String {
Expand All @@ -870,13 +890,34 @@ func removeEntityName(entityId: EntityID) {
if let stored = entityNameMap[entityId],
stored.isEmpty == false
{
reverseEntityNameMap.removeValue(forKey: stored)
if var list = reverseEntityNameMap[stored] {
list.removeAll { $0 == entityId }
if list.isEmpty {
reverseEntityNameMap.removeValue(forKey: stored)
} else {
reverseEntityNameMap[stored] = list
}
}
}
entityNameMap.removeValue(forKey: entityId)
}

public func findEntity(name: String) -> EntityID? {
reverseEntityNameMap[name]
guard var list = reverseEntityNameMap[name], !list.isEmpty else {
return nil
}

list = list.filter { id in
scene.exists(id) && entityNameMap[id] == name
}

if list.isEmpty {
reverseEntityNameMap.removeValue(forKey: name)
return nil
}

reverseEntityNameMap[name] = list
return list.first
}

/*
Expand Down
2 changes: 1 addition & 1 deletion Sources/UntoldEngine/Utils/Globals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var entityMeshMap: [EntityID: [Mesh]] = [:] // Holds all meshes loaded

var entityNameMap: [EntityID: String] = [:] // links entity Id to names

var reverseEntityNameMap: [String: EntityID] = [:]
var reverseEntityNameMap: [String: [EntityID]] = [:]

// Timing properties
var timeSinceLastUpdatePreviousTime: TimeInterval!
Expand Down
23 changes: 23 additions & 0 deletions Tests/UntoldEngineTests/ECSTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,29 @@ final class ECSTests: XCTestCase {
XCTAssertNotEqual(entityId, wrongId, "entities should not match")
}

func testFindEntityWithDuplicateNamesReturnsFirstValidMatch() {
entityNameMap.removeAll()
reverseEntityNameMap.removeAll()

let firstEntity = createEntity()
let secondEntity = createEntity()

setEntityName(entityId: firstEntity, name: "dup")
setEntityName(entityId: secondEntity, name: "dup")

XCTAssertEqual(findEntity(name: "dup"), firstEntity, "Should return first entity assigned with the name")

destroyEntity(entityId: firstEntity)

XCTAssertEqual(findEntity(name: "dup"), secondEntity, "Should skip stale entity and return next valid match")

if let list = reverseEntityNameMap["dup"] {
XCTAssertEqual(list, [secondEntity], "Stale entries should be pruned from the reverse name map")
} else {
XCTFail("Expected reverse name map to contain remaining entity")
}
}

func testGetAllEntityComponentTypes() {
// Arrange
let entityId = createEntity()
Expand Down
Loading