Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Folium-iOS/Classes/Games/Games.swift
2 views
//
//  BaseGame.swift
//  Folium-iOS
//
//  Created by Jarrod Norwell on 10/3/2026.
//

import Cytrus
import CombinedCores
import CoreGraphics
import Foundation
import UIKit

class CodableHashableSendable : Codable, Hashable, @unchecked Sendable {
    var id: UUID = UUID()
    
    static func == (lhs: CodableHashableSendable, rhs: CodableHashableSendable) -> Bool {
        lhs.id == rhs.id
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
}

class BaseGame : Codable, Comparable, Hashable, @unchecked Sendable {
    var id: UUID = UUID()
    let name: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
    
    static func == (lhs: BaseGame, rhs: BaseGame) -> Bool {
        lhs.id == rhs.id
    }
    
    static func < (lhs: BaseGame, rhs: BaseGame) -> Bool {
        lhs.name.localizedCaseInsensitiveCompare(rhs.name) == .orderedAscending
    }
    
    init(details: GameDetails) {
        name = details.name
    }
    
    func getCore() -> Core? {
        switch self {
        case is NewCherryGame: .cherry
        case is NewCytrusGame: .cytrus
        case is NewGrapeGame: .grape
        case is NewGuavaGame: .guava
        case is NewKiwiGame: .kiwi
        case is NewMandarineGame: .mandarine
        case is NewMangoGame: .mango
        case is NewPlumGame: .plum
        case is NewTomatoGame: .tomato
        default: nil
        }
    }
    
    func asGame<T>() -> T? {
        self as? T
    }
}

class NewCherryGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    let skins: [Skin]
    
    init(cartridge: URL, skinManager: SkinManager) {
        core = .cherry
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .cherry)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewCytrusGame : BaseGame, @unchecked Sendable {
    // TODO: rewrite this
    class Extras : CodableHashableSendable, @unchecked Sendable {
        var cheats: [CytrusCheat] = []
        var saveStates: [CytrusSaveState] = []
        
        var identifier: UInt64? = nil
        var cytrus: Cytrus
        var cheatsManager: CytrusCheatsManager
        
        init(cytrus: Cytrus, identifier: UInt64? = nil, _ error: inout NSError?) {
            self.cytrus = cytrus
            self.identifier = identifier
            
            self.cheatsManager = .init(with: identifier ?? 999)
            self.cheatsManager.load()
            self.cheats = self.cheatsManager.cheats()
            
            for element in cytrus.savesStates(for: identifier ?? 999) {
                switch element {
                case let saveState as CytrusSaveState:
                    self.saveStates.append(saveState)
                case let nsError as NSError:
                    error = nsError
                default:
                    break
                }
            }
            super.init()
        }
        
        required init(from decoder: any Decoder) throws {
            fatalError("init(from:) has not been implemented")
        }
        
        func toggle(_ cheat: CytrusCheat, _ index: Int = -1) {
            cheatsManager.toggle(cheat: cheat)
            guard index >= 0 else {
                return
            }
            cheatsManager.update(cheat: cheat, at: index)
            cheatsManager.save()
        }
        
        func update() {
            cheatsManager.load()
            cheats = cheatsManager.cheats()
            
            saveStates.removeAll()
            for element in cytrus.savesStates(for: identifier ?? 999) {
                switch element {
                case let saveState as CytrusSaveState:
                    saveStates.append(saveState)
                default:
                    break
                }
            }
        }
    }
    
    // TODO: rewrite this
    class Information : CodableHashableSendable, @unchecked Sendable {
        var identifier: UInt64? = nil
        var kernelMemoryMode: CytrusKernelMemoryMode? = nil
        var new3DSKernelMemoryMode: CytrusNew3DSKernelMemoryMode? = nil
        var publisher: String? = nil
        var regions: String? = nil
        
        init(from information: CytrusGameInformation) {
            self.identifier = information.identifier
            self.kernelMemoryMode = information.kernelMemoryMode
            self.new3DSKernelMemoryMode = information.new3DSKernelMemoryMode
            self.publisher = information.publisher
            self.regions = information.regions
            super.init()
        }
        
        init(identifier: UInt64? = nil, kernelMemoryMode: CytrusKernelMemoryMode? = nil,
             new3DSKernelMemoryMode: CytrusNew3DSKernelMemoryMode? = nil, publisher: String? = nil, regions: String? = nil) {
            self.identifier = identifier
            self.kernelMemoryMode = kernelMemoryMode
            self.new3DSKernelMemoryMode = new3DSKernelMemoryMode
            self.publisher = publisher
            self.regions = regions
            super.init()
        }
        
        required init(from decoder: any Decoder) throws {
            fatalError("init(from:) has not been implemented")
        }
    }
    
    let core: Core
    var details: GameDetails
    var extras: Extras
    var icon: Data?
    var information: Information
    let skins: [Skin]
    
    init(cartridge: URL, cytrusCore: Cytrus, skinManager: SkinManager) {
        core = .cytrus
        details = GameDetails(cartridge: cartridge)
        var error: NSError?
        extras = Extras(cytrus: cytrusCore, identifier: nil, &error)
        information = Information()
        skins = skinManager.skins(for: .cytrus)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewGrapeGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    var icon: CGImage?
    let skins: [Skin]
    
    init(cartridge: URL, grapeCore: CombinedCores.GrapeCore, skinManager: SkinManager) {
        core = .grape
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .grape)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewGuavaGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    let skins: [Skin]
    
    init(cartridge: URL, guavaCore: CombinedCores.GuavaCore, skinManager: SkinManager) {
        core = .guava
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .guava)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewKiwiGame : BaseGame, @unchecked Sendable {
    let core: Core
    var details: GameDetails
    let skins: [Skin]
    
    init(cartridge: URL, kiwiCore: CombinedCores.KiwiCore, skinManager: SkinManager) {
        core = .kiwi
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .kiwi)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewMandarineGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    var icon: UIImage?
    let skins: [Skin]
    
    init(cartridge: URL, mandarineCore: CombinedCores.MandarineCore, skinManager: SkinManager) {
        core = .mandarine
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .mandarine)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewMangoGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    var icon: UIImage?
    let skins: [Skin]
    
    init(cartridge: URL, mangoCore: CombinedCores.MangoCore, skinManager: SkinManager) {
        core = .mango
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .mango)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewPlumGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    let skins: [Skin]
    
    init(cartridge: URL, skinManager: SkinManager) {
        core = .plum
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .plum)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}

class NewTomatoGame : BaseGame, @unchecked Sendable {
    let core: Core
    let details: GameDetails
    var icon: UIImage?
    let skins: [Skin]
    
    init(cartridge: URL, tomatoCore: CombinedCores.TomatoCore, skinManager: SkinManager) {
        core = .tomato
        details = GameDetails(cartridge: cartridge)
        skins = skinManager.skins(for: .tomato)
        super.init(details: details)
    }
    
    required init(from decoder: any Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }
}