diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs index 1d27efb05..1845f199d 100644 --- a/src/ARMeilleure/Translation/Cache/JitCache.cs +++ b/src/ARMeilleure/Translation/Cache/JitCache.cs @@ -15,11 +15,11 @@ namespace ARMeilleure.Translation.Cache static partial class JitCache { private static readonly int _pageSize = (int)MemoryBlock.GetPageSize(); - private static readonly int _pageMask = _pageSize - 1; + private static readonly int _pageMask = _pageSize - 2; private const int CodeAlignment = 4; // Bytes. private const int CacheSize = 2047 * 1024 * 1024; - private const int CacheSizeIOS = 128 * 1024 * 1024; + private const int CacheSizeIOS = 64 * 1024 * 1024; private static ReservedRegion _jitRegion; private static JitCacheInvalidation _jitCacheInvalidator; @@ -91,15 +91,7 @@ namespace ARMeilleure.Translation.Cache if (OperatingSystem.IsIOS()) { - // Marshal.Copy(code, 0, funcPtr, code.Length); - unsafe - { - fixed (byte* codePtr = code) - { - JitSupportDarwinAot.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length); - } - } - + Marshal.Copy(code, 0, funcPtr, code.Length); if (deferProtect) { _deferredRxProtect.Enqueue((funcOffset, code.Length)); diff --git a/src/ARMeilleure/Translation/TranslatorStubs.cs b/src/ARMeilleure/Translation/TranslatorStubs.cs index 77e850ee2..d80823a8b 100644 --- a/src/ARMeilleure/Translation/TranslatorStubs.cs +++ b/src/ARMeilleure/Translation/TranslatorStubs.cs @@ -60,6 +60,8 @@ namespace ARMeilleure.Translation { get { + ObjectDisposedException.ThrowIf(_disposed, this); + return _dispatchLoop.Value; } } diff --git a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj index fcf369e9f..21717bbdf 100644 --- a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj +++ b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj @@ -90,9 +90,6 @@ 5650564D2D2A75B300C8BB1E /* PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet */ = { isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet; attributesByRelativePath = { - "Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib" = ( - CodeSignOnCopy, - ); "Dependencies/Dynamic Libraries/SoftwareKeyboard.framework" = ( CodeSignOnCopy, RemoveHeadersOnCopy, @@ -152,7 +149,6 @@ "Dependencies/Dynamic Libraries/libavcodec.dylib", "Dependencies/Dynamic Libraries/libavutil.dylib", "Dependencies/Dynamic Libraries/libMoltenVK.dylib", - "Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib", "Dependencies/Dynamic Libraries/SoftwareKeyboard.framework", Dependencies/XCFrameworks/libavcodec.xcframework, Dependencies/XCFrameworks/libavfilter.xcframework, @@ -625,16 +621,6 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -811,12 +797,32 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Core/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Core/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Core/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = 0.0.8; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/Core/Headers/Ryujinx-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/App/Core/Headers/Ryujinx-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -841,16 +847,6 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", - "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = fast; GENERATE_INFOPLIST_FILE = YES; @@ -1027,12 +1023,32 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Core/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Core/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Core/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = 0.0.8; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/Core/Headers/Ryujinx-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/App/Core/Headers/Ryujinx-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index f5c700e80..ff54f4ed2 100644 Binary files a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate and b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/MeloNX/MeloNX/App/Core/Display/DisplayVisible.swift b/src/MeloNX/MeloNX/App/Core/Display/DisplayVisible.swift deleted file mode 100644 index 6f1f9242f..000000000 --- a/src/MeloNX/MeloNX/App/Core/Display/DisplayVisible.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Untitled.swift -// MeloNX -// -// Created by Stossy11 on 28/11/2024. -// - -import Foundation -import GameController -import UIKit - - - -var theWindow: UIWindow? = nil -extension UIWindow { - @objc func wdb_makeKeyAndVisible() { - if #available(iOS 13.0, *) { - self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene) - } - self.wdb_makeKeyAndVisible() - theWindow = self - - - if UserDefaults.standard.bool(forKey: "isVirtualController") { - if let window = theWindow { - - class LandscapeViewController: UIViewController { - override var supportedInterfaceOrientations: UIInterfaceOrientationMask { - return .landscape - } - - override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { - return .landscapeLeft - } - } - - let landscapeVC = LandscapeViewController() - landscapeVC.modalPresentationStyle = .fullScreen - theWindow?.rootViewController?.present(landscapeVC, animated: false, completion: nil) - waitforcontroller() - } - } - } -} - - -func patchMakeKeyAndVisible() { - let uiwindowClass = UIWindow.self - if let m1 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.makeKeyAndVisible)), - let m2 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.wdb_makeKeyAndVisible)) { - method_exchangeImplementations(m1, m2) - } -} - diff --git a/src/MeloNX/MeloNX/App/Core/Display/FPSDisplay/FPSMonitor.swift b/src/MeloNX/MeloNX/App/Core/Display/FPSDisplay/FPSMonitor.swift deleted file mode 100644 index bbd8bfae4..000000000 --- a/src/MeloNX/MeloNX/App/Core/Display/FPSDisplay/FPSMonitor.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// FPSMonitor.swift -// MeloNX -// -// Created by Stossy11 on 21/12/2024. -// - -import Foundation -import SwiftUI - -class FPSMonitor: ObservableObject { - @Published private(set) var currentFPS: UInt64 = 0 - private var timer: Timer? - - init() { - timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in - self?.updateFPS() - } - } - - deinit { - timer?.invalidate() - } - - private func updateFPS() { - let currentfps = UInt64(get_current_fps()) - - self.currentFPS = currentfps - } - - - func formatFPS() -> String { - let fps = Double(currentFPS) - let fpsString = String(format: "FPS: %.2f", fps) - - return fpsString - } -} - - - diff --git a/src/MeloNX/MeloNX/App/Core/Display/MemoryDisplay/MemoryUsageMonitor.swift b/src/MeloNX/MeloNX/App/Core/Display/MemoryDisplay/MemoryUsageMonitor.swift deleted file mode 100644 index 06070a38b..000000000 --- a/src/MeloNX/MeloNX/App/Core/Display/MemoryDisplay/MemoryUsageMonitor.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// MemoryUsageMonitor.swift -// MeloNX -// -// Created by Stossy11 on 21/12/2024. -// - -import Foundation -import SwiftUI - -class MemoryUsageMonitor: ObservableObject { - @Published private(set) var memoryUsage: UInt64 = 0 - private var timer: Timer? - - init() { - timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in - self?.updateMemoryUsage() - } - } - - deinit { - timer?.invalidate() - } - - private func updateMemoryUsage() { - var taskInfo = task_vm_info_data_t() - var count = mach_msg_type_number_t(MemoryLayout.size) / 4 - let result: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) { - $0.withMemoryRebound(to: integer_t.self, capacity: 1) { - task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count) - } - } - - if result == KERN_SUCCESS { - memoryUsage = taskInfo.phys_footprint - } - else { - print("Error with task_info(): " + - (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) - } - } - - func formatMemorySize(_ bytes: UInt64) -> String { - let formatter = ByteCountFormatter() - formatter.allowedUnits = [.useMB, .useGB] - formatter.countStyle = .memory - return formatter.string(fromByteCount: Int64(bytes)) - } - -} - - diff --git a/src/MeloNX/MeloNX/App/Core/Display/PerformanceDisplay/PerformanceOverlay.swift b/src/MeloNX/MeloNX/App/Core/Display/PerformanceDisplay/PerformanceOverlay.swift deleted file mode 100644 index ac014ff4a..000000000 --- a/src/MeloNX/MeloNX/App/Core/Display/PerformanceDisplay/PerformanceOverlay.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Untitled.swift -// MeloNX -// -// Created by Stossy11 on 21/12/2024. -// - -import SwiftUI - -struct PerformanceOverlayView: View { - @StateObject private var memorymonitor = MemoryUsageMonitor() - - @StateObject private var fpsmonitor = FPSMonitor() - - var body: some View { - VStack { - Text("\(fpsmonitor.formatFPS())") - Text(memorymonitor.formatMemorySize(memorymonitor.memoryUsage)) - } - } -} - diff --git a/src/MeloNX/MeloNX/App/Core/MetalHUD/MTLHUD.swift b/src/MeloNX/MeloNX/App/Core/MetalHUD/MTLHUD.swift deleted file mode 100644 index e89e9f6f4..000000000 --- a/src/MeloNX/MeloNX/App/Core/MetalHUD/MTLHUD.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// MTLHUD.swift -// MeloNX -// -// Created by Stossy11 on 26/11/2024. -// - -import Foundation - - -class MTLHud { - - var canMetalHud: Bool { - return openMetalDylib() - } - - var isEnabled: Bool { - if let getenv = getenv("MTL_HUD_ENABLED") { - return String(cString: getenv).contains("1") - } - return false - } - - static let shared = MTLHud() - - private init() { - openMetalDylib() - if UserDefaults.standard.bool(forKey: "MTL_HUD_ENABLED") { - enable() - } else { - disable() - } - } - - func openMetalDylib() -> Bool { - let path = "/usr/lib/libMTLHud.dylib" - - // Load the dynamic library - if dlopen(path, RTLD_NOW) != nil { - // Library loaded successfully - print("Library loaded from \(path)") - return true - } else { - // Handle error - if let error = String(validatingUTF8: dlerror()) { - print("Error loading library: \(error)") - } - return false - } - } - - - func enable() { - setenv("MTL_HUD_ENABLED", "1", 1) - } - - func disable() { - setenv("MTL_HUD_ENABLED", "0", 1) - } -} diff --git a/src/MeloNX/MeloNX/App/Views/ContentView.swift b/src/MeloNX/MeloNX/App/Views/ContentView.swift index 0fa635617..b6603d4c5 100644 --- a/src/MeloNX/MeloNX/App/Views/ContentView.swift +++ b/src/MeloNX/MeloNX/App/Views/ContentView.swift @@ -264,7 +264,7 @@ struct ContentView: View { if game.titleName.lowercased() != "super mario odyssey" { setting = (MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0")) } else { - setting = (MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "2")) + setting = (MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "1")) } setenv(setting.string, setting.value, 1) diff --git a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/libMoltenVK.dylib b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/libMoltenVK.dylib index 912e12d22..7e3092cd5 100755 Binary files a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/libMoltenVK.dylib and b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/libMoltenVK.dylib differ diff --git a/src/MeloNX/MeloNX/Dependencies/Ryujinx.Headless.SDL2.dylib b/src/MeloNX/MeloNX/Dependencies/Ryujinx.Headless.SDL2.dylib new file mode 100644 index 000000000..b24dd4f6b Binary files /dev/null and b/src/MeloNX/MeloNX/Dependencies/Ryujinx.Headless.SDL2.dylib differ diff --git a/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/Info.plist b/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/Info.plist index 19c99be01..2e0914e03 100644 Binary files a/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/Info.plist and b/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/Info.plist differ diff --git a/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/MoltenVK b/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/MoltenVK index 912e12d22..7e3092cd5 100755 Binary files a/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/MoltenVK and b/src/MeloNX/MeloNX/Dependencies/XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework/MoltenVK differ diff --git a/src/MeloNX/MeloNX/MeloNX.entitlements b/src/MeloNX/MeloNX/MeloNX.entitlements index aff1d9915..caa3d5839 100644 --- a/src/MeloNX/MeloNX/MeloNX.entitlements +++ b/src/MeloNX/MeloNX/MeloNX.entitlements @@ -4,8 +4,6 @@ com.apple.developer.kernel.extended-virtual-addressing - com.apple.developer.kernel.increased-debugging-memory-limit - com.apple.developer.kernel.increased-memory-limit diff --git a/src/MeloNX/MeloNX/Views/ContentView.swift b/src/MeloNX/MeloNX/Views/ContentView.swift deleted file mode 100644 index 0fa635617..000000000 --- a/src/MeloNX/MeloNX/Views/ContentView.swift +++ /dev/null @@ -1,309 +0,0 @@ -// -// ContentView.swift -// MeloNX -// -// Created by Stossy11 on 3/11/2024. -// - -import SwiftUI -// import SDL2 -import GameController -import Darwin -import UIKit -import MetalKit -// import SDL -import SoftwareKeyboard - -struct MoltenVKSettings: Codable, Hashable { - let string: String - var value: String -} - -struct ContentView: View { - // MARK: - Properties - @State private var theWindow: UIWindow? - @State private var game: Game? - @State private var controllersList: [Controller] = [] - @State private var currentControllers: [Controller] = [] - @State private var config: Ryujinx.Configuration - @State var settings: [MoltenVKSettings] - @AppStorage("useTrollStore") var useTrollStore: Bool = false - @State private var isVirtualControllerActive: Bool = false - @AppStorage("isVirtualController") var isVCA: Bool = true - @State var onscreencontroller: Controller = Controller(id: "", name: "") - @AppStorage("JIT") var isJITEnabled: Bool = false - @State var isMK8: Bool = false - @AppStorage("quit") var quit: Bool = false - - @State var quits: Bool = false - @State private var clumpOffset: CGFloat = -100 - private let clumpWidth: CGFloat = 100 - private let animationDuration: Double = 1.0 - @State private var isAnimating = false - @State var isLoading = true - - // MARK: - Initialization - init() { - let defaultConfig = loadSettings() ?? Ryujinx.Configuration(gamepath: "") - _config = State(initialValue: defaultConfig) - - let defaultSettings: [MoltenVKSettings] = [ - MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"), - MoltenVKSettings(string: "MVK_CONFIG_RESUME_LOST_DEVICE", value: "1") - ] - - _settings = State(initialValue: defaultSettings) - - print("JIT Enabled: \(isJITEnabled)") - - initializeSDL() - } - - // MARK: - Body - var body: some View { - if let game, quits == false { - if isLoading { - emulationView - .onAppear() { - Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in - timer.invalidate() - quits = quit - - if quits { - quit = false - timer.invalidate() - } - } - } - } else { - VStack { - - } - .onAppear() { - isAnimating = false - } - } - } else { - mainMenuView - .onAppear() { - quits = false - } - } - - } - - // MARK: - View Components - private var emulationView: some View { - GeometryReader { screenGeometry in - ZStack { - HStack(spacing: screenGeometry.size.width * 0.04) { - if let icon = game?.icon { - Image(uiImage: icon) - .resizable() - .frame( - width: min(screenGeometry.size.width * 0.25, 250), - height: min(screenGeometry.size.width * 0.25, 250) - ) - .clipShape(RoundedRectangle(cornerRadius: 16)) - .shadow(color: .black.opacity(0.5), radius: 10, x: 0, y: 5) - } - - VStack(alignment: .leading, spacing: screenGeometry.size.height * 0.015) { - Text("Loading \(game?.titleName ?? "Game")") - .font(.system(size: min(screenGeometry.size.width * 0.04, 32))) - .foregroundColor(.white) - - GeometryReader { geometry in - let containerWidth = min(screenGeometry.size.width * 0.35, 350) - - ZStack(alignment: .leading) { - // Background track - Rectangle() - .cornerRadius(10) - .frame(width: containerWidth, height: min(screenGeometry.size.height * 0.015, 12)) - .foregroundColor(.gray.opacity(0.3)) - .shadow(color: .black.opacity(0.2), radius: 4, x: 0, y: 2) - - // Animated loading bar - Rectangle() - .cornerRadius(10) - .frame(width: clumpWidth, height: min(screenGeometry.size.height * 0.015, 12)) - .foregroundColor(.blue) - .shadow(color: .blue.opacity(0.5), radius: 4, x: 0, y: 2) - .offset(x: isAnimating ? containerWidth : -clumpWidth) - .animation( - Animation.linear(duration: 1.0) - .repeatForever(autoreverses: false), - value: isAnimating - ) - } - .clipShape(RoundedRectangle(cornerRadius: 16)) - .onAppear { - isAnimating = true - - setupEmulation() - - - Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in - if get_current_fps() != 0 { - isLoading = false - isAnimating = false - timer.invalidate() - } - print(get_current_fps()) - } - } - } - .frame(height: min(screenGeometry.size.height * 0.015, 12)) - .frame(width: min(screenGeometry.size.width * 0.35, 350)) - } - } - .padding(.horizontal, screenGeometry.size.width * 0.06) - .padding(.vertical, screenGeometry.size.height * 0.05) - .position( - x: screenGeometry.size.width / 2, - y: screenGeometry.size.height * 0.5 - ) - } - } - } - - private var mainMenuView: some View { - MainTabView(startemu: $game, config: $config, MVKconfig: $settings, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller) - .onAppear() { - refreshControllersList() - - - let isJIT = UserDefaults.standard.bool(forKey: "JIT-ENABLED") - - if !isJIT, useTrollStore { - askForJIT() - } - - } - } - - // MARK: - Helper Methods - var SdlInitFlags: uint = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_VIDEO; - private func initializeSDL() { - setMoltenVKSettings() - SDL_SetMainReady() - SDL_iPhoneSetEventPump(SDL_TRUE) - SDL_Init(SdlInitFlags) - initialize() - } - - private func setupEmulation() { - patchMakeKeyAndVisible() - - if (currentControllers.first(where: { $0 == onscreencontroller }) != nil) { - - isVCA = true - - DispatchQueue.main.async { - start(displayid: 1) - } - - - } else { - isVCA = false - - DispatchQueue.main.async { - start(displayid: 1) - } - - - } - } - - private func refreshControllersList() { - controllersList = Ryujinx.shared.getConnectedControllers() - - if let onscreen = controllersList.first(where: { $0.name == Ryujinx.shared.virtualController.controllername }) { - self.onscreencontroller = onscreen - } - - controllersList.removeAll(where: { $0.id == "0"}) - - if controllersList.count > 2 { - let controller = controllersList[2] - currentControllers.append(controller) - } else if let controller = controllersList.first(where: { $0.id == onscreencontroller.id }), !controllersList.isEmpty { - currentControllers.append(controller) - } - } - - func showAlert(title: String, message: String, showOk: Bool, completion: @escaping (Bool) -> Void) { - DispatchQueue.main.async { - if let mainWindow = UIApplication.shared.windows.last { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - - if showOk { - let okAction = UIAlertAction(title: "OK", style: .default) { _ in - completion(true) - } - - alert.addAction(okAction) - } else { - completion(false) - } - - mainWindow.rootViewController?.present(alert, animated: true, completion: nil) - } - } - } - - - private func start(displayid: UInt32) { - guard let game else { return } - - config.gamepath = game.fileURL.path - config.inputids = Array(Set(currentControllers.map(\.id))) - var setting: MoltenVKSettings - - if game.titleName.lowercased() != "super mario odyssey" { - setting = (MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0")) - } else { - setting = (MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "2")) - } - setenv(setting.string, setting.value, 1) - - - - if config.inputids.isEmpty { - config.inputids.append("0") - } - - do { - try Ryujinx.shared.start(with: config) - } catch { - print("Error: \(error.localizedDescription)") - } - } - - - - - private func setMoltenVKSettings() { - - settings.forEach { setting in - setenv(setting.string, setting.value, 1) - } - } -} - -// MARK: - Helper Functions -func loadSettings() -> Ryujinx.Configuration? { - guard let jsonString = UserDefaults.standard.string(forKey: "config"), - let data = jsonString.data(using: .utf8) else { - return nil - } - - do { - return try JSONDecoder().decode(Ryujinx.Configuration.self, from: data) - } catch { - print("Failed to load settings: \(error)") - return nil - } -} - diff --git a/src/MeloNX/MeloNX/Views/ControllerView/ControllerView.swift b/src/MeloNX/MeloNX/Views/ControllerView/ControllerView.swift deleted file mode 100644 index 54b260e8f..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/ControllerView.swift +++ /dev/null @@ -1,304 +0,0 @@ -// -// ControllerView.swift -// Pomelo-V2 -// -// Created by Stossy11 on 16/7/2024. -// - -import SwiftUI -import GameController -import SwiftUIJoystick -import CoreMotion - -struct ControllerView: View { - - @AppStorage("performacehud") var performacehud: Bool = false - @AppStorage("quit") var quit: Bool = false - var body: some View { - GeometryReader { geometry in - if geometry.size.height > geometry.size.width && UIDevice.current.userInterfaceIdiom != .pad { - VStack { - if performacehud { - HStack { - - PerformanceOverlayView() - - Spacer() - - // Button("Stop emulation") { - // DispatchQueue.main.async { - // stop_emulation() - // quit = true - // } - // } - } - } - - - Spacer() - VStack { - HStack { - VStack { - ShoulderButtonsViewLeft() - ZStack { - Joystick() - DPadView() - } - } - .padding() - VStack { - ShoulderButtonsViewRight() - ZStack { - Joystick(iscool: true) // hope this works - ABXYView() - } - } - .padding() - } - - HStack { - ButtonView(button: .start) // Adding the + button - .padding(.horizontal, 40) - ButtonView(button: .back) // Adding the - button - .padding(.horizontal, 40) - } - } - .padding(.bottom, geometry.size.height / 3.2) // very broken - } - } else { - // could be landscape - VStack { - if performacehud { - HStack { - PerformanceOverlayView() - - Spacer() - - // Button("Stop emulation") { - // DispatchQueue.main.async { - // stop_emulation() - // quit = true - // } - // } - } - } - - - Spacer() - VStack { - HStack { - - // gotta fuckin add + and - now - VStack { - ShoulderButtonsViewLeft() - ZStack { - Joystick() - DPadView() - } - } - HStack { - // Spacer() - VStack { - // Spacer() - ButtonView(button: .back) // Adding the + button - } - Spacer() - VStack { - // Spacer() - ButtonView(button: .start) // Adding the - button - } - // Spacer() - } - VStack { - ShoulderButtonsViewRight() - ZStack { - Joystick(iscool: true) // hope this work s - ABXYView() - } - } - } - - } - // .padding(.bottom, geometry.size.height / 11) // also extremally broken ( - } - } - } - .padding() - } -} - -struct ShoulderButtonsViewLeft: View { - @State var width: CGFloat = 160 - @State var height: CGFloat = 20 - var body: some View { - HStack { - ButtonView(button: .leftTrigger) - .padding(.horizontal) - ButtonView(button: .leftShoulder) - .padding(.horizontal) - } - .frame(width: width, height: height) - .onAppear() { - if UIDevice.current.systemName.contains("iPadOS") { - width *= 1.2 - height *= 1.2 - } - } - } -} - -struct ShoulderButtonsViewRight: View { - @State var width: CGFloat = 160 - @State var height: CGFloat = 20 - var body: some View { - HStack { - ButtonView(button: .rightShoulder) - .padding(.horizontal) - ButtonView(button: .rightTrigger) - .padding(.horizontal) - } - .frame(width: width, height: height) - .onAppear() { - if UIDevice.current.systemName.contains("iPadOS") { - width *= 1.2 - height *= 1.2 - } - } - } -} - -struct DPadView: View { - @State var size: CGFloat = 145 - var body: some View { - VStack { - ButtonView(button: .dPadUp) - HStack { - ButtonView(button: .dPadLeft) - Spacer(minLength: 20) - ButtonView(button: .dPadRight) - } - ButtonView(button: .dPadDown) - .padding(.horizontal) - } - .frame(width: size, height: size) - .onAppear() { - if UIDevice.current.systemName.contains("iPadOS") { - size *= 1.2 - } - } - } -} - -struct ABXYView: View { - @State var size: CGFloat = 145 - var body: some View { - VStack { - ButtonView(button: .X) - HStack { - ButtonView(button: .Y) - Spacer(minLength: 20) - ButtonView(button: .A) - } - ButtonView(button: .B) - .padding(.horizontal) - } - .frame(width: size, height: size) - .onAppear() { - if UIDevice.current.systemName.contains("iPadOS") { - size *= 1.2 - } - } - } -} - -struct ButtonView: View { - var button: VirtualControllerButton - @State var width: CGFloat = 45 - @State var height: CGFloat = 45 - @State var isPressed = false - @AppStorage("onscreenhandheld") var onscreenjoy: Bool = false - @Environment(\.colorScheme) var colorScheme - @Environment(\.presentationMode) var presentationMode - - - - var body: some View { - Image(systemName: buttonText) - .resizable() - .frame(width: width, height: height) - .foregroundColor(colorScheme == .dark ? Color.gray : Color.gray) - .opacity(isPressed ? 0.4 : 0.7) - .gesture( - DragGesture(minimumDistance: 0) - .onChanged { _ in - if !self.isPressed { - self.isPressed = true - Ryujinx.shared.virtualController.setButtonState(1, for: button) - Haptics.shared.play(.heavy) - } - } - .onEnded { _ in - self.isPressed = false - Ryujinx.shared.virtualController.setButtonState(0, for: button) - } - ) - .onAppear() { - if button == .leftTrigger || button == .rightTrigger || button == .leftShoulder || button == .rightShoulder { - width = 65 - } - - - if button == .back || button == .start || button == .guide { - width = 35 - height = 35 - } - - if UIDevice.current.systemName.contains("iPadOS") { - width *= 1.2 - height *= 1.2 - } - } - } - - - - private var buttonText: String { - switch button { - case .A: - return "a.circle.fill" - case .B: - return "b.circle.fill" - case .X: - return "x.circle.fill" - case .Y: - return "y.circle.fill" - case .dPadUp: - return "arrowtriangle.up.circle.fill" - case .dPadDown: - return "arrowtriangle.down.circle.fill" - case .dPadLeft: - return "arrowtriangle.left.circle.fill" - case .dPadRight: - return "arrowtriangle.right.circle.fill" - case .leftTrigger: - return"zl.rectangle.roundedtop.fill" - case .rightTrigger: - return "zr.rectangle.roundedtop.fill" - case .leftShoulder: - return "l.rectangle.roundedbottom.fill" - case .rightShoulder: - return "r.rectangle.roundedbottom.fill" - case .start: - return "plus.circle.fill" // System symbol for + - case .back: - return "minus.circle.fill" // System symbol for - - case .guide: - return "house.circle.fill" - // This should be all the cases - default: - return "" - } - } -} - - diff --git a/src/MeloNX/MeloNX/Views/ControllerView/Haptics/Haptics.swift b/src/MeloNX/MeloNX/Views/ControllerView/Haptics/Haptics.swift deleted file mode 100644 index 5dd555815..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/Haptics/Haptics.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// Haptics.swift -// Pomelo -// -// Created by Stossy11 on 11/9/2024. -// Copyright © 2024 Stossy11. All rights reserved. -// - -import UIKit -import SwiftUI - -class Haptics { - static let shared = Haptics() - - private init() { } - - func play(_ feedbackStyle: UIImpactFeedbackGenerator.FeedbackStyle) { - print("haptics") - UIImpactFeedbackGenerator(style: feedbackStyle).impactOccurred() - } - - func notify(_ feedbackType: UINotificationFeedbackGenerator.FeedbackType) { - UINotificationFeedbackGenerator().notificationOccurred(feedbackType) - } -} - - diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/Contents.json b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164c9..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/Contents.json b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/Contents.json deleted file mode 100644 index 3a763d2f9..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "JoyStickBase@1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickBase@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickBase@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@1x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@1x.png deleted file mode 100644 index 2e3903652..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@1x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@2x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@2x.png deleted file mode 100644 index 49a14c122..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@2x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@3x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@3x.png deleted file mode 100644 index 35851e642..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultBase.imageset/JoyStickBase@3x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/Contents.json b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/Contents.json deleted file mode 100644 index 6c1bf409f..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "JoyStickHandle@1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickHandle@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickHandle@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@1x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@1x.png deleted file mode 100644 index d4555a959..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@1x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@2x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@2x.png deleted file mode 100644 index 93c135334..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@2x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@3x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@3x.png deleted file mode 100644 index 25e602e3f..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/DefaultHandle.imageset/JoyStickHandle@3x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/Contents.json b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/Contents.json deleted file mode 100644 index 6f901e4e8..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "JoyStickBaseCustom@1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickBaseCustom@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickBaseCustom@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@1x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@1x.png deleted file mode 100644 index 113ccadc4..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@1x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@2x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@2x.png deleted file mode 100644 index bbdf7e4cd..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@2x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@3x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@3x.png deleted file mode 100644 index 949788e5f..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyBase.imageset/JoyStickBaseCustom@3x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/Contents.json b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/Contents.json deleted file mode 100644 index 4091d8b19..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "JoyStickHandleCustom@1x.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickHandleCustom@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "JoyStickHandleCustom@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@1x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@1x.png deleted file mode 100644 index 9fb451158..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@1x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@2x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@2x.png deleted file mode 100644 index 2c0f0d930..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@2x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@3x.png b/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@3x.png deleted file mode 100644 index edc88f2ee..000000000 Binary files a/src/MeloNX/MeloNX/Views/ControllerView/JoyStickView/Resources/Assets.xcassets/FancyHandle.imageset/JoyStickHandleCustom@3x.png and /dev/null differ diff --git a/src/MeloNX/MeloNX/Views/ControllerView/Joystick/JoystickView.swift b/src/MeloNX/MeloNX/Views/ControllerView/Joystick/JoystickView.swift deleted file mode 100644 index dc1db3d8c..000000000 --- a/src/MeloNX/MeloNX/Views/ControllerView/Joystick/JoystickView.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// JoystickView.swift -// Pomelo -// -// Created by Stossy11 on 30/9/2024. -// Copyright © 2024 Stossy11. All rights reserved. -// - -import SwiftUI -import SwiftUIJoystick - -public struct Joystick: View { - @State var iscool: Bool? = nil - - @ObservedObject public var joystickMonitor = JoystickMonitor() - var dragDiameter: CGFloat { - var selfs = CGFloat(160) - if UIDevice.current.systemName.contains("iPadOS") { - return selfs * 1.2 - } - return selfs - } - private let shape: JoystickShape = .circle - - public var body: some View { - VStack{ - JoystickBuilder( - monitor: self.joystickMonitor, - width: self.dragDiameter, - shape: .circle, - background: { - Text("") - .hidden() - }, - foreground: { - Circle().fill(Color.gray) - .opacity(0.7) - }, - locksInPlace: false) - .onChange(of: self.joystickMonitor.xyPoint) { newValue in - let scaledX = Float(newValue.x) - let scaledY = Float(newValue.y) // my dumbass broke this by having -y instead of y :/ - print("Joystick Position: (\(scaledX), \(scaledY))") - - if iscool != nil { - Ryujinx.shared.virtualController.thumbstickMoved(.right, x: newValue.x, y: newValue.y) - } else { - Ryujinx.shared.virtualController.thumbstickMoved(.left, x: newValue.x, y: newValue.y) - } - } - } - } -} diff --git a/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift b/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift deleted file mode 100644 index 4d722d14d..000000000 --- a/src/MeloNX/MeloNX/Views/GamesList/GameListView.swift +++ /dev/null @@ -1,493 +0,0 @@ -// -// GameListView.swift -// MeloNX -// -// Created by Stossy11 on 3/11/2024. -// - -import SwiftUI -import UniformTypeIdentifiers - - -struct GameLibraryView: View { - @Binding var startemu: Game? - @State private var games: [Game] = [] - @State private var searchText = "" - @State private var isSearching = false - @AppStorage("recentGames") private var recentGamesData: Data = Data() - @State private var recentGames: [Game] = [] - @Environment(\.colorScheme) var colorScheme - @State var firmwareInstaller = false - @State var firmwareversion = "0" - @State var isImporting: Bool = false - @State var startgame = false - - - var filteredGames: [Game] { - if searchText.isEmpty { - return games - } - return games.filter { - $0.titleName.localizedCaseInsensitiveContains(searchText) || - $0.developer.localizedCaseInsensitiveContains(searchText) - } - } - - var body: some View { - iOSNav { - ScrollView { - LazyVStack(alignment: .leading, spacing: 20) { - if !isSearching { - Text("Games") - .font(.system(size: 34, weight: .bold)) - .padding(.horizontal) - .padding(.top, 12) - } - - if games.isEmpty { - VStack(spacing: 16) { - Image(systemName: "gamecontroller.fill") - .font(.system(size: 64)) - .foregroundColor(.secondary.opacity(0.7)) - .padding(.top, 60) - Text("No Games Found") - .font(.title2.bold()) - .foregroundColor(.primary) - Text("Add ROM, Keys and Firmware to get started") - .font(.subheadline) - .foregroundColor(.secondary) - } - .frame(maxWidth: .infinity) - .padding(.top, 40) - } else { - if !isSearching && !recentGames.isEmpty { - VStack(alignment: .leading, spacing: 12) { - Text("Recent") - .font(.title2.bold()) - .padding(.horizontal) - - ScrollView(.horizontal, showsIndicators: false) { - LazyHStack(spacing: 16) { - ForEach(recentGames) { game in - RecentGameCard(game: game, startemu: $startemu) - .onTapGesture { - addToRecentGames(game) - startemu = game - } - } - } - .padding(.horizontal) - } - } - - VStack(alignment: .leading, spacing: 12) { - Text("All Games") - .font(.title2.bold()) - .padding(.horizontal) - - LazyVStack(spacing: 2) { - ForEach(filteredGames) { game in - GameListRow(game: game, startemu: $startemu) - .onTapGesture { - addToRecentGames(game) - } - } - } - } - } else { - LazyVStack(spacing: 2) { - ForEach(filteredGames) { game in - GameListRow(game: game, startemu: $startemu) - .onTapGesture { - addToRecentGames(game) - } - } - } - } - } - } - .onAppear { - loadGames() - loadRecentGames() - - - let firmware = Ryujinx.shared.fetchFirmwareVersion() - firmwareversion = (firmware == "" ? "0" : firmware) - } - } - .toolbar { - ToolbarItem(placement: .topBarLeading) { - Menu { - - Text("Firmware Version: \(firmwareversion)") - .tint(.white) - - if firmwareversion == "0" { - Button { - firmwareInstaller.toggle() - } label: { - Text("Install Firmware") - } - - } else { - Button { - Ryujinx.shared.removeFirmware() - let firmware = Ryujinx.shared.fetchFirmwareVersion() - firmwareversion = (firmware == "" ? "0" : firmware) - } label: { - Text("Remove Firmware") - } - - - Button { - let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion) - - self.startemu = game - } label: { - Text("Mii Maker") - } - Button { - - isImporting.toggle() - } label: { - Text("Open game from system") - } - } - - Button { - let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! - let sharedurl = documentsUrl.absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://") - let furl = URL(string: sharedurl)! - if UIApplication.shared.canOpenURL(furl) { - UIApplication.shared.open(furl, options: [:]) - } - } label: { - Text("Show MeloNX Folder") - } - } label: { - Image(systemName: "ellipsis.circle") - .foregroundColor(.blue) - } - - } - } - } - .background(Color(.systemGroupedBackground)) - .searchable(text: $searchText) - .onChange(of: searchText) { _ in - isSearching = !searchText.isEmpty - } - .fileImporter(isPresented: $firmwareInstaller, allowedContentTypes: [.item]) { result in - switch result { - - case .success(let url): - - do { - - let fun = url.startAccessingSecurityScopedResource() - let path = url.path - - Ryujinx.shared.installFirmware(firmwarePath: path) - - firmwareversion = (Ryujinx.shared.fetchFirmwareVersion() == "" ? "0" : Ryujinx.shared.fetchFirmwareVersion()) - if fun { - url.stopAccessingSecurityScopedResource() - } - } - - case .failure(let error): - print(error) - } - } - .fileImporter(isPresented: $isImporting, allowedContentTypes: [.zip, .data]) { result in - switch result { - case .success(let url): - guard url.startAccessingSecurityScopedResource() else { - print("Failed to access security-scoped resource") - return - } - defer { url.stopAccessingSecurityScopedResource() } - - do { - let handle = try FileHandle(forReadingFrom: url) - let fileExtension = (url.pathExtension as NSString).utf8String - let extensionPtr = UnsafeMutablePointer(mutating: fileExtension) - - var gameInfo = get_game_info(handle.fileDescriptor, extensionPtr) - - var game = Game(containerFolder: url.deletingLastPathComponent(), fileType: .item, fileURL: url, titleName: "", titleId: "", developer: "", version: "") - - game.titleName = withUnsafePointer(to: &gameInfo.TitleName) { - $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) { - String(cString: $0) - } - } - - game.developer = withUnsafePointer(to: &gameInfo.Developer) { - $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) { - String(cString: $0) - } - } - - game.titleId = String(gameInfo.TitleId) - - print(String(gameInfo.TitleId)) - - - game.version = String(gameInfo.Version) - - game.icon = game.createImage(from: gameInfo) - - - DispatchQueue.main.async { - startemu = game - } - } catch { - print(error) - } - - - case .failure(let err): - print("File import failed: \(err.localizedDescription)") - } - } - - - } - - - private func addToRecentGames(_ game: Game) { - recentGames.removeAll { $0.id == game.id } - - recentGames.insert(game, at: 0) - - if recentGames.count > 5 { - recentGames = Array(recentGames.prefix(5)) - } - - saveRecentGames() - } - - private func saveRecentGames() { - do { - let encoder = JSONEncoder() - let data = try encoder.encode(recentGames) - recentGamesData = data - } catch { - print("Error saving recent games: \(error)") - } - } - - private func loadRecentGames() { - do { - let decoder = JSONDecoder() - recentGames = try decoder.decode([Game].self, from: recentGamesData) - } catch { - print("Error loading recent games: \(error)") - recentGames = [] - } - } - - private func loadGames() { - let fileManager = FileManager.default - guard let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return } - - let romsDirectory = documentsDirectory.appendingPathComponent("roms") - - // Check if "roms" folder exists; if not, create it - if !fileManager.fileExists(atPath: romsDirectory.path) { - do { - try fileManager.createDirectory(at: romsDirectory, withIntermediateDirectories: true, attributes: nil) - } catch { - print("Failed to create roms directory: \(error)") - } - } - games = [] - // Load games only from "roms" folder - do { - let files = try fileManager.contentsOfDirectory(at: romsDirectory, includingPropertiesForKeys: nil) - - files.forEach { fileURLCandidate in - do { - let handle = try FileHandle(forReadingFrom: fileURLCandidate) - let fileExtension = (fileURLCandidate.pathExtension as NSString).utf8String - let extensionPtr = UnsafeMutablePointer(mutating: fileExtension) - - var gameInfo = get_game_info(handle.fileDescriptor, extensionPtr) - - var game = Game(containerFolder: romsDirectory, fileType: .item, fileURL: fileURLCandidate, titleName: "", titleId: "", developer: "", version: "") - - game.titleName = withUnsafePointer(to: &gameInfo.TitleName) { - $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) { - String(cString: $0) - } - } - - game.developer = withUnsafePointer(to: &gameInfo.Developer) { - $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) { - String(cString: $0) - } - } - - game.titleId = String(gameInfo.TitleId) - - - game.version = String(gameInfo.Version) - - game.icon = game.createImage(from: gameInfo) - - - games.append(game) - } catch { - print(error) - } - } - - } catch { - print("Error loading games from roms folder: \(error)") - } - } -} - -extension Game: Codable { - enum CodingKeys: String, CodingKey { - case titleName, titleId, developer, version, fileURL - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - titleName = try container.decode(String.self, forKey: .titleName) - titleId = try container.decode(String.self, forKey: .titleId) - developer = try container.decode(String.self, forKey: .developer) - version = try container.decode(String.self, forKey: .version) - fileURL = try container.decode(URL.self, forKey: .fileURL) - - // Initialize other properties - self.containerFolder = fileURL.deletingLastPathComponent() - self.fileType = .item - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(titleName, forKey: .titleName) - try container.encode(titleId, forKey: .titleId) - try container.encode(developer, forKey: .developer) - try container.encode(version, forKey: .version) - try container.encode(fileURL, forKey: .fileURL) - } -} - -struct RecentGameCard: View { - let game: Game - @Binding var startemu: Game? - @Environment(\.colorScheme) var colorScheme - - var body: some View { - Button(action: { - startemu = game - }) { - VStack(alignment: .leading, spacing: 8) { - if let icon = game.icon { - Image(uiImage: icon) - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: 140, height: 140) - .cornerRadius(12) - } else { - ZStack { - RoundedRectangle(cornerRadius: 12) - .fill(colorScheme == .dark ? - Color(.systemGray5) : Color(.systemGray6)) - .frame(width: 140, height: 140) - - Image(systemName: "gamecontroller.fill") - .font(.system(size: 40)) - .foregroundColor(.gray) - } - } - - VStack(alignment: .leading, spacing: 2) { - Text(game.titleName) - .font(.subheadline.bold()) - .lineLimit(1) - - Text(game.developer) - .font(.caption) - .foregroundColor(.secondary) - .lineLimit(1) - } - .padding(.horizontal, 4) - } - } - .buttonStyle(.plain) - } -} - -struct GameListRow: View { - let game: Game - @Binding var startemu: Game? - @Environment(\.colorScheme) var colorScheme - - var body: some View { - Button(action: { - startemu = game - }) { - HStack(spacing: 16) { - // Game Icon - if let icon = game.icon { - Image(uiImage: icon) - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: 45, height: 45) - .cornerRadius(8) - } else { - ZStack { - RoundedRectangle(cornerRadius: 8) - .fill(colorScheme == .dark ? - Color(.systemGray5) : Color(.systemGray6)) - .frame(width: 45, height: 45) - - Image(systemName: "gamecontroller.fill") - .font(.system(size: 20)) - .foregroundColor(.gray) - } - } - - // Game Info - VStack(alignment: .leading, spacing: 2) { - Text(game.titleName) - .font(.body) - .foregroundColor(.primary) - - Text(game.developer) - .font(.subheadline) - .foregroundColor(.secondary) - } - - Spacer() - - Image(systemName: "play.circle.fill") - .font(.title2) - .foregroundColor(.accentColor) - .opacity(0.8) - } - .padding(.horizontal) - .padding(.vertical, 8) - .background(Color(.systemBackground)) - .contextMenu { - Button { - startemu = game - } label: { - Label("Play Now", systemImage: "play.fill") - } - - Button { - // Add info action - } label: { - Label("Game Info", systemImage: "info.circle") - } - } - } - .buttonStyle(.plain) - } -} diff --git a/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift b/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift deleted file mode 100644 index 838f227fc..000000000 --- a/src/MeloNX/MeloNX/Views/SettingsView/SettingsView.swift +++ /dev/null @@ -1,430 +0,0 @@ -// -// SettingsView.swift -// MeloNX -// -// Created by Stossy11 on 25/11/2024. -// - -import SwiftUI -import SwiftSVG - -struct SettingsView: View { - @Binding var config: Ryujinx.Configuration - @Binding var MoltenVKSettings: [MoltenVKSettings] - - @Binding var controllersList: [Controller] - @Binding var currentControllers: [Controller] - - @Binding var onscreencontroller: Controller - @AppStorage("useTrollStore") var useTrollStore: Bool = false - - @AppStorage("ignoreJIT") var ignoreJIT: Bool = false - - var memoryManagerModes = [ - ("HostMapped", "Host (fast)"), - ("HostMappedUnsafe", "Host Unchecked (fast, unstable / unsafe)"), - ("SoftwarePageTable", "Software (slow)"), - ] - - @AppStorage("RyuDemoControls") var ryuDemo: Bool = false - @AppStorage("MTL_HUD_ENABLED") var metalHUDEnabled: Bool = false - - @AppStorage("performacehud") var performacehud: Bool = false - - @State private var showResolutionInfo = false - @State private var searchText = "" - - var filteredMemoryModes: [(String, String)] { - guard !searchText.isEmpty else { return memoryManagerModes } - return memoryManagerModes.filter { $0.1.localizedCaseInsensitiveContains(searchText) } - } - - var body: some View { - iOSNav { - List { - - - // Graphics & Performance - Section { - Toggle(isOn: $config.fullscreen) { - labelWithIcon("Fullscreen", iconName: "rectangle.expand.vertical") - } - .tint(.blue) - - Toggle(isOn: $config.disableShaderCache) { - labelWithIcon("Shader Cache", iconName: "memorychip") - } - .tint(.blue) - - Toggle(isOn: $config.enableTextureRecompression) { - labelWithIcon("Texture Recompression", iconName: "rectangle.compress.vertical") - } - .tint(.blue) - - Toggle(isOn: $config.disableDockedMode) { - labelWithIcon("Docked Mode", iconName: "dock.rectangle") - } - .tint(.blue) - - VStack(alignment: .leading, spacing: 10) { - HStack { - labelWithIcon("Resolution Scale", iconName: "magnifyingglass") - .font(.headline) - Spacer() - Button { - showResolutionInfo.toggle() - } label: { - Image(systemName: "info.circle") - .symbolRenderingMode(.hierarchical) - .foregroundStyle(.secondary) - } - .buttonStyle(.plain) - .help("Learn more about Resolution Scale") - .alert(isPresented: $showResolutionInfo) { - Alert( - title: Text("Resolution Scale"), - message: Text("Adjust the internal rendering resolution. Higher values improve visuals but may reduce performance."), - dismissButton: .default(Text("OK")) - ) - } - } - - Slider(value: $config.resscale, in: 0.1...3.0, step: 0.1) { - Text("Resolution Scale") - } minimumValueLabel: { - Text("0.1x") - .font(.footnote) - .foregroundColor(.secondary) - } maximumValueLabel: { - Text("3.0x") - .font(.footnote) - .foregroundColor(.secondary) - } - Text("\(config.resscale, specifier: "%.2f")x") - .font(.subheadline) - .foregroundColor(.secondary) - } - .padding(.vertical, 8) - - Toggle(isOn: $performacehud) { - labelWithIcon("Performance Overlay", iconName: "speedometer") - } - .tint(.blue) - } header: { - Text("Graphics & Performance") - .font(.title3.weight(.semibold)) - .textCase(nil) - .headerProminence(.increased) - } footer: { - Text("Fine-tune graphics and performance to suit your device and preferences.") - } - - // Input Selector - Section { - if !controllersList.filter({ !currentControllers.contains($0) }).isEmpty { - DisclosureGroup("Unselected Controllers") { - ForEach(controllersList.filter { !currentControllers.contains($0) }) { controller in - var customBinding: Binding { - Binding( - get: { currentControllers.contains(controller) }, - set: { bool in - if !bool { - currentControllers.removeAll(where: { $0.id == controller.id }) - } else { - currentControllers.append(controller) - } - } - ) - } - - Toggle(isOn: customBinding) { - Text(controller.name) - .font(.body) - } - .tint(.blue) - } - } - } - - - - ForEach(controllersList) { controller in - - var customBinding: Binding { - Binding( - get: { currentControllers.contains(controller) }, - set: { bool in - if !bool { - currentControllers.removeAll(where: { $0.id == controller.id }) - } else { - currentControllers.append(controller) - } - // toggleController(controller) - } - ) - } - - - if customBinding.wrappedValue { - DisclosureGroup { - Toggle(isOn: customBinding) { - Text(controller.name) - .font(.body) - } - .tint(.blue) - } label: { - let controller = String((controllersList.firstIndex(where: { $0.id == controller.id }) ?? 0) + 1) - - - Text("Player \(controller)") - } - - } - } - } header: { - Text("Input Selector") - .font(.title3.weight(.semibold)) - .textCase(nil) - .headerProminence(.increased) - } footer: { - Text("Select input devices and on-screen controls to play with. ") - } - - // Input Settings - Section { - - Toggle(isOn: $config.listinputids) { - labelWithIcon("List Input IDs", iconName: "list.bullet") - } - .tint(.blue) - - Toggle(isOn: $ryuDemo) { - labelWithIcon("On-Screen Controller (Demo)", iconName: "hand.draw") - } - .tint(.blue) - .disabled(true) - } header: { - Text("Input Settings") - .font(.title3.weight(.semibold)) - .textCase(nil) - .headerProminence(.increased) - } footer: { - Text("Configure input devices and on-screen controls for easier navigation and play.") - } - - // CPU Mode - Section { - if filteredMemoryModes.isEmpty { - Text("No matches for \"\(searchText)\"") - .foregroundColor(.secondary) - } else { - Picker(selection: $config.memoryManagerMode) { - ForEach(filteredMemoryModes, id: \.0) { key, displayName in - Text(displayName).tag(key) - } - } label: { - labelWithIcon("Memory Manager Mode", iconName: "gearshape") - } - } - } header: { - Text("CPU Mode") - .font(.title3.weight(.semibold)) - .textCase(nil) - .headerProminence(.increased) - } footer: { - Text("Select how memory is managed. 'Host (fast)' is best for most users.") - } - - - // Other Settings - Section { - - Toggle(isOn: $useTrollStore) { - labelWithIcon("TrollStore", iconName: "troll.svg") - } - .tint(.blue) - - Toggle(isOn: $config.debuglogs) { - labelWithIcon("Debug Logs", iconName: "exclamationmark.bubble") - } - .tint(.blue) - - Toggle(isOn: $config.tracelogs) { - labelWithIcon("Trace Logs", iconName: "waveform.path") - } - .tint(.blue) - } header: { - Text("Miscellaneous Options") - .font(.title3.weight(.semibold)) - .textCase(nil) - .headerProminence(.increased) - } footer: { - Text("Enable logs for troubleshooting and Enable automatic TrollStore JIT.") - } - - // Advanced - Section { - DisclosureGroup { - - HStack { - labelWithIcon("Page Size", iconName: "textformat.size") - Spacer() - Text("\(String(Int(getpagesize())))") - .foregroundColor(.secondary) - - } - - TextField("Additional Arguments", text: Binding( - get: { - config.additionalArgs.joined(separator: " ") - }, - set: { newValue in - config.additionalArgs = newValue - .split(separator: ",") - .map { $0.trimmingCharacters(in: .whitespaces) } - } - )) - .textInputAutocapitalization(.none) - .disableAutocorrection(true) - - - Button { - Ryujinx.shared.removeFirmware() - - } label: { - Text("Remove Firmware") - .font(.body) - } - } label: { - Text("Advanced Options") - } - } header: { - Text("Advanced") - .font(.title3.weight(.semibold)) - .textCase(nil) - .headerProminence(.increased) - } footer: { - Text("For advanced users. See page size or add custom arguments for experimental features. (Please don't touch this if you don't know what you're doing)") - } - - } - .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always)) - .navigationTitle("Settings") - .navigationBarTitleDisplayMode(.inline) - .listStyle(.insetGrouped) - .onAppear { - if let configs = loadSettings() { - self.config = configs - } - } - .onChange(of: config) { _ in - saveSettings() - } - } - .navigationViewStyle(.stack) - } - - private func toggleController(_ controller: Controller) { - if currentControllers.contains(where: { $0.id == controller.id }) { - currentControllers.removeAll(where: { $0.id == controller.id }) - } else { - currentControllers.append(controller) - } - } - - func saveSettings() { -#if targetEnvironment(simulator) - - print("Saving Settings") -#else - do { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - let data = try encoder.encode(config) - let jsonString = String(data: data, encoding: .utf8) - UserDefaults.standard.set(jsonString, forKey: "config") - } catch { - print("Failed to save settings: \(error)") - } -#endif - } - - // Original loadSettings function assumed to exist - func loadSettings() -> Ryujinx.Configuration? { - -#if targetEnvironment(simulator) - print("Running on Simulator") - - return Ryujinx.Configuration(gamepath: "") -#else - guard let jsonString = UserDefaults.standard.string(forKey: "config"), - let data = jsonString.data(using: .utf8) else { - return nil - } - do { - let decoder = JSONDecoder() - let configs = try decoder.decode(Ryujinx.Configuration.self, from: data) - return configs - } catch { - print("Failed to load settings: \(error)") - return nil - } -#endif - } - - @ViewBuilder - private func labelWithIcon(_ text: String, iconName: String, flipimage: Bool? = nil) -> some View { - HStack(spacing: 8) { - if iconName.hasSuffix(".svg"){ - if let flipimage, flipimage { - SVGView(svgName: iconName, color: .blue) - .symbolRenderingMode(.hierarchical) - .frame(width: 20, height: 20) - .rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0)) - } else { - SVGView(svgName: iconName, color: .blue) - .symbolRenderingMode(.hierarchical) - .frame(width: 20, height: 20) - } - } else if !iconName.isEmpty { - Image(systemName: iconName) - .symbolRenderingMode(.hierarchical) - .foregroundStyle(.blue) - } - Text(text) - } - .font(.body) - } -} - - -struct SVGView: UIViewRepresentable { - var svgName: String - var color: Color = Color.black - - func makeUIView(context: Context) -> UIView { - var svgName = svgName - var hammock = UIView() - - if svgName.hasSuffix(".svg") { - svgName.removeLast(4) - } - - - - let svgLayer = UIView(SVGNamed: svgName) { svgLayer in - svgLayer.fillColor = UIColor(color).cgColor // Apply the provided color - svgLayer.resizeToFit(hammock.frame) - hammock.layer.addSublayer(svgLayer) - } - - return hammock - } - - func updateUIView(_ uiView: UIView, context: Context) { - // Update the SVG view's fill color when the color changes - if let svgLayer = uiView.layer.sublayers?.first as? CAShapeLayer { - svgLayer.fillColor = UIColor(color).cgColor - } - } -} diff --git a/src/MeloNX/MeloNX/Views/TabView/TabView.swift b/src/MeloNX/MeloNX/Views/TabView/TabView.swift deleted file mode 100644 index ccf7796bc..000000000 --- a/src/MeloNX/MeloNX/Views/TabView/TabView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// TabView.swift -// MeloNX -// -// Created by Stossy11 on 10/12/2024. -// - -import SwiftUI -import UniformTypeIdentifiers - - -struct MainTabView: View { - @Binding var startemu: Game? - @Binding var config: Ryujinx.Configuration - @Binding var MVKconfig: [MoltenVKSettings] - @Binding var controllersList: [Controller] - @Binding var currentControllers: [Controller] - - @Binding var onscreencontroller: Controller - - var body: some View { - TabView { - GameLibraryView(startemu: $startemu) - .tabItem { - Label("Games", systemImage: "gamecontroller.fill") - } - - SettingsView(config: $config, MoltenVKSettings: $MVKconfig, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller) - .tabItem { - Label("Settings", systemImage: "gear") - } - } - } -} diff --git a/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs b/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs index a8a21d146..914712bb1 100644 --- a/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs +++ b/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs @@ -66,6 +66,8 @@ namespace Ryujinx.Cpu.LightningJit { get { + ObjectDisposedException.ThrowIf(_disposed, this); + return _dispatchLoop.Value; } }