Added a lot of stuff lmao

This commit is contained in:
stossy11 2024-06-26 21:24:37 +10:00
parent 9e4cad4159
commit a57ce24f6d
44 changed files with 889 additions and 177 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -131,7 +131,7 @@
38C8467F2C1DCD2200331706 /* VirtualControllerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VirtualControllerView.swift; sourceTree = "<group>"; };
38C846962C1DCDC100331706 /* EmulationVirtualControllerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmulationVirtualControllerController.swift; sourceTree = "<group>"; };
38C846972C1DCDC100331706 /* EmulationScreensController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmulationScreensController.swift; sourceTree = "<group>"; };
38C8469C2C1DCDC100331706 /* SudachiEmulationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SudachiEmulationController.swift; sourceTree = "<group>"; };
38C8469C2C1DCDC100331706 /* SudachiEmulationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SudachiEmulationController.swift; sourceTree = "<group>"; wrapsLines = 1; };
38C846A12C1DCDC100331706 /* INIEditController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = INIEditController.swift; sourceTree = "<group>"; };
38C846AC2C1DCE8900331706 /* MoltenVK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = MoltenVK.xcframework; sourceTree = "<group>"; };
38C846AD2C1DCE8900331706 /* libavcodec.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = libavcodec.xcframework; sourceTree = "<group>"; };
@ -670,6 +670,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CODE_SIGN_ENTITLEMENTS = Pomelo/Pomelo.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
@ -708,6 +709,7 @@
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@ -719,6 +721,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CODE_SIGN_ENTITLEMENTS = Pomelo/Pomelo.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
@ -757,6 +760,7 @@
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";

View File

@ -14,8 +14,8 @@
filePath = "Pomelo/Classes/LibraryManager.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "143"
endingLineNumber = "143"
startingLineNumber = "145"
endingLineNumber = "145"
landmarkName = "createMissingDirectoriesInDocumentsDirectory()"
landmarkType = "7">
</BreakpointContent>

BIN
Pomelo/.DS_Store vendored

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,38 @@
{
"images" : [
{
"filename" : "IMG_1799 1.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "IMG_1808.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "IMG_1799.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "IMG_1800.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "IMG_1799.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "image 1.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,54 +1,34 @@
{
"images" : [
{
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
"filename" : "IMG_1799 1.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "IMG_1808.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "IMG_1799.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -0,0 +1,38 @@
{
"images" : [
{
"filename" : "IMG_1800.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "IMG_1800 1.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "IMG_1800 2.jpg",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -0,0 +1,38 @@
{
"images" : [
{
"filename" : "image.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "image 1.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"filename" : "image 2.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

View File

@ -75,12 +75,13 @@ struct Core : Comparable, Hashable {
var colors: [VirtualControllerButton.ButtonType: UIColor] = [:]
// Load theme
if let theme = ThemeLoader.shared.loadTheme() {
if let theme = ThemeLoader.shared.loadThemes() {
colors = [
.a: theme.color(for: .a) ?? .systemGray,
.b: theme.color(for: .b) ?? .systemGray,
.x: theme.color(for: .x) ?? .systemGray,
.y: theme.color(for: .y) ?? .systemGray,
// Add more buttons as needed
]
} else {
@ -115,7 +116,8 @@ class DirectoriesManager {
func directories() -> [String : [String : MissingFile.FileImportance]] {
[
"themes" : ["theme.json": .optional],
"themes" : [
"theme.json": .optional],
"amiibo" : [:],
"cache" : [:],
"config" : [:],
@ -147,11 +149,17 @@ class DirectoriesManager {
try FileManager.default.createDirectory(at: coreDirectory, withIntermediateDirectories: false)
}
var isDirectory: ObjCBool = true
// Create theme.json file if it doesn't exist
if directory == "themes" {
let themeFileURL = coreDirectory.appendingPathComponent("theme.json")
let themeimagefoler = coreDirectory.appendingPathComponent("images/")
if !FileManager.default.fileExists(atPath: themeimagefoler.path, isDirectory: &isDirectory) {
try FileManager.default.createDirectory(at: themeimagefoler, withIntermediateDirectories: false)
}
if !FileManager.default.fileExists(atPath: themeFileURL.path) {
let defaultTheme = Theme(color: "", a: "", b: "", x: "", y: "")
let defaultTheme = Theme(background: "", a: "", b: "", x: "", y: "")
if let jsonData = try? JSONEncoder().encode(defaultTheme) {
FileManager.default.createFile(atPath: themeFileURL.path, contents: jsonData, attributes: nil)
}
@ -163,18 +171,14 @@ class DirectoriesManager {
func scanDirectoriesForRequiredFiles(for core: inout Core) {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
directories().forEach { directory in
directory.value.forEach { subdirectory, fileNames in
let coreSubdirectory = documentsDirectory.appendingPathComponent(directory.key, conformingTo: .folder)
.appendingPathComponent(subdirectory, conformingTo: .folder)
directories().forEach { directory, fileNames in
let coreDirectory = documentsDirectory.appendingPathComponent(directory, conformingTo: .folder)
fileNames.forEach { (fileName, fileImportance) in
let fileURL = coreDirectory.appendingPathComponent(fileName, conformingTo: .fileURL)
// Ensure fileNames is treated as a dictionary of [String: MissingFile.FileImportance]
if let fileNamesDict = fileNames as? [String: MissingFile.FileImportance] {
fileNamesDict.forEach { (fileName, fileImportance) in
if !FileManager.default.fileExists(atPath: coreSubdirectory.appendingPathComponent(fileName, conformingTo: .fileURL).path) {
core.missingFiles.append(.init(coreName: core.name, directory: coreSubdirectory, fileImportance: fileImportance, fileName: fileName))
}
}
if !FileManager.default.fileExists(atPath: fileURL.path) {
core.missingFiles.append(.init(coreName: core.name, directory: coreDirectory, fileImportance: fileImportance, fileName: fileName))
}
}
}

View File

@ -10,7 +10,7 @@ import SwiftUI
import Foundation
struct Theme: Codable {
let color: String
let background: String
let a: String?
let b: String?
let x: String?
@ -37,10 +37,10 @@ struct Theme: Codable {
class ThemeLoader {
static let shared = ThemeLoader()
func loadTheme(completion: @escaping (UIColor?) -> Void) {
func loadTheme(completion: @escaping (UIColor?, URL?) -> Void) {
let fileManager = FileManager.default
guard let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
completion(nil)
completion(nil, nil)
print("Unable to get documents directory.")
return
}
@ -51,21 +51,33 @@ class ThemeLoader {
do {
let data = try Data(contentsOf: themeURL)
let theme = try JSONDecoder().decode(Theme.self, from: data)
let color = UIColor(hex: theme.color)
let fileExtension = (theme.background as NSString).pathExtension.lowercased()
let color = UIColor(hex: theme.background)
DispatchQueue.main.async {
print("Loaded theme color: \(color) from \(themeURL)")
completion(color)
if fileExtension == "png" || fileExtension == "jpg" || fileExtension == "jpeg" {
let themeURLs = documentsDirectory.appendingPathComponent("themes/images/\(theme.background)")
if fileManager.fileExists(atPath: themeURLs.path) {
print(themeURLs.path)
completion(nil, themeURLs)
} else {
print("Unable To get image trying to load theme colors: \(color) from \(themeURL)")
completion(color, nil)
}
} else {
print("Loaded theme color: \(color) from \(themeURL)")
completion(color, nil)
}
}
} catch {
DispatchQueue.main.async {
print("Error loading theme: \(error.localizedDescription)")
completion(nil)
completion(nil, nil)
}
}
}
}
func loadTheme() -> Theme? {
func loadThemes() -> Theme? {
let fileManager = FileManager.default
guard let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
return nil
@ -82,6 +94,10 @@ class ThemeLoader {
return nil
}
}
func LoadBackgroundImage() {
}
}
extension UIColor {

View File

@ -55,15 +55,3 @@ struct ContentView: View {
}
struct BootOSView: View {
@State var core: Core?
var body: some View {
Text("beans")
.onAppear {
if let core = core {
let PomeloGame = SudachiGame(core: core, developer: "", fileURL: URL(string: "{")!, imageData: Data(), title: "")
presentPomeloEmulation(PomeloGame: PomeloGame)
}
}
}
}

View File

@ -15,7 +15,7 @@ struct ScreenConfiguration {
static let cornerRadius: CGFloat = 10
}
class EmulationScreensController : EmulationVirtualControllerController {
class EmulationScreensController: EmulationVirtualControllerController {
var primaryScreen, secondaryScreen: UIView!
var primaryBlurredScreen, secondaryBlurredScreen: UIView!
fileprivate var visualEffectView: UIVisualEffectView!
@ -26,9 +26,23 @@ class EmulationScreensController : EmulationVirtualControllerController {
fileprivate var portraitConstraints, landscapeConstraints: [NSLayoutConstraint]!
fileprivate var customButtonPortraitConstraints, customButtonLandscapeConstraints: [NSLayoutConstraint]!
let customButton: UIButton = {
let button = UIButton(type: .system)
// Set the system image for the button
let image = UIImage(systemName: "x.square")
button.setImage(image, for: .normal)
// Adjust button appearance if necessary
button.tintColor = .white
button.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
let userDefaults = UserDefaults.standard
visualEffectView = .init(effect: UIBlurEffect(style: .systemMaterial))
visualEffectView.translatesAutoresizingMaskIntoConstraints = false
@ -57,21 +71,30 @@ class EmulationScreensController : EmulationVirtualControllerController {
if #available(iOS 17, *) {
registerForTraitChanges([UITraitUserInterfaceStyle.self], action: #selector(traitDidChange))
}
// Add the custom button
if userDefaults.bool(forKey: "exitgame") {
addCustomButton()
// Add the initial constraints for the custom button
applyCustomButtonConstraints(for: view.bounds.size)
}
}
override func viewWillTransition(to size: CGSize, with coordinator: any UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let userDefaults = UserDefaults.standard
if userDefaults.bool(forKey: "exitgame") {
// Update the custom button constraints based on the new size
applyCustomButtonConstraints(for: size)
}
if userDefaults.bool(forKey: "isfullscreen") {
if UIApplication.shared.statusBarOrientation == .portrait {
view.removeConstraints(fullScreenConstraints)
view.addConstraints(portraitConstraints)
} else {
view.removeConstraints(fullScreenConstraints)
view.addConstraints(fullScreenConstraints)
}
view.removeConstraints(fullScreenConstraints)
view.addConstraints(fullScreenConstraints)
} else {
if UIApplication.shared.statusBarOrientation == .portrait || UIApplication.shared.statusBarOrientation == .portraitUpsideDown {
if UIApplication.shared.statusBarOrientation.isPortrait {
view.removeConstraints(landscapeConstraints)
view.addConstraints(portraitConstraints)
} else {
@ -111,13 +134,6 @@ class EmulationScreensController : EmulationVirtualControllerController {
primaryScreen.bottomAnchor.constraint(equalTo: view.bottomAnchor)
]
portraitConstraints = [
primaryScreen.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
primaryScreen.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10),
primaryScreen.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16),
]
view.addConstraints(fullScreenConstraints)
}
@ -163,8 +179,7 @@ class EmulationScreensController : EmulationVirtualControllerController {
primaryBlurredScreen.trailingAnchor.constraint(equalTo: primaryScreen.trailingAnchor, constant: 10)
]
view.addConstraints(UIApplication.shared.statusBarOrientation == .portrait ||
UIApplication.shared.statusBarOrientation == .portraitUpsideDown ? portraitConstraints : landscapeConstraints)
view.addConstraints(UIApplication.shared.statusBarOrientation.isPortrait ? portraitConstraints : landscapeConstraints)
}
@objc fileprivate func traitDidChange() {
@ -198,4 +213,34 @@ class EmulationScreensController : EmulationVirtualControllerController {
return imageRef
}
func addCustomButton() {
customButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(customButton)
customButtonPortraitConstraints = [
customButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
customButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
customButton.widthAnchor.constraint(equalToConstant: 100), // Increased width
customButton.heightAnchor.constraint(equalToConstant: 100) // Increased height
]
customButtonLandscapeConstraints = [
customButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
customButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10),
customButton.widthAnchor.constraint(equalToConstant: 100), // Increased width
customButton.heightAnchor.constraint(equalToConstant: 100) // Increased height
]
}
func applyCustomButtonConstraints(for size: CGSize) {
view.removeConstraints(customButtonPortraitConstraints)
view.removeConstraints(customButtonLandscapeConstraints)
if size.width > size.height {
view.addConstraints(customButtonLandscapeConstraints)
} else {
view.addConstraints(customButtonPortraitConstraints)
}
}
}

View File

@ -12,6 +12,7 @@ import Foundation
import GameController
import MetalKit.MTKView
import UIKit
import SwiftUI
class SudachiEmulationController : EmulationScreensController {
fileprivate var thread: Thread!
@ -28,7 +29,7 @@ class SudachiEmulationController : EmulationScreensController {
sudachiGame = game
thread = .init(block: step)
thread.name = "Sudachi"
thread.name = "Pomelo"
thread.qualityOfService = .userInteractive
thread.threadPriority = 0.9
}
@ -39,14 +40,50 @@ class SudachiEmulationController : EmulationScreensController {
override func viewDidLoad() {
super.viewDidLoad()
let oldsaved = UserDefaults.standard.color(forKey: "color")
if let savedColor = oldsaved {
print("\(savedColor)" + "fun theme")
let userDefaults = UserDefaults.standard
if let urlString = userDefaults.string(forKey: "background") {
let fileManager = FileManager.default
let backgroundURL = URL(fileURLWithPath: urlString)
let exists = fileManager.fileExists(atPath: urlString)
if exists {
if let image = UIImage(contentsOfFile: urlString) {
let backgroundImageView = UIImageView(image: image)
backgroundImageView.contentMode = .scaleAspectFill
self.view.addSubview(backgroundImageView)
self.view.sendSubviewToBack(backgroundImageView)
} else {
print("Error: Unable to load image from path: \(urlString)")
if let savedColor = userDefaults.color(forKey: "color") {
print("\(savedColor)" + " fun theme")
view.backgroundColor = savedColor
} else {
print("fun theme nil")
view.backgroundColor = .systemBackground // Default color
}
}
} else {
print("Error: File does not exist or is a directory at path: \(urlString)")
if let savedColor = userDefaults.color(forKey: "color") {
print("\(savedColor)" + " fun theme")
view.backgroundColor = savedColor
} else {
print("fun theme nil")
view.backgroundColor = .systemBackground // Default color
}
}
} else if let savedColor = userDefaults.color(forKey: "color") {
print("\(savedColor)" + " fun theme")
view.backgroundColor = savedColor
} else {
print("\(oldsaved)" + "fun theme nil")
print("fun theme nil")
view.backgroundColor = .systemBackground // Default color
}
if userDefaults.bool(forKey: "exitgame") {
customButton.addTarget(self, action: #selector(customButtonTapped), for: .touchUpInside)
}
}
override func viewDidLayoutSubviews() {
@ -80,6 +117,18 @@ class SudachiEmulationController : EmulationScreensController {
}
}
@objc func customButtonTapped() {
stopEmulation()
}
func stopEmulation() {
if isRunning {
self.dismiss(animated: true)
isRunning = false
sudachi.bootOS1()
thread.cancel()
}
}
@objc fileprivate func step() {
while true {
sudachi.step()
@ -301,6 +350,21 @@ class SudachiEmulationController : EmulationScreensController {
}
}
struct SudachiEmulationViewController: UIViewControllerRepresentable {
var game: SudachiGame
@Binding var shouldStopEmulation: Bool
func makeUIViewController(context: Context) -> SudachiEmulationController {
let controller = SudachiEmulationController(game: game)
controller.modalPresentationStyle = .fullScreen
return controller
}
func updateUIViewController(_ uiViewController: SudachiEmulationController, context: Context) {
if shouldStopEmulation {
uiViewController.stopEmulation()
}
}
}
#endif

Binary file not shown.

View File

@ -6,5 +6,67 @@
<true/>
<key>UIRequiresPersistentWiFi</key>
<true/>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeDescription</key>
<string>NRO file</string>
<key>UTTypeIdentifier</key>
<string>com.stossy11.nro</string>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>NCA file</string>
<key>UTTypeIdentifier</key>
<string>com.stossy11.nca</string>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>NSO file</string>
<key>UTTypeIdentifier</key>
<string>com.stossy11.nso</string>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>NRO file</string>
<key>UTTypeIdentifier</key>
<string>com.stossy11.nsp</string>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>NRO file</string>
<key>UTTypeIdentifier</key>
<string>com.stossy11.xci</string>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
<dict>
<key>UTTypeDescription</key>
<string>NRO file</string>
<key>UTTypeIdentifier</key>
<string>com.stossy11.keys</string>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeDescription</key>
<string>nro</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeTagSpecification</key>
<dict/>
</dict>
</array>
</dict>
</plist>

View File

@ -8,6 +8,7 @@
import SwiftUI
import Foundation
import UIKit
import UniformTypeIdentifiers
struct Help : Comparable, Hashable, Identifiable {
var id = UUID()
@ -30,19 +31,6 @@ struct Help : Comparable, Hashable, Identifiable {
}
struct CoreRowView: View {
var core: Core
var body: some View {
VStack(alignment: .leading) {
Text(core.name.rawValue)
.font(.headline)
Text(core.console.rawValue)
.font(.subheadline)
}
}
}
struct GameRowView: View {
var game: SudachiGame
@ -86,6 +74,7 @@ struct CoreDetailView: View {
@State var core: Core
@State private var searchText = ""
@State var ispoped = false
@State var game: SudachiGame? = nil
var body: some View {
let filteredGames = core.games.filter { game in
@ -101,6 +90,8 @@ struct CoreDetailView: View {
ForEach(0..<filteredGames.count, id: \.self) { index in
if let game = core.games[index] as? SudachiGame {
Button {
self.game = game
// ispoped = true
presentPomeloEmulation(PomeloGame: game)
} label: {
GameRowView(game: game)
@ -115,6 +106,14 @@ struct CoreDetailView: View {
}
.padding()
}
.onAppear() {
core = Core(console: Core.Console.nSwitch, name: .Sudachi, games: [], missingFiles: [], root: URL(string: "[]")!)
do {
core = try LibraryManager.shared.library()
} catch {
print("Failed to fetch library: \(error)")
}
}
.refreshable {
core = Core(console: Core.Console.nSwitch, name: .Sudachi, games: [], missingFiles: [], root: URL(string: "[]")!)
do {
@ -200,10 +199,10 @@ struct InfoView: View {
}
struct SideJITServerSettings: View {
@AppStorage("sidejitserver-enable") var sidejitserver: Bool = false
@AppStorage("sidejitserver-NavigationLink") var showAlert: Bool = false
@AppStorage("sidejitserver-ip") var ip: String = ""
@AppStorage("sidejitserver-udid") var udid: String = ""
@AppStorage("sidejitserver-enable-true") var sidejitserver: Bool = false
@AppStorage("sidejitserver-NavigationLink-true") var showAlert: Bool = false
@AppStorage("sidejitserver-ip-true") var ip: String = ""
@AppStorage("sidejitserver-udid-true") var udid: String = ""
@AppStorage("sidejitserver-enable-auto") var sidejitserverauto: Bool = false
@AppStorage("alertstring") var alertstring = ""
@AppStorage("alert") var alert = false
@ -214,10 +213,11 @@ struct SideJITServerSettings: View {
.font(.largeTitle)
TextField("SideJITServer IP", text: $ip)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
.padding(.top)
Text("This is not needed if SideJITServer has already been detected")
.font(.subheadline)
.foregroundColor(.secondary)
.padding(.bottom)
SecureField("UDID", text: $udid)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
@ -343,11 +343,33 @@ struct SideJITServerSettings: View {
}
}
extension UTType {
static var nro: UTType {
UTType(exportedAs: "com.stossy11.nro")
}
static var nca: UTType {
UTType(exportedAs: "com.stossy11.nca")
}
static var nso: UTType {
UTType(exportedAs: "com.stossy11.nso")
}
static var nsp: UTType {
UTType(exportedAs: "com.stossy11.nsp")
}
static var xci: UTType {
UTType(exportedAs: "com.stossy11.xci")
}
static var keys: UTType {
UTType(exportedAs: "com.stossy11.keys")
}
}
struct LibraryView: View {
@Binding var core: Core
@State var showingEditConfig = false
@State private var isActive: Bool = false
@State private var isimport: Bool = false
@State private var showprompt: Bool = false
@AppStorage("sidejitserver-enable") var sidejitserver: Bool = false
@AppStorage("sidejitserver-NavigationLink") var showAlert: Bool = false
@ -359,7 +381,7 @@ struct LibraryView: View {
@AppStorage("issue") var issue = false
var body: some View {
NavigationView {
NavigationStack {
VStack {
let (doesKeyExist, doesProdExist) = doeskeysexist()
if doesKeyExist && doesProdExist {
@ -389,39 +411,93 @@ struct LibraryView: View {
}
}
.fileImporter(isPresented: $isimport, allowedContentTypes: [.data], onCompletion: { result in
switch result {
case .success(let file):
if file.startAccessingSecurityScopedResource() {
moveFileToAppropriateFolder(file)
file.stopAccessingSecurityScopedResource()
} else {
print("Failed to access the file")
}
case .failure(let error):
isimport = false
print(error.localizedDescription)
}
//moveFileToAppropriateFolder()
})
.navigationBarTitle("Library", displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
isimport = true
} label: {
Image(systemName: "folder.badge.plus")
}
}
}
}
}
private func moveFileToAppropriateFolder(_ fileURL: URL) {
let fileManager = FileManager.default
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let romsDirectory = documentsDirectory.appendingPathComponent("roms")
let keysDirectory = documentsDirectory.appendingPathComponent("keys")
let fileExtension = fileURL.pathExtension.lowercased()
if ["nca", "nro", "nso", "nsp", "xci"].contains(fileExtension) {
do {
try fileManager.moveItem(at: fileURL, to: romsDirectory.appendingPathComponent(fileURL.lastPathComponent))
} catch {
print("Error moving file to roms folder: \(error.localizedDescription)")
}
} else if fileExtension == "keys" {
do {
try fileManager.moveItem(at: fileURL, to: keysDirectory.appendingPathComponent(fileURL.lastPathComponent))
} catch {
print("Error moving file to keys folder: \(error.localizedDescription)")
}
}
}
func doeskeysexist() -> (Bool, Bool) {
var doesprodexist = false
var doestitleexist = false
var bean: [MissingFile] = []
if core != nil {
let title = core.root.appendingPathComponent("keys").appendingPathComponent("title.keys")
let prod = core.root.appendingPathComponent("keys").appendingPathComponent("prod.keys")
let fileManager = FileManager.default
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
if fileManager.fileExists(atPath: prod.path) {
doesprodexist = true
} else {
print("File does not exist")
do {
bean = try LibraryManager.shared.library().missingFiles
} catch {
print("uhoh stinky")
}
if fileManager.fileExists(atPath: title.path) {
doestitleexist = true
} else {
print("File does not exist")
print(bean.count)
print(bean)
// Check if "prod.keys" is missing
doesprodexist = !bean.contains { $0.fileName == "prod.keys" && $0.directory.lastPathComponent == "keys" }
if !doesprodexist {
print("prod.keys does not exist")
}
// Check if "title.keys" is missing
doestitleexist = !bean.contains { $0.fileName == "title.keys" && $0.directory.lastPathComponent == "keys" }
if (!doestitleexist) {
print("title.keys does not exist")
}
}
return((doestitleexist, doesprodexist))
return (doestitleexist, doesprodexist)
}
}
struct INIEditControllerWrapper: UIViewControllerRepresentable {
let console: Core.Console // Replace Console with your actual type
let configURL: URL

View File

@ -8,15 +8,16 @@
import SwiftUI
import Foundation
import UIKit
import Sudachi
@main
struct PomeloApp: App {
@State var cores: Core = Core(console: .nSwitch, name: .Sudachi, games: [], missingFiles: [], root: URL(fileURLWithPath: "/"))
@AppStorage("entitlementNotExists") private var entitlementNotExists: Bool = false
@AppStorage("sidejitserver-enable") var sidejitserver: Bool = false
@AppStorage("sidejitserver-NavigationLink") var showAlert: Bool = false
@AppStorage("sidejitserver-ip") var ip: String = ""
@AppStorage("sidejitserver-udid") var udid: String = ""
@AppStorage("sidejitserver-enable-true") var sidejitserver: Bool = false
@AppStorage("sidejitserver-NavigationLink-true") var showAlert: Bool = false
@AppStorage("sidejitserver-ip-true") var ip: String = ""
@AppStorage("sidejitserver-udid-true") var udid: String = ""
@AppStorage("sidejitserver-enable-auto") var sidejitserverauto: Bool = false
@State private var latestVersion: String?
@State var alertstring = ""
@ -74,7 +75,7 @@ struct PomeloApp: App {
.alert(isPresented: $alert) {
Alert(
title: Text("SideJITServer"),
message: Text("SideJITServer has been found on your network would you like to enable support."),
message: Text("SideJITServer has been found on your network would you like to enable support. (Please Configure SideJITServer in Settings)"),
primaryButton: .default(Text("OK"), action: {
UserDefaults.standard.set(true, forKey: "sidejitserver-enable")
}),
@ -91,36 +92,64 @@ struct PomeloApp: App {
struct NavView: View {
@Binding var cores: Core
let sudachi = Sudachi.shared
@State private var selectedTab = 0
@State private var isTabDisabled = false
@State private var showAlert = false
var body: some View {
TabView {
TabView(selection: $selectedTab) {
LibraryView(core: $cores)
.tabItem {
Label("Games", systemImage: "rectangle.on.rectangle")
}
BootOSView(core: cores)
.tabItem {
Label("Home Menu", systemImage: "house")
}
.tag(0)
if sudachi.canGetFullPath() {
LibraryView(core: $cores)
.onChange(of: selectedTab) { newValue in
if newValue == 1 {
selectedTab = 0
let PomeloGame = SudachiGame(core: cores, developer: "", fileURL: URL(string: "{")!, imageData: Data(), title: "")
presentPomeloEmulation(PomeloGame: PomeloGame)
}
}
.tabItem {
Label("Home Menu", systemImage: "house")
}
.tag(1)
} else {
NoBootOS()
.tabItem {
Label("Home Menu", systemImage: "house")
}
.tag(1)
}
SettingsView(core: cores)
.tabItem {
Label("Settings", systemImage: "gear")
}
.tag(2)
}
}
}
func presentPomeloEmulation(PomeloGame: SudachiGame) {
var backgroundColor: UIColor = .systemBackground
let PomeloEmulationController = SudachiEmulationController(game: PomeloGame)
PomeloEmulationController.modalPresentationStyle = .fullScreen
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
ThemeLoader.shared.loadTheme { color in
ThemeLoader.shared.loadTheme { color, image in
let userdefaults = UserDefaults.standard
if let color = color {
UserDefaults.standard.setValue(nil, forKey: "color")
UserDefaults.standard.setColor(color, forKey: "color")
userdefaults.setValue(nil, forKey: "color")
userdefaults.setValue(nil, forKey: "background")
userdefaults.setColor(color, forKey: "color")
} else if let image = image {
userdefaults.setValue(nil, forKey: "color")
userdefaults.setValue(nil, forKey: "background")
userdefaults.setValue(image.path, forKey: "background")
}
}
@ -130,3 +159,17 @@ func presentPomeloEmulation(PomeloGame: SudachiGame) {
rootViewController.present(PomeloEmulationController, animated: true, completion: nil)
}
}
struct NoBootOS: View {
let sudachi = Sudachi.shared
var body: some View {
VStack {
Text("Unable Launch Switch OS")
.font(.largeTitle)
.padding()
Text("You do not have the Switch Home Menu Files Needed to launch the Ηome Menu")
}
}
}

View File

@ -10,15 +10,38 @@ import SwiftUI
struct SettingsView: View {
@State var core: Core
@State var showprompt = false
@AppStorage("sidejitserver-enable-true") var sidejitserver: Bool = false
@AppStorage("sidejitserver-NavigationLink-true") var showAlert: Bool = false
@AppStorage("sidejitserver-ip-true") var ip: String = ""
@AppStorage("sidejitserver-udid-true") var udid: String = ""
@AppStorage("icon") var iconused = 1
var body: some View {
NavigationView {
NavigationStack {
ScrollView {
VStack(alignment: .leading) {
VStack {
Text("Welcome to Pomelo")
.font(.title)
VStack(alignment: .center) {
if iconused == 1 {
Image("AppIcon-inapp")
.resizable()
.frame(width: 200, height: 200)
.cornerRadius(20)
} else if iconused == 2 {
Image(.appIconSecondaryInapp)
.resizable()
.frame(width: 200, height: 200)
.cornerRadius(20)
} else {
Image(.appIconInvertedInapp)
.resizable()
.frame(width: 200, height: 200)
.cornerRadius(20)
}
.padding()
Text("Welcome To Pomelo")
.padding()
.font(.title)
}
.padding()
VStack(alignment: .leading) {
NavigationLink(destination: InfoView()) {
Rectangle()
@ -88,23 +111,55 @@ struct SettingsView: View {
.foregroundColor(.primary)
.padding()
} else {
NavigationLink(destination: SideJITServerSettings()) {
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
.cornerRadius(10) // Apply rounded corners
.frame(width: .infinity, height: 50) // Set the desired dimensions
.overlay() {
HStack {
Text("SideJITServer Settings")
.foregroundColor(.primary)
.padding()
Spacer()
}
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
.cornerRadius(10) // Apply rounded corners
.frame(width: .infinity, height: 50) // Set the desired dimensions
.overlay() {
Toggle(isOn: $sidejitserver) {
Text("SideJITServer")
}
.padding()
}
.padding()
if sidejitserver {
NavigationLink(destination: SideJITServerSettings()) {
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
.cornerRadius(10) // Apply rounded corners
.frame(width: .infinity, height: 50) // Set the desired dimensions
.overlay() {
HStack {
Text("SideJITServer Settings")
.foregroundColor(.primary)
.padding()
Spacer()
}
}
}
.padding()
}
.padding()
}
NavigationLink(destination: AppIconView()) {
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
.cornerRadius(10) // Apply rounded corners
.frame(width: .infinity, height: 50) // Set the desired dimensions
.overlay() {
HStack {
Text("App Icon")
.foregroundColor(.primary)
.padding()
Spacer()
}
}
}
.padding()
// NavigationLink(
NavigationLink(destination: AdvancedSettingsView()) {
Rectangle()
@ -140,6 +195,7 @@ struct SettingsView: View {
struct AdvancedSettingsView: View {
@AppStorage("isfullscreen") var isFullScreen: Bool = false
@AppStorage("exitgame") var exitgame: Bool = false
var body: some View {
ScrollView {
Rectangle()
@ -156,10 +212,91 @@ struct AdvancedSettingsView: View {
.padding(.bottom)
.font(.footnote)
.foregroundColor(.gray)
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
.cornerRadius(10) // Apply rounded corners
.frame(width: .infinity, height: 50) // Set the desired dimensions
.overlay() {
HStack {
Toggle("Exit Game Button", isOn: $exitgame)
.padding()
}
}
Text("This is very unstable and can lead to game freezing and overall bad preformance after you exit a game")
.padding(.bottom)
.font(.footnote)
.foregroundColor(.gray)
}
}
}
struct AppIconView: View {
let icons = ["AppIcon-1", "Appicon-Secondary", "Appicon-inverted"] // Replace with your icon names
@AppStorage("icon") var iconused = 1
var body: some View {
ScrollView {
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 16) {
ForEach(icons, id: \.self) { iconName in
Button {
if iconName == "AppIcon" {
iconused = 1
UIApplication.shared.setAlternateIconName(iconName) { error in
if let error = error {
print("fuck \(error.localizedDescription)")
}
}
} else if iconName == "Appicon-Secondary" {
iconused = 2
UIApplication.shared.setAlternateIconName(iconName) { error in
if let error = error {
print("fuck \(error.localizedDescription)")
}
}
} else {
UIApplication.shared.setAlternateIconName(iconName) { error in
if let error = error {
print("fuck \(error.localizedDescription)")
}
}
}
} label: {
VStack {
if iconName == "AppIcon-1" {
Image(.appIconInapp)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 80, height: 80) // Adjust size as needed
.clipShape(RoundedRectangle(cornerRadius: 16))
Text("Main App Icon")
} else if iconName == "Appicon-Secondary" {
Image(.appIconSecondaryInapp)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 80, height: 80) // Adjust size as needed
.clipShape(RoundedRectangle(cornerRadius: 16))
Text("Secondary App Icon")
} else if iconName == "Appicon-inverted" {
Image(.appIconInvertedInapp)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 80, height: 80) // Adjust size as needed
.clipShape(RoundedRectangle(cornerRadius: 16))
Text("Inverted Main App Icon")
}
}
}
}
}
}
.padding()
.navigationTitle("App Icons")
Spacer()
Text("All of these icons were generously made by ZxATHER")
.padding(.bottom)
.font(.footnote)
.foregroundColor(.gray)
}
}
// let userDefaults = UserDefaults.standard
// userDefaults.set(true, forKey: "isfullscreen")

View File

@ -34,6 +34,30 @@ public struct Sudachi {
sudachiObjC.bootOS()
}
public func pause() {
sudachiObjC.pause()
}
public func play() {
sudachiObjC.play()
}
public func togglepause() {
if sudachiObjC.ispaused() {
sudachiObjC.play()
} else {
sudachiObjC.pause()
}
}
public func ispaused() -> Bool {
return sudachiObjC.ispaused()
}
public func canGetFullPath() -> Bool {
return sudachiObjC.canGetFullPath()
}
public func bootOS1() {
sudachiObjC.quit()
}

View File

@ -314,7 +314,7 @@ Core::SystemResultStatus EmulationSession::BootOS() {
// Register an ExecuteProgram callback such that Core can execute a sub-program
m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
m_next_program_index = program_index_;
EmulationSession::GetInstance().HaltEmulation();
// EmulationSession::GetInstance().HaltEmulation();
});
OnEmulationStarted();

View File

@ -23,7 +23,7 @@ void EmulationWindow::OnSurfaceChanged(CA::MetalLayer* surface, CGSize size) {
m_window_height = size.height;
// Ensures that we emulate with the correct aspect ratio.
UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
// UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
window_info.render_surface = reinterpret_cast<void*>(surface);
window_info.render_surface_scale = [[UIScreen mainScreen] nativeScale];

View File

@ -50,6 +50,10 @@ typedef NS_ENUM(NSUInteger, VirtualControllerButtonType) {
+(SudachiObjC *) sharedInstance NS_SWIFT_NAME(shared());
-(void) configureLayer:(CAMetalLayer *)layer withSize:(CGSize)size NS_SWIFT_NAME(configure(layer:with:));
-(void) bootOS;
-(void) pause;
-(void) play;
-(BOOL) ispaused;
-(BOOL) canGetFullPath;
-(void) quit;
-(void) insertGame:(NSURL *)url NS_SWIFT_NAME(insert(game:));
-(void) insertGames:(NSArray<NSURL *> *)games NS_SWIFT_NAME(insert(games:));

View File

@ -14,6 +14,52 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/settings.h"
#include "common/fs/fs.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/savedata_factory.h"
#include "core/loader/nro.h"
#include "frontend_common/content_manager.h"
#include "common/detached_tasks.h"
#include "common/dynamic_library.h"
#include "common/fs/path_util.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_real.h"
#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general.h"
#include "core/frontend/applets/mii_edit.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "frontend_common/yuzu_config.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/vulkan_common/vulkan_instance.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#import <mach/mach.h>
@ -46,7 +92,49 @@
return sharedInstance;
}
- (BOOL)ispaused {
return EmulationSession::GetInstance().IsPaused();
}
-(void) pause {
EmulationSession::GetInstance().System().Pause();
void(EmulationSession::GetInstance().PauseEmulation());
}
-(void) play {
EmulationSession::GetInstance().System().Run();
void(EmulationSession::GetInstance().UnPauseEmulation());
}
- (BOOL)canGetFullPath {
@try {
Core::System& system = EmulationSession::GetInstance().System();
auto bis_system = system.GetFileSystemController().GetSystemNANDContents();
if (bis_system == nullptr) {
return NO;
}
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::QLaunch);
auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
if (qlaunch_applet_nca == nullptr) {
return NO;
}
const auto filename = qlaunch_applet_nca->GetFullPath();
// If GetFullPath() is successful
return YES;
} @catch (NSException *exception) {
// Handle the exception if needed
return NO;
}
}
-(void) quit {
EmulationSession::GetInstance().HaltEmulation();
EmulationSession::GetInstance().System().Exit();
void(EmulationSession::GetInstance().ShutdownEmulation());
}