a bunch of changes

This commit is contained in:
Stossy11 2025-02-16 12:16:54 +11:00
parent 802a8d7bae
commit f95281899c
19 changed files with 340 additions and 36 deletions

View File

@ -25,6 +25,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */ = {isa = PBXBuildFile; productRef = 4E0DED332D05695D00FEF007 /* SwiftUIJoystick */; }; 4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */ = {isa = PBXBuildFile; productRef = 4E0DED332D05695D00FEF007 /* SwiftUIJoystick */; };
4E8A80772D5FDD2D0041B48F /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; };
4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */ = {isa = PBXBuildFile; productRef = 4EA5AE812D16807500AD0B9F /* SwiftSVG */; }; 4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */ = {isa = PBXBuildFile; productRef = 4EA5AE812D16807500AD0B9F /* SwiftSVG */; };
CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; }; CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -197,6 +198,7 @@
4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */, 4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */,
CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */, CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */,
4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */, 4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */,
4E8A80772D5FDD2D0041B48F /* GameController.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -656,10 +658,15 @@
"$(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; GCC_OPTIMIZATION_LEVEL = fast;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MeloNX/Info.plist; INFOPLIST_FILE = MeloNX/Info.plist;
INFOPLIST_KEY_GCSupportsControllerUserInteraction = YES;
INFOPLIST_KEY_GCSupportsGameMode = YES; INFOPLIST_KEY_GCSupportsGameMode = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games";
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
@ -670,7 +677,7 @@
INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_UISupportsDocumentBrowser = YES; INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -710,6 +717,14 @@
"$(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",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
MARKETING_VERSION = 1.1.0; MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
@ -755,10 +770,15 @@
"$(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; GCC_OPTIMIZATION_LEVEL = fast;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MeloNX/Info.plist; INFOPLIST_FILE = MeloNX/Info.plist;
INFOPLIST_KEY_GCSupportsControllerUserInteraction = YES;
INFOPLIST_KEY_GCSupportsGameMode = YES; INFOPLIST_KEY_GCSupportsGameMode = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.games";
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
@ -769,7 +789,7 @@
INFOPLIST_KEY_UIRequiresFullScreen = YES; INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
INFOPLIST_KEY_UISupportsDocumentBrowser = YES; INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -809,6 +829,14 @@
"$(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",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
MARKETING_VERSION = 1.1.0; MARKETING_VERSION = 1.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;

View File

@ -12,12 +12,12 @@
<key>Ryujinx.xcscheme_^#shared#^_</key> <key>Ryujinx.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>3</integer> <integer>2</integer>
</dict> </dict>
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key> <key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>4</integer> <integer>1</integer>
</dict> </dict>
</dict> </dict>
<key>SuppressBuildableAutocreation</key> <key>SuppressBuildableAutocreation</key>

View File

@ -0,0 +1,58 @@
//
// EntitlementChecker.swift
// MeloNX
//
// Created by Stossy11 on 15/02/2025.
//
import Foundation
import Security
typealias SecTaskRef = OpaquePointer
@_silgen_name("SecTaskCopyValueForEntitlement")
func SecTaskCopyValueForEntitlement(
_ task: SecTaskRef,
_ entitlement: NSString,
_ error: NSErrorPointer
) -> CFTypeRef?
@_silgen_name("SecTaskCreateFromSelf")
func SecTaskCreateFromSelf(
_ allocator: CFAllocator?
) -> SecTaskRef?
@_silgen_name("SecTaskCopyValuesForEntitlements")
func SecTaskCopyValuesForEntitlements(
_ task: SecTaskRef,
_ entitlements: CFArray,
_ error: UnsafeMutablePointer<Unmanaged<CFError>?>?
) -> CFDictionary?
func checkAppEntitlements(_ ents: [String]) -> [String: Any]? {
guard let task = SecTaskCreateFromSelf(nil) else {
print("Failed to create SecTask")
return nil
}
guard let entitlements = SecTaskCopyValuesForEntitlements(task, ents as CFArray, nil) else {
print("Failed to get entitlements")
return nil
}
return entitlements as? [String: Any]
}
func checkAppEntitlement(_ ent: String) -> Bool? {
guard let task = SecTaskCreateFromSelf(nil) else {
print("Failed to create SecTask")
return nil
}
guard let entitlements = SecTaskCopyValueForEntitlement(task, ent as NSString, nil) else {
print("Failed to get entitlements")
return nil
}
return entitlements.boolValue != nil && entitlements.boolValue
}

View File

@ -0,0 +1,28 @@
//
// AspectRatio.swift
// MeloNX
//
// Created by Stossy11 on 16/02/2025.
//
import Foundation
public enum AspectRatio: String, Codable, CaseIterable {
case fixed4x3 = "Fixed4x3"
case fixed16x9 = "Fixed16x9"
case fixed16x10 = "Fixed16x10"
case fixed21x9 = "Fixed21x9"
case fixed32x9 = "Fixed32x9"
case stretched = "Stretched"
var displayName: String {
switch self {
case .fixed4x3: return "4:3"
case .fixed16x9: return "16:9 (Default)"
case .fixed16x10: return "16:10"
case .fixed21x9: return "21:9"
case .fixed32x9: return "32:9"
case .stretched: return "Stretched (Full Screen)"
}
}
}

View File

@ -0,0 +1,52 @@
//
// Language.swift
// MeloNX
//
// Created by Stossy11 on 16/02/2025.
//
import Foundation
public enum SystemLanguage: String, Codable, CaseIterable {
case japanese = "Japanese"
case americanEnglish = "AmericanEnglish"
case french = "French"
case german = "German"
case italian = "Italian"
case spanish = "Spanish"
case chinese = "Chinese"
case korean = "Korean"
case dutch = "Dutch"
case portuguese = "Portuguese"
case russian = "Russian"
case taiwanese = "Taiwanese"
case britishEnglish = "BritishEnglish"
case canadianFrench = "CanadianFrench"
case latinAmericanSpanish = "LatinAmericanSpanish"
case simplifiedChinese = "SimplifiedChinese"
case traditionalChinese = "TraditionalChinese"
case brazilianPortuguese = "BrazilianPortuguese"
var displayName: String {
switch self {
case .japanese: return "Japanese"
case .americanEnglish: return "American English"
case .french: return "French"
case .german: return "German"
case .italian: return "Italian"
case .spanish: return "Spanish"
case .chinese: return "Chinese"
case .korean: return "Korean"
case .dutch: return "Dutch"
case .portuguese: return "Portuguese"
case .russian: return "Russian"
case .taiwanese: return "Taiwanese"
case .britishEnglish: return "British English"
case .canadianFrench: return "Canadian French"
case .latinAmericanSpanish: return "Latin American Spanish"
case .simplifiedChinese: return "Simplified Chinese"
case .traditionalChinese: return "Traditional Chinese"
case .brazilianPortuguese: return "Brazilian Portuguese"
}
}
}

View File

@ -0,0 +1,31 @@
//
// Region.swift
// MeloNX
//
// Created by Stossy11 on 16/02/2025.
//
import Foundation
public enum SystemRegionCode: String, Codable, CaseIterable {
case japan = "Japan"
case usa = "USA"
case europe = "Europe"
case australia = "Australia"
case china = "China"
case korea = "Korea"
case taiwan = "Taiwan"
var displayName: String {
switch self {
case .japan: return "Japan"
case .usa: return "United States"
case .europe: return "Europe"
case .australia: return "Australia"
case .china: return "China"
case .korea: return "Korea"
case .taiwan: return "Taiwan"
}
}
}

View File

@ -28,26 +28,6 @@ struct iOSNav<Content: View>: View {
} }
} }
public enum AspectRatio: String, Codable, CaseIterable {
case fixed4x3 = "Fixed4x3"
case fixed16x9 = "Fixed16x9"
case fixed16x10 = "Fixed16x10"
case fixed21x9 = "Fixed21x9"
case fixed32x9 = "Fixed32x9"
case stretched = "Stretched"
var displayName: String {
switch self {
case .fixed4x3: return "4:3"
case .fixed16x9: return "16:9 (Default)"
case .fixed16x10: return "16:10"
case .fixed21x9: return "21:9"
case .fixed32x9: return "32:9"
case .stretched: return "Stretched (Full Screen)"
}
}
}
class Ryujinx { class Ryujinx {
private var isRunning = false private var isRunning = false
@ -60,6 +40,8 @@ class Ryujinx {
@Published var emulationUIView = UIView() @Published var emulationUIView = UIView()
@Published var games: [Game] = [] @Published var games: [Game] = []
@Published var defMLContentSize: CGFloat?
var shouldMetal: Bool { var shouldMetal: Bool {
metalLayer == nil metalLayer == nil
} }
@ -93,6 +75,8 @@ class Ryujinx {
var dfsIntegrityChecks: Bool var dfsIntegrityChecks: Bool
var disablePTC: Bool var disablePTC: Bool
var disablevsync: Bool var disablevsync: Bool
var language: SystemLanguage
var regioncode: SystemRegionCode
init(gamepath: String, init(gamepath: String,
@ -116,7 +100,9 @@ class Ryujinx {
expandRam: Bool = false, expandRam: Bool = false,
dfsIntegrityChecks: Bool = false, dfsIntegrityChecks: Bool = false,
disablePTC: Bool = false, disablePTC: Bool = false,
disablevsync: Bool = false disablevsync: Bool = false,
language: SystemLanguage = .americanEnglish,
regioncode: SystemRegionCode = .usa
) { ) {
self.gamepath = gamepath self.gamepath = gamepath
self.inputids = inputids self.inputids = inputids
@ -140,6 +126,8 @@ class Ryujinx {
self.dfsIntegrityChecks = dfsIntegrityChecks self.dfsIntegrityChecks = dfsIntegrityChecks
self.disablePTC = disablePTC self.disablePTC = disablePTC
self.disablevsync = disablevsync self.disablevsync = disablevsync
self.language = language
self.regioncode = regioncode
} }
} }
@ -262,6 +250,10 @@ class Ryujinx {
// We don't need this. Ryujinx should handle it fine :3 // We don't need this. Ryujinx should handle it fine :3
// this also causes crashes in some games :3 // this also causes crashes in some games :3
args.append(contentsOf: ["--system-language", config.language.rawValue])
args.append(contentsOf: ["--system-region", config.regioncode.rawValue])
args.append(contentsOf: ["--aspect-ratio", config.aspectRatio.rawValue]) args.append(contentsOf: ["--aspect-ratio", config.aspectRatio.rawValue])
if config.nintendoinput { if config.nintendoinput {
@ -276,7 +268,7 @@ class Ryujinx {
args.append("--disable-vsync") args.append("--disable-vsync")
} }
if config.hypervisor { if config.hypervisor {
args.append("--use-hypervisor") args.append("--use-hypervisor")
} }
@ -295,7 +287,8 @@ class Ryujinx {
} }
if config.ignoreMissingServices { if config.ignoreMissingServices {
args.append(contentsOf: ["--ignore-missing-services", String(config.maxAnisotropy)]) // args.append(contentsOf: ["--ignore-missing-services"])
args.append("--ignore-missing-services")
} }
if config.maxAnisotropy != 0 { if config.maxAnisotropy != 0 {
@ -318,15 +311,15 @@ class Ryujinx {
} }
if config.debuglogs { if config.debuglogs {
args.append(contentsOf: ["--enable-debug-logs"]) args.append("--enable-debug-logs")
} }
if config.tracelogs { if config.tracelogs {
args.append(contentsOf: ["--enable-trace-logs"]) args.append("--enable-trace-logs")
} }
// List the input ids // List the input ids
if config.listinputids { if config.listinputids {
args.append(contentsOf: ["--list-inputs-ids"]) args.append("--list-inputs-ids")
} }
// Append the input ids (limit to 4 just in case) // Append the input ids (limit to 4 just in case)

View File

@ -42,7 +42,7 @@ struct ContentView: View {
@AppStorage("quit") var quit: Bool = false @AppStorage("quit") var quit: Bool = false
@State var quits: Bool = false @State var quits: Bool = false
@AppStorage("MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS") var mVKPreFillBuffer: Bool = true @AppStorage("MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS") var mVKPreFillBuffer: Bool = true
@AppStorage("MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS") var syncqsubmits: Bool = false @AppStorage("MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS") var syncqsubmits: Bool = true
// Loading Animation // Loading Animation
@State private var clumpOffset: CGFloat = -100 @State private var clumpOffset: CGFloat = -100

View File

@ -129,6 +129,8 @@ struct ControllerView: View {
struct ShoulderButtonsViewLeft: View { struct ShoulderButtonsViewLeft: View {
@State var width: CGFloat = 160 @State var width: CGFloat = 160
@State var height: CGFloat = 20 @State var height: CGFloat = 20
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
var body: some View { var body: some View {
HStack { HStack {
ButtonView(button: .leftTrigger) ButtonView(button: .leftTrigger)
@ -142,6 +144,9 @@ struct ShoulderButtonsViewLeft: View {
width *= 1.2 width *= 1.2
height *= 1.2 height *= 1.2
} }
width *= CGFloat(controllerScale)
height *= CGFloat(controllerScale)
} }
} }
} }
@ -149,6 +154,8 @@ struct ShoulderButtonsViewLeft: View {
struct ShoulderButtonsViewRight: View { struct ShoulderButtonsViewRight: View {
@State var width: CGFloat = 160 @State var width: CGFloat = 160
@State var height: CGFloat = 20 @State var height: CGFloat = 20
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
var body: some View { var body: some View {
HStack { HStack {
ButtonView(button: .rightShoulder) ButtonView(button: .rightShoulder)
@ -162,12 +169,16 @@ struct ShoulderButtonsViewRight: View {
width *= 1.2 width *= 1.2
height *= 1.2 height *= 1.2
} }
width *= CGFloat(controllerScale)
height *= CGFloat(controllerScale)
} }
} }
} }
struct DPadView: View { struct DPadView: View {
@State var size: CGFloat = 145 @State var size: CGFloat = 145
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
var body: some View { var body: some View {
VStack { VStack {
ButtonView(button: .dPadUp) ButtonView(button: .dPadUp)
@ -184,12 +195,16 @@ struct DPadView: View {
if UIDevice.current.systemName.contains("iPadOS") { if UIDevice.current.systemName.contains("iPadOS") {
size *= 1.2 size *= 1.2
} }
size *= CGFloat(controllerScale)
} }
} }
} }
struct ABXYView: View { struct ABXYView: View {
@State var size: CGFloat = 145 @State var size: CGFloat = 145
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
var body: some View { var body: some View {
VStack { VStack {
ButtonView(button: .X) ButtonView(button: .X)
@ -206,6 +221,8 @@ struct ABXYView: View {
if UIDevice.current.systemName.contains("iPadOS") { if UIDevice.current.systemName.contains("iPadOS") {
size *= 1.2 size *= 1.2
} }
size *= CGFloat(controllerScale)
} }
} }
} }
@ -218,6 +235,7 @@ struct ButtonView: View {
@AppStorage("onscreenhandheld") var onscreenjoy: Bool = false @AppStorage("onscreenhandheld") var onscreenjoy: Bool = false
@Environment(\.colorScheme) var colorScheme @Environment(\.colorScheme) var colorScheme
@Environment(\.presentationMode) var presentationMode @Environment(\.presentationMode) var presentationMode
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
@ -256,6 +274,9 @@ struct ButtonView: View {
width *= 1.2 width *= 1.2
height *= 1.2 height *= 1.2
} }
width *= CGFloat(controllerScale)
height *= CGFloat(controllerScale)
} }
} }

View File

@ -13,11 +13,14 @@ public struct Joystick: View {
@State var iscool: Bool? = nil @State var iscool: Bool? = nil
@ObservedObject public var joystickMonitor = JoystickMonitor() @ObservedObject public var joystickMonitor = JoystickMonitor()
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
var dragDiameter: CGFloat { var dragDiameter: CGFloat {
var selfs = CGFloat(160) var selfs = CGFloat(160)
selfs *= controllerScale
if UIDevice.current.systemName.contains("iPadOS") { if UIDevice.current.systemName.contains("iPadOS") {
return selfs * 1.2 return selfs * 1.2
} }
return selfs return selfs
} }
private let shape: JoystickShape = .circle private let shape: JoystickShape = .circle

View File

@ -11,16 +11,18 @@ import SwiftUI
struct EmulationView: View { struct EmulationView: View {
@AppStorage("isVirtualController") var isVCA: Bool = true @AppStorage("isVirtualController") var isVCA: Bool = true
@AppStorage("showScreenShotButton") var ssb: Bool = false @AppStorage("showScreenShotButton") var ssb: Bool = false
@State var isPresentedThree: Bool = false
@State var isAirplaying = Air.shared.connected @State var isAirplaying = Air.shared.connected
@Environment(\.scenePhase) var scenePhase
var body: some View { var body: some View {
ZStack { ZStack {
if isAirplaying { if isAirplaying {
Text("") Text("")
.onAppear { .onAppear {
Air.play(AnyView(MetalView(airplay: true).ignoresSafeArea())) Air.play(AnyView(MetalView().ignoresSafeArea()))
} }
} else { } else {
MetalView(airplay: false) // The Emulation View MetalView() // The Emulation View
.ignoresSafeArea() .ignoresSafeArea()
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
} }
@ -31,6 +33,7 @@ struct EmulationView: View {
ControllerView() // Virtual Controller ControllerView() // Virtual Controller
} }
if ssb { if ssb {
Group { Group {
VStack { VStack {

View File

@ -10,7 +10,7 @@ import MetalKit
struct MetalView: UIViewRepresentable { struct MetalView: UIViewRepresentable {
var airplay: Bool // just in case :3 var airplay: Bool = Air.shared.connected // just in case :3
func makeUIView(context: Context) -> UIView { func makeUIView(context: Context) -> UIView {
let metalLayer = Ryujinx.shared.metalLayer! let metalLayer = Ryujinx.shared.metalLayer!

View File

@ -40,9 +40,11 @@ struct SettingsView: View {
@AppStorage("oldWindowCode") var windowCode: Bool = false @AppStorage("oldWindowCode") var windowCode: Bool = false
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
@State private var showResolutionInfo = false @State private var showResolutionInfo = false
@State private var showAnisotropicInfo = false @State private var showAnisotropicInfo = false
@State private var showControllerInfo = false
@State private var searchText = "" @State private var searchText = ""
var filteredMemoryModes: [(String, String)] { var filteredMemoryModes: [(String, String)] {
@ -270,6 +272,35 @@ struct SettingsView: View {
Text("Select input devices and on-screen controls to play with. ") Text("Select input devices and on-screen controls to play with. ")
} }
// Language and Region Settings
Section {
Picker(selection: $config.language) {
ForEach(SystemLanguage.allCases, id: \.self) { ratio in
Text(ratio.displayName).tag(ratio)
}
} label: {
labelWithIcon("Language", iconName: "character.bubble")
}
Picker(selection: $config.regioncode) {
ForEach(SystemRegionCode.allCases, id: \.self) { ratio in
Text(ratio.displayName).tag(ratio)
}
} label: {
labelWithIcon("Region", iconName: "globe")
}
// globe
} header: {
Text("Language and Region Settings")
.font(.title3.weight(.semibold))
.textCase(nil)
.headerProminence(.increased)
} footer: {
Text("Configure the System Language and the Region.")
}
// Input Settings // Input Settings
Section { Section {
@ -283,6 +314,46 @@ struct SettingsView: View {
} }
.tint(.blue) .tint(.blue)
.disabled(true) .disabled(true)
VStack(alignment: .leading, spacing: 10) {
HStack {
labelWithIcon("On-Screen Controller Scale", iconName: "magnifyingglass")
.font(.headline)
Spacer()
Button {
showControllerInfo.toggle()
} label: {
Image(systemName: "info.circle")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.secondary)
}
.buttonStyle(.plain)
.help("Learn more about On-Screen Controller Scale")
.alert(isPresented: $showControllerInfo) {
Alert(
title: Text("On-Screen Controller Scale"),
message: Text("Adjust the On-Screen Controller size."),
dismissButton: .default(Text("OK"))
)
}
}
Slider(value: $controllerScale, in: 0.1...3.0, step: 0.05) {
Text("Resolution Scale")
} minimumValueLabel: {
Text("0.1x")
.font(.footnote)
.foregroundColor(.secondary)
} maximumValueLabel: {
Text("3.0x")
.font(.footnote)
.foregroundColor(.secondary)
}
Text("\(controllerScale, specifier: "%.2f")x")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(.vertical, 8)
} header: { } header: {
Text("Input Settings") Text("Input Settings")
.font(.title3.weight(.semibold)) .font(.title3.weight(.semibold))

View File

@ -15,6 +15,17 @@
</array> </array>
</dict> </dict>
</array> </array>
<key>GCSupportedGameControllers</key>
<array>
<dict>
<key>ProfileName</key>
<string>ExtendedGamepad</string>
</dict>
<dict>
<key>ProfileName</key>
<string>MicroGamepad</string>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key> <key>LSApplicationQueriesSchemes</key>
<array> <array>
<string>melonx</string> <string>melonx</string>
@ -25,6 +36,11 @@
<array> <array>
<string>LaunchGameIntent</string> <string>LaunchGameIntent</string>
</array> </array>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>processing</string>
</array>
<key>UIFileSharingEnabled</key> <key>UIFileSharingEnabled</key>
<true/> <true/>
<key>UTExportedTypeDeclarations</key> <key>UTExportedTypeDeclarations</key>

View File

@ -319,7 +319,6 @@ namespace Ryujinx.Headless.SDL2
if (_window != null) if (_window != null)
{ {
_window.Exit(); _window.Exit();
_emulationContext.Dispose(); _emulationContext.Dispose();
_emulationContext = null; _emulationContext = null;
@ -332,6 +331,7 @@ namespace Ryujinx.Headless.SDL2
if (_virtualFileSystem == null) { if (_virtualFileSystem == null) {
_virtualFileSystem = VirtualFileSystem.CreateInstance(); _virtualFileSystem = VirtualFileSystem.CreateInstance();
} }
var extension = Marshal.PtrToStringAnsi(extensionPtr); var extension = Marshal.PtrToStringAnsi(extensionPtr);
var stream = OpenFile(descriptor); var stream = OpenFile(descriptor);

View File

@ -4,7 +4,7 @@ namespace Ryujinx.Memory
{ {
public const int PageBits = 12; public const int PageBits = 12;
public const int PageSize = 1 << PageBits; public const int PageSize = 1 << PageBits;
public const int PageMask = PageSize - 1; public const int PageMask = PageSize - 2;
private const int PtLevelBits = 9; // 9 * 4 + 12 = 48 (max address space size) private const int PtLevelBits = 9; // 9 * 4 + 12 = 48 (max address space size)
private const int PtLevelSize = 1 << PtLevelBits; private const int PtLevelSize = 1 << PtLevelBits;