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
2 changes: 1 addition & 1 deletion Sources/DHKit/EncounterSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public final class EncounterSession: Identifiable, Hashable {
}

/// Reduce stress on a combat participant by ID, clamping to 0.
public func reduceStress(_ amount: Int, from id: UUID) {
public func reduceStress(_ amount: Int, for id: UUID) {
if let i = _adversarySlots.firstIndex(where: { $0.id == id }) {
let s = _adversarySlots[i]
_adversarySlots[i] = s.applying(currentStress: max(0, s.currentStress - amount))
Expand Down
7 changes: 5 additions & 2 deletions Sources/DHKit/EncounterStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Observation
// MARK: - EncounterStoreError

/// Errors thrown by ``EncounterStore`` operations.
public enum EncounterStoreError: Error, LocalizedError, Sendable {
nonisolated public enum EncounterStoreError: Error, LocalizedError, Sendable {
case notFound(UUID)
case saveFailed(UUID, String)
case deleteFailed(UUID, String)
Expand Down Expand Up @@ -188,7 +188,10 @@ public final class EncounterStore {
/// Valid definitions are published via ``definitions``, sorted by
/// `modifiedAt` descending. Directory-level errors are stored in ``loadError``.
public func load() async {
guard !isLoading else { return }
// EncounterStore is a single shared instance loaded once at app startup.
// Concurrent calls to load() are a programming error, not a normal operating
// condition — use precondition so violations surface immediately in debug builds.
precondition(!isLoading, "load() called while a load is already in progress")
isLoading = true
loadError = nil
defer { isLoading = false }
Expand Down
14 changes: 6 additions & 8 deletions Sources/DHKit/SessionRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,14 @@ public final class SessionRegistry {

public init() {}

/// Return the existing session for `definitionID`, or create and store a new one.
/// Return the existing session for `definition.id`, or create and store a new one.
public func session(
for definitionID: UUID,
definition: EncounterDefinition,
for definition: EncounterDefinition,
compendium: Compendium
) -> EncounterSession {
if let existing = sessions[definitionID] { return existing }
if let existing = sessions[definition.id] { return existing }
let newSession = EncounterSession.make(from: definition, using: compendium)
sessions[definitionID] = newSession
sessions[definition.id] = newSession
return newSession
}

Expand All @@ -57,12 +56,11 @@ public final class SessionRegistry {
/// Use this when the GM wants to restart an encounter from scratch without navigating away.
@discardableResult
public func resetSession(
for definitionID: UUID,
definition: EncounterDefinition,
for definition: EncounterDefinition,
compendium: Compendium
) -> EncounterSession {
let newSession = EncounterSession.make(from: definition, using: compendium)
sessions[definitionID] = newSession
sessions[definition.id] = newSession
return newSession
}
}
2 changes: 1 addition & 1 deletion Tests/DHKitTests/EncounterSessionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ import Testing
let slot = session.playerSlots[0]

session.applyStress(4, to: slot.id)
session.reduceStress(2, from: slot.id)
session.reduceStress(2, for: slot.id)
#expect(session.playerSlots[0].currentStress == 2)
}

Expand Down
22 changes: 11 additions & 11 deletions Tests/DHKitTests/SessionRegistryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import Testing
let compendium = makeCompendium()
let def = makeDefinition()

let session = registry.session(for: def.id, definition: def, compendium: compendium)
let session = registry.session(for: def, compendium: compendium)
#expect(session.adversarySlots.count == 1)
}

Expand All @@ -45,8 +45,8 @@ import Testing
let compendium = makeCompendium()
let def = makeDefinition()

let s1 = registry.session(for: def.id, definition: def, compendium: compendium)
let s2 = registry.session(for: def.id, definition: def, compendium: compendium)
let s1 = registry.session(for: def, compendium: compendium)
let s2 = registry.session(for: def, compendium: compendium)
#expect(s1 === s2)
}

Expand All @@ -55,7 +55,7 @@ import Testing
let compendium = makeCompendium()
let def = makeDefinition()

_ = registry.session(for: def.id, definition: def, compendium: compendium)
_ = registry.session(for: def, compendium: compendium)
registry.clearSession(for: def.id)
#expect(registry.sessions[def.id] == nil)
}
Expand All @@ -65,11 +65,11 @@ import Testing
let compendium = makeCompendium()
let def1 = makeDefinition(adversaryIDs: ["goblin"])

let s1 = registry.session(for: def1.id, definition: def1, compendium: compendium)
let s1 = registry.session(for: def1, compendium: compendium)
s1.applyDamage(2, to: s1.adversarySlots[0].id)
#expect(s1.adversarySlots[0].currentHP == 1)

let s2 = registry.resetSession(for: def1.id, definition: def1, compendium: compendium)
let s2 = registry.resetSession(for: def1, compendium: compendium)

#expect(s2 !== s1)
#expect(s2.adversarySlots[0].currentHP == 3)
Expand All @@ -80,10 +80,10 @@ import Testing
let compendium = makeCompendium()
let def = makeDefinition()

let s1 = registry.session(for: def.id, definition: def, compendium: compendium)
let s2 = registry.resetSession(for: def.id, definition: def, compendium: compendium)
let s1 = registry.session(for: def, compendium: compendium)
let s2 = registry.resetSession(for: def, compendium: compendium)

let s3 = registry.session(for: def.id, definition: def, compendium: compendium)
let s3 = registry.session(for: def, compendium: compendium)
#expect(s3 === s2)
#expect(s3 !== s1)
}
Expand All @@ -95,8 +95,8 @@ import Testing
var def2 = def1
def2.adversaryIDs = ["goblin", "goblin"]

_ = registry.session(for: def1.id, definition: def1, compendium: compendium)
let s2 = registry.resetSession(for: def2.id, definition: def2, compendium: compendium)
_ = registry.session(for: def1, compendium: compendium)
let s2 = registry.resetSession(for: def2, compendium: compendium)

#expect(s2.adversarySlots.count == 2)
}
Expand Down
Loading