Skip to content

Commit

Permalink
Fix PVGame viewmodel realm crash, use @persisted
Browse files Browse the repository at this point in the history
Signed-off-by: Joseph Mattiello <[email protected]>
  • Loading branch information
JoeMatt committed Nov 22, 2024
1 parent 9dcde91 commit 2f416ea
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 233 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ class GameImporterDatabaseService : GameImporterDatabaseServicing {
game.regionName = regionName
}

if let regionID = gameDBRecordInfo["regionID"] as? Int, forceRefresh || game.regionID.value == nil {
game.regionID.value = regionID
if let regionID = gameDBRecordInfo["regionID"] as? Int, forceRefresh || game.regionID == nil {
game.regionID = regionID
}

if let gameDescription = gameDBRecordInfo["gameDescription"] as? String, !gameDescription.isEmpty, forceRefresh || game.gameDescription == nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import PVFileSystem

@objcMembers
public final class PVImageFile: PVFile {
public internal(set) dynamic var _cgsize: String!
public dynamic var ratio: Float = 0.0
public dynamic var width: Int = 0
public dynamic var height: Int = 0
public dynamic var layout: String = ""
@Persisted public internal(set) dynamic var _cgsize: String!
@Persisted public var ratio: Float = 0.0
@Persisted public var width: Int = 0
@Persisted public var height: Int = 0
@Persisted public var layout: String = ""

public convenience init(withPartialPath partialPath: String, relativeRoot: RelativeRoot = RelativeRoot.platformDefault) {
self.init()
Expand Down
20 changes: 8 additions & 12 deletions PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVBIOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,19 @@ public final class PVBIOS: Object, Identifiable, BIOSFileProvider {
// public var status: BIOSStatus
public var id: String { expectedMD5 }

public dynamic var system: PVSystem!
@Persisted public var system: PVSystem!

public dynamic var descriptionText: String = ""
@Persisted public var descriptionText: String = ""
public var regions: RegionOptions = .unknown
public dynamic var version: String = ""
public dynamic var optional: Bool = false
@Persisted public var version: String = ""
@Persisted public var optional: Bool = false

public dynamic var expectedMD5: String = ""
public dynamic var expectedSize: Int = 0
public dynamic var expectedFilename: String = ""
@Persisted(indexed: true) public var expectedMD5: String = ""
@Persisted public var expectedSize: Int = 0
@Persisted(primaryKey: true) public var expectedFilename: String = ""

public dynamic var file: PVFile?
@Persisted public var file: PVFile?
public var fileInfo: PVFile? { return file }

public override static func primaryKey() -> String? {
return "expectedFilename"
}
}

public extension PVBIOS {
Expand Down
22 changes: 9 additions & 13 deletions PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import PVPrimitives

@objcMembers
public final class PVCore: RealmSwift.Object, Identifiable {
public dynamic var identifier: String = ""
public dynamic var principleClass: String = ""
public var supportedSystems = List<PVSystem>()
@Persisted(primaryKey: true) public var identifier: String = ""
@Persisted public var principleClass: String = ""
@Persisted public var supportedSystems: List<PVSystem>

public dynamic var projectName = ""
public dynamic var projectURL = ""
public dynamic var projectVersion = ""
public dynamic var disabled = false
public dynamic var appStoreDisabled = false
@Persisted public var projectName = ""
@Persisted public var projectURL = ""
@Persisted public var projectVersion = ""
@Persisted public var disabled = false
@Persisted public var appStoreDisabled = false

public var hasCoreClass: Bool {
let _class: AnyClass? = NSClassFromString(principleClass)
Expand All @@ -30,7 +30,7 @@ public final class PVCore: RealmSwift.Object, Identifiable {
}

// Reverse links
public var saveStates = LinkingObjects(fromType: PVSaveState.self, property: "core")
@Persisted(originProperty: "core") public var saveStates: LinkingObjects<PVSaveState>

public convenience init(withIdentifier identifier: String, principleClass: String, supportedSystems: [PVSystem], name: String, url: String, version: String, disabled: Bool = false, appStoreDisabled: Bool = false) {
self.init()
Expand All @@ -45,10 +45,6 @@ public final class PVCore: RealmSwift.Object, Identifiable {
self.appStoreDisabled = appStoreDisabled
}

public override static func primaryKey() -> String? {
return "identifier"
}

public override class func ignoredProperties() -> [String] {
["hasCoreClass", "id"]
}
Expand Down
103 changes: 48 additions & 55 deletions PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVGame.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,53 +14,60 @@ import PVFileSystem

@objcMembers
public final class PVGame: RealmSwift.Object, Identifiable, PVGameLibraryEntry {
public dynamic var title: String = ""
public dynamic var id :String = NSUUID().uuidString
@Persisted public var title: String = ""
@Persisted(wrappedValue: NSUUID().uuidString) public var id :String

// TODO: This is a 'partial path' meaing it's something like {system id}.filename
// We should make this an absolute path but would need a Realm translater and modifying
// any methods that use this path. Everything should use PVEmulatorConfigure path(forGame:)
// and then we just need to change that method but I haven't check that every method uses that
// The other option is to only use the filename and then path(forGame:) would determine the
// fully qualified path, but if we add network / cloud storage that may or may not change that.
public dynamic var romPath: String = ""
public dynamic var file: PVFile!
public private(set) var relatedFiles = List<PVFile>()
@Persisted public var romPath: String = ""
@Persisted public var file: PVFile!
@Persisted public private(set) var relatedFiles = List<PVFile>()

public dynamic var customArtworkURL: String = ""
public dynamic var originalArtworkURL: String = ""
public dynamic var originalArtworkFile: PVImageFile?
@Persisted public var customArtworkURL: String = ""
@Persisted public var originalArtworkURL: String = ""
@Persisted public var originalArtworkFile: PVImageFile?

public dynamic var requiresSync: Bool = true
public dynamic var isFavorite: Bool = false
@Persisted public var requiresSync: Bool = true
@Persisted(indexed: true) public var isFavorite: Bool = false

public dynamic var romSerial: String?
public dynamic var romHeader: String?
public private(set) dynamic var importDate: Date = Date()
@Persisted public var romSerial: String?
@Persisted public var romHeader: String?
@Persisted public private(set) var importDate: Date = Date()

public dynamic var systemIdentifier: String = ""
public dynamic var system: PVSystem!
@Persisted(indexed: true) public var systemIdentifier: String = ""
@Persisted public var system: PVSystem!

public dynamic var md5Hash: String = ""
public dynamic var crc: String = ""
/*
Primary key must be set at import time and can't be changed after.
I had to change the import flow to calculate the MD5 before import.
Seems sane enough since it's on the serial queue. Could always use
an async dispatch if it's an issue. - jm
*/

@Persisted(primaryKey: true) public var md5Hash: String = ""
@Persisted public var crc: String = ""

// If the user has set 'always use' for a specfic core
// We don't use PVCore incase cores are removed / deleted
public dynamic var userPreferredCoreID: String?
@Persisted public var userPreferredCoreID: String?

/* Links to other objects */
public private(set) var saveStates = LinkingObjects<PVSaveState>(fromType: PVSaveState.self, property: "game")
public private(set) var cheats = LinkingObjects<PVCheats>(fromType: PVCheats.self, property: "game")
public private(set) var recentPlays = LinkingObjects(fromType: PVRecentGame.self, property: "game")
public private(set) var screenShots = List<PVImageFile>()
@Persisted(originProperty: "game") public private(set) var saveStates: LinkingObjects<PVSaveState>
@Persisted(originProperty: "game") public private(set) var cheats: LinkingObjects<PVCheats>
@Persisted(originProperty: "game") public private(set) var recentPlays: LinkingObjects<PVRecentGame>
@Persisted public private(set) var screenShots = List<PVImageFile>()

public private(set) var libraries = LinkingObjects<PVLibrary>(fromType: PVLibrary.self, property: "games")
@Persisted(originProperty: "games") public private(set) var libraries: LinkingObjects<PVLibrary>

/* Tracking data */
public dynamic var lastPlayed: Date?
public dynamic var playCount: Int = 0
public dynamic var timeSpentInGame: Int = 0
public dynamic var rating: Int = -1 {
@Persisted public var lastPlayed: Date?
@Persisted public var playCount: Int = 0
@Persisted public var timeSpentInGame: Int = 0
@Persisted public var rating: Int = -1 {
willSet {
assert(-1 ... 5 ~= newValue, "Setting rating out of range -1 to 5")
}
Expand All @@ -72,35 +79,21 @@ public final class PVGame: RealmSwift.Object, Identifiable, PVGameLibraryEntry {
}

/* Extra metadata from OpenBG */
public dynamic var gameDescription: String?
public dynamic var boxBackArtworkURL: String?
public dynamic var developer: String?
public dynamic var publisher: String?
public dynamic var publishDate: String?
public dynamic var genres: String? // Is a comma seperated list or single entry
public dynamic var referenceURL: String?
public dynamic var releaseID: String?
public dynamic var regionName: String?
public var regionID = RealmProperty<Int?>()
public dynamic var systemShortName: String?
public dynamic var language: String?
@Persisted public var gameDescription: String?
@Persisted public var boxBackArtworkURL: String?
@Persisted public var developer: String?
@Persisted public var publisher: String?
@Persisted public var publishDate: String?
@Persisted public var genres: String? // Is a comma seperated list or single entry
@Persisted public var referenceURL: String?
@Persisted public var releaseID: String?
@Persisted public var regionName: String?
@Persisted public var regionID: Int?
@Persisted public var systemShortName: String?
@Persisted public var language: String?

public var validatedGame: PVGame? { return self.isInvalidated ? nil : self }

/*
Primary key must be set at import time and can't be changed after.
I had to change the import flow to calculate the MD5 before import.
Seems sane enough since it's on the serial queue. Could always use
an async dispatch if it's an issue. - jm
*/
public override static func primaryKey() -> String? {
return "md5Hash"
}

public override static func indexedProperties() -> [String] {
return ["systemIdentifier"]
}

public static func mockGenerate(systemID: String? = nil, count: Int = 10) -> [PVGame] {
let systemIdentifier = systemID ?? "mock.system"
return (1...count).map { index in
Expand Down Expand Up @@ -186,7 +179,7 @@ public extension Game {
let genres = game.genres
let referenceURL = game.referenceURL
let releaseID = game.releaseID
let regionID = game.regionID.value
let regionID = game.regionID
let regionName = game.regionName
let systemShortName = game.systemShortName
let language = game.language
Expand Down Expand Up @@ -265,7 +258,7 @@ extension Game: RealmRepresentable {
object.referenceURL = referenceURL
object.releaseID = releaseID
object.regionName = regionName
object.regionID.value = regionID
object.regionID = regionID
object.systemShortName = systemShortName
object.language = language
object.file = PVFile(withPartialPath: file.fileName)
Expand Down
18 changes: 9 additions & 9 deletions PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ import RealmSwift

@objcMembers
public final class PVLibrary: Object {
public dynamic var uuid: String = ""
public dynamic var name: String = ""
@Persisted public var uuid: String = ""
@Persisted public var name: String = ""

public dynamic var isLocal: Bool = true
@Persisted public var isLocal: Bool = true

// Remote info
public dynamic var ipaddress: String = ""
public dynamic var domainname: String = ""
public dynamic var bonjourName: String = ""
public dynamic var port: Int = 7769 // prov on phone pad
@Persisted public var ipaddress: String = ""
@Persisted public var domainname: String = ""
@Persisted public var bonjourName: String = ""
@Persisted public var port: Int = 7769 // prov on phone pad

public dynamic var lastSeen: Date = Date()
@Persisted public var lastSeen: Date = Date()

public private(set) var games = List<PVGame>()
@Persisted public private(set) var games: List<PVGame>
}

// PVLibrary - Network
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public protocol PVGameLibraryEntry: PVLibraryEntry {
dynamic var referenceURL: String? { get }
dynamic var releaseID: String? { get }
dynamic var regionName: String? { get }
var regionID: RealmProperty<Int?> { get }
var regionID: Int? { get }
dynamic var systemShortName: String? { get }
dynamic var language: String? { get }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,10 @@ import RealmSwift

@objcMembers public final class PVRecentGame: Object, Identifiable, PVRecentGameLibraryEntry {

public dynamic var id :String = NSUUID().uuidString
public dynamic var game: PVGame!
public dynamic var lastPlayedDate: Date = Date()
public dynamic var core: PVCore?

public override static func indexedProperties() -> [String] {
return ["lastPlayedDate"]
}
@Persisted(wrappedValue: UUID().uuidString) public var id: String
@Persisted public var game: PVGame!
@Persisted(wrappedValue: Date(), indexed: true) public var lastPlayedDate: Date
@Persisted public var core: PVCore?

public convenience init(withGame game: PVGame, core: PVCore? = nil) {
self.init()
Expand Down
22 changes: 9 additions & 13 deletions PVLibrary/Sources/PVRealm/RealmPlatform/Entities/PVSaveState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ import PVPrimitives

@objcMembers
public final class PVSaveState: RealmSwift.Object, Identifiable, Filed, LocalFileProvider {
public dynamic var id = UUID().uuidString
public dynamic var game: PVGame!
public dynamic var core: PVCore!
public dynamic var file: PVFile!
public dynamic var date: Date = Date()
public dynamic var lastOpened: Date?
public dynamic var image: PVImageFile?
public dynamic var isAutosave: Bool = false
@Persisted(wrappedValue: UUID().uuidString, primaryKey: true) public var id: String
@Persisted public var game: PVGame!
@Persisted public var core: PVCore!
@Persisted public var file: PVFile!
@Persisted public var date: Date = Date()
@Persisted public var lastOpened: Date?
@Persisted public var image: PVImageFile?
@Persisted public var isAutosave: Bool = false

public dynamic var createdWithCoreVersion: String!
@Persisted public var createdWithCoreVersion: String!

public convenience init(withGame game: PVGame, core: PVCore, file: PVFile, image: PVImageFile? = nil, isAutosave: Bool = false) {
self.init()
Expand All @@ -38,8 +38,4 @@ public final class PVSaveState: RealmSwift.Object, Identifiable, Filed, LocalFil
public static func == (lhs: PVSaveState, rhs: PVSaveState) -> Bool {
return lhs.file.url == rhs.file.url
}

public override static func primaryKey() -> String? {
return "id"
}
}
Loading

0 comments on commit 2f416ea

Please sign in to comment.