44 lines
1.4 KiB
Swift
44 lines
1.4 KiB
Swift
import Foundation
|
|
import Combine
|
|
|
|
/// Persists a best score per game id in UserDefaults. Shared across the shell
|
|
/// (to show "BEST" on cards) and the SpriteKit scenes (to submit results).
|
|
final class HighScoreStore: ObservableObject {
|
|
static let shared = HighScoreStore()
|
|
|
|
private let storageKey = "arcade85.highscores.v1"
|
|
@Published private(set) var scores: [String: Int] = [:]
|
|
|
|
private init() { load() }
|
|
|
|
func best(_ id: String) -> Int { scores[id] ?? 0 }
|
|
|
|
/// Records `score` for `id` if it beats the stored best. Returns true on a new record.
|
|
@discardableResult
|
|
func submit(id: String, score: Int) -> Bool {
|
|
guard score > (scores[id] ?? 0) else { return false }
|
|
scores[id] = score
|
|
save()
|
|
return true
|
|
}
|
|
|
|
/// Clears the stored best for one game (used when a game's scoring scale changes).
|
|
func reset(_ id: String) {
|
|
guard scores[id] != nil else { return }
|
|
scores[id] = nil
|
|
save()
|
|
}
|
|
|
|
private func load() {
|
|
guard let data = UserDefaults.standard.data(forKey: storageKey),
|
|
let decoded = try? JSONDecoder().decode([String: Int].self, from: data)
|
|
else { return }
|
|
scores = decoded
|
|
}
|
|
|
|
private func save() {
|
|
guard let data = try? JSONEncoder().encode(scores) else { return }
|
|
UserDefaults.standard.set(data, forKey: storageKey)
|
|
}
|
|
}
|