mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
iOS: Add per-game boot compatibility settings
Add per-game EE Cycle Rate and Fast Boot overrides through the emulator bridge. setGameSettings gains eeCycleRate and fastBoot parameters with their override flags, the global game settings result reports the global defaults, and per-game overrides are read, clamped, and written into the EmuCore Speedhacks and Fast Boot INI keys. A negative EE underclock is clamped back to zero while RetroAchievements hardcore mode is active. The per-game settings panel surfaces EE Cycle Rate and Fast Boot pickers with reset-to-global controls, and gates saving on the game having a settings identity.
This commit is contained in:
@@ -145,11 +145,15 @@ typedef void (^ARMSX2RetroAchievementsCompletion)(BOOL success, NSString * _Nonn
|
||||
volumePercent:(int)volumePercent
|
||||
eeCoreType:(int)eeCoreType
|
||||
mtvu:(BOOL)mtvu
|
||||
eeCycleRateOverride:(BOOL)eeCycleRateOverride
|
||||
eeCycleRate:(int)eeCycleRate
|
||||
fastBootOverride:(BOOL)fastBootOverride
|
||||
fastBoot:(BOOL)fastBoot
|
||||
enableCheats:(BOOL)enableCheats
|
||||
enablePatches:(BOOL)enablePatches
|
||||
enableGameFixes:(BOOL)enableGameFixes
|
||||
enableGameDBHardwareFixes:(BOOL)enableGameDBHardwareFixes
|
||||
NS_SWIFT_NAME(setGameSettings(forISO:enabled:upscaleMultiplier:aspectRatio:textureFiltering:hardwareMipmapping:blendingAccuracy:interlaceMode:trilinearFiltering:halfPixelOffset:roundSprite:alignSpriteOverride:alignSprite:mergeSpriteOverride:mergeSprite:wildArmsOffsetOverride:wildArmsOffset:textureOffsetXOverride:textureOffsetX:textureOffsetYOverride:textureOffsetY:skipDrawStartOverride:skipDrawStart:skipDrawEndOverride:skipDrawEnd:volumeOverride:volumePercent:eeCoreType:mtvu:enableCheats:enablePatches:enableGameFixes:enableGameDBHardwareFixes:));
|
||||
NS_SWIFT_NAME(setGameSettings(forISO:enabled:upscaleMultiplier:aspectRatio:textureFiltering:hardwareMipmapping:blendingAccuracy:interlaceMode:trilinearFiltering:halfPixelOffset:roundSprite:alignSpriteOverride:alignSprite:mergeSpriteOverride:mergeSprite:wildArmsOffsetOverride:wildArmsOffset:textureOffsetXOverride:textureOffsetX:textureOffsetYOverride:textureOffsetY:skipDrawStartOverride:skipDrawStart:skipDrawEndOverride:skipDrawEnd:volumeOverride:volumePercent:eeCoreType:mtvu:eeCycleRateOverride:eeCycleRate:fastBootOverride:fastBoot:enableCheats:enablePatches:enableGameFixes:enableGameDBHardwareFixes:));
|
||||
+ (void)setGameSettingsForCurrentGameWithEnabled:(BOOL)enabled
|
||||
upscaleMultiplier:(float)upscaleMultiplier
|
||||
aspectRatio:(nonnull NSString *)aspectRatio
|
||||
@@ -178,11 +182,15 @@ typedef void (^ARMSX2RetroAchievementsCompletion)(BOOL success, NSString * _Nonn
|
||||
volumePercent:(int)volumePercent
|
||||
eeCoreType:(int)eeCoreType
|
||||
mtvu:(BOOL)mtvu
|
||||
eeCycleRateOverride:(BOOL)eeCycleRateOverride
|
||||
eeCycleRate:(int)eeCycleRate
|
||||
fastBootOverride:(BOOL)fastBootOverride
|
||||
fastBoot:(BOOL)fastBoot
|
||||
enableCheats:(BOOL)enableCheats
|
||||
enablePatches:(BOOL)enablePatches
|
||||
enableGameFixes:(BOOL)enableGameFixes
|
||||
enableGameDBHardwareFixes:(BOOL)enableGameDBHardwareFixes
|
||||
NS_SWIFT_NAME(setGameSettingsForCurrentGame(enabled:upscaleMultiplier:aspectRatio:textureFiltering:hardwareMipmapping:blendingAccuracy:interlaceMode:trilinearFiltering:halfPixelOffset:roundSprite:alignSpriteOverride:alignSprite:mergeSpriteOverride:mergeSprite:wildArmsOffsetOverride:wildArmsOffset:textureOffsetXOverride:textureOffsetX:textureOffsetYOverride:textureOffsetY:skipDrawStartOverride:skipDrawStart:skipDrawEndOverride:skipDrawEnd:volumeOverride:volumePercent:eeCoreType:mtvu:enableCheats:enablePatches:enableGameFixes:enableGameDBHardwareFixes:));
|
||||
NS_SWIFT_NAME(setGameSettingsForCurrentGame(enabled:upscaleMultiplier:aspectRatio:textureFiltering:hardwareMipmapping:blendingAccuracy:interlaceMode:trilinearFiltering:halfPixelOffset:roundSprite:alignSpriteOverride:alignSprite:mergeSpriteOverride:mergeSprite:wildArmsOffsetOverride:wildArmsOffset:textureOffsetXOverride:textureOffsetX:textureOffsetYOverride:textureOffsetY:skipDrawStartOverride:skipDrawStart:skipDrawEndOverride:skipDrawEnd:volumeOverride:volumePercent:eeCoreType:mtvu:eeCycleRateOverride:eeCycleRate:fastBootOverride:fastBoot:enableCheats:enablePatches:enableGameFixes:enableGameDBHardwareFixes:));
|
||||
+ (nonnull NSString *)clearCacheForISO:(nonnull NSString *)isoName NS_SWIFT_NAME(clearCache(forISO:));
|
||||
+ (nonnull NSString *)deleteGameDataForISO:(nonnull NSString *)isoName NS_SWIFT_NAME(deleteGameData(forISO:));
|
||||
+ (BOOL)deleteISO:(nonnull NSString *)isoName deleteGameData:(BOOL)deleteGameData NS_SWIFT_NAME(deleteISO(_:deleteGameData:));
|
||||
|
||||
@@ -1483,6 +1483,14 @@ static NSMutableDictionary<NSString*, id>* ARMSX2BuildGlobalGameSettingsResult()
|
||||
const bool globalEnableGameDBHardwareFixes = g_p44_settings_interface ? !g_p44_settings_interface->GetBoolValue("EmuCore/GS", "UserHacks", false) : true;
|
||||
const int globalEECoreType = g_p44_settings_interface ? g_p44_settings_interface->GetIntValue("EmuCore/CPU", "CoreType", 2) : 2;
|
||||
const bool globalMTVU = g_p44_settings_interface ? g_p44_settings_interface->GetBoolValue("EmuCore/Speedhacks", "vuThread", true) : true;
|
||||
const int globalEECycleRate = ARMSX2ClampInt(
|
||||
g_p44_settings_interface ? g_p44_settings_interface->GetIntValue("EmuCore/Speedhacks", "EECycleRate", 0) : 0,
|
||||
-3,
|
||||
3);
|
||||
const bool globalFastBoot = g_p44_settings_interface ?
|
||||
g_p44_settings_interface->GetBoolValue(
|
||||
"EmuCore", "EnableFastBoot",
|
||||
g_p44_settings_interface->GetBoolValue("GameISO", "FastBoot", false)) : false;
|
||||
const int globalVolumePercent = ARMSX2ClampInt(
|
||||
g_p44_settings_interface ? g_p44_settings_interface->GetIntValue("SPU2/Output", "StandardVolume", ARMSX2DefaultAudioVolumePercent) : ARMSX2DefaultAudioVolumePercent,
|
||||
0,
|
||||
@@ -1524,6 +1532,12 @@ static NSMutableDictionary<NSString*, id>* ARMSX2BuildGlobalGameSettingsResult()
|
||||
@"enableGameDBHardwareFixes": @(globalEnableGameDBHardwareFixes),
|
||||
@"eeCoreType": @(globalEECoreType),
|
||||
@"mtvu": @(globalMTVU),
|
||||
@"globalEECycleRate": @(globalEECycleRate),
|
||||
@"eeCycleRate": @(globalEECycleRate),
|
||||
@"hasEECycleRateOverride": @NO,
|
||||
@"globalFastBoot": @(globalFastBoot),
|
||||
@"fastBoot": @(globalFastBoot),
|
||||
@"hasFastBootOverride": @NO,
|
||||
@"globalVolumePercent": @(globalVolumePercent),
|
||||
@"volumePercent": @(globalVolumePercent),
|
||||
@"hasVolumeOverride": @NO,
|
||||
@@ -1583,6 +1597,8 @@ static void ARMSX2ApplyPerGameSettingsOverrides(NSMutableDictionary<NSString*, i
|
||||
si.ContainsValue("EmuCore/CPU", "CoreType") ||
|
||||
si.ContainsValue("EmuCore/CPU", "UseArm64Dynarec") ||
|
||||
si.ContainsValue("EmuCore/Speedhacks", "vuThread") ||
|
||||
si.ContainsValue("EmuCore/Speedhacks", "EECycleRate") ||
|
||||
si.ContainsValue("EmuCore", "EnableFastBoot") ||
|
||||
si.ContainsValue("SPU2/Output", "StandardVolume") ||
|
||||
si.ContainsValue("SPU2/Output", "FastForwardVolume");
|
||||
|
||||
@@ -1629,6 +1645,10 @@ static void ARMSX2ApplyPerGameSettingsOverrides(NSMutableDictionary<NSString*, i
|
||||
result[@"enableGameDBHardwareFixes"] = @(!si.GetBoolValue("EmuCore/GS", "UserHacks", ![result[@"enableGameDBHardwareFixes"] boolValue]));
|
||||
result[@"eeCoreType"] = @(si.GetIntValue("EmuCore/CPU", "CoreType", [result[@"eeCoreType"] intValue]));
|
||||
result[@"mtvu"] = @(si.GetBoolValue("EmuCore/Speedhacks", "vuThread", [result[@"mtvu"] boolValue]));
|
||||
result[@"hasEECycleRateOverride"] = @(si.ContainsValue("EmuCore/Speedhacks", "EECycleRate"));
|
||||
result[@"eeCycleRate"] = @(ARMSX2ClampInt(si.GetIntValue("EmuCore/Speedhacks", "EECycleRate", [result[@"eeCycleRate"] intValue]), -3, 3));
|
||||
result[@"hasFastBootOverride"] = @(si.ContainsValue("EmuCore", "EnableFastBoot"));
|
||||
result[@"fastBoot"] = @(si.GetBoolValue("EmuCore", "EnableFastBoot", [result[@"fastBoot"] boolValue]));
|
||||
}
|
||||
|
||||
static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
@@ -1661,6 +1681,10 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
int volumePercent,
|
||||
int eeCoreType,
|
||||
BOOL mtvu,
|
||||
BOOL eeCycleRateOverride,
|
||||
int eeCycleRate,
|
||||
BOOL fastBootOverride,
|
||||
BOOL fastBoot,
|
||||
BOOL enableCheats,
|
||||
BOOL enablePatches,
|
||||
BOOL enableGameFixes,
|
||||
@@ -1760,6 +1784,22 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
si.SetIntValue("ARMSX2iOS/PerGame", "ManualMTVUVersion", 3);
|
||||
si.SetBoolValue("EmuCore/Speedhacks", "vuThread", mtvu);
|
||||
}
|
||||
|
||||
if (eeCycleRateOverride) {
|
||||
int clampedEECycleRate = ARMSX2ClampInt(eeCycleRate, -3, 3);
|
||||
if (ARMSX2RetroAchievementsHardcoreActive() && clampedEECycleRate < 0) {
|
||||
ARMSX2LogRetroAchievementsHardcoreBlock("per_game_ee_underclock");
|
||||
clampedEECycleRate = 0;
|
||||
}
|
||||
si.SetIntValue("EmuCore/Speedhacks", "EECycleRate", clampedEECycleRate);
|
||||
} else {
|
||||
si.DeleteValue("EmuCore/Speedhacks", "EECycleRate");
|
||||
}
|
||||
|
||||
if (fastBootOverride)
|
||||
si.SetBoolValue("EmuCore", "EnableFastBoot", fastBoot);
|
||||
else
|
||||
si.DeleteValue("EmuCore", "EnableFastBoot");
|
||||
} else {
|
||||
si.DeleteValue("ARMSX2iOS/PerGame", "Enabled");
|
||||
si.DeleteValue("EmuCore/GS", "upscale_multiplier");
|
||||
@@ -1787,6 +1827,8 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
si.DeleteValue("ARMSX2iOS/PerGame", "ManualMTVU");
|
||||
si.DeleteValue("ARMSX2iOS/PerGame", "ManualMTVUVersion");
|
||||
si.DeleteValue("EmuCore/Speedhacks", "vuThread");
|
||||
si.DeleteValue("EmuCore/Speedhacks", "EECycleRate");
|
||||
si.DeleteValue("EmuCore", "EnableFastBoot");
|
||||
si.DeleteValue("SPU2/Output", "StandardVolume");
|
||||
si.DeleteValue("SPU2/Output", "FastForwardVolume");
|
||||
si.RemoveEmptySections();
|
||||
@@ -2337,6 +2379,10 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
volumePercent:(int)volumePercent
|
||||
eeCoreType:(int)eeCoreType
|
||||
mtvu:(BOOL)mtvu
|
||||
eeCycleRateOverride:(BOOL)eeCycleRateOverride
|
||||
eeCycleRate:(int)eeCycleRate
|
||||
fastBootOverride:(BOOL)fastBootOverride
|
||||
fastBoot:(BOOL)fastBoot
|
||||
enableCheats:(BOOL)enableCheats
|
||||
enablePatches:(BOOL)enablePatches
|
||||
enableGameFixes:(BOOL)enableGameFixes
|
||||
@@ -2356,6 +2402,7 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
textureOffsetYOverride, textureOffsetY, skipDrawStartOverride,
|
||||
skipDrawStart, skipDrawEndOverride, skipDrawEnd,
|
||||
volumeOverride, volumePercent, eeCoreType, mtvu,
|
||||
eeCycleRateOverride, eeCycleRate, fastBootOverride, fastBoot,
|
||||
enableCheats, enablePatches, enableGameFixes, enableGameDBHardwareFixes);
|
||||
}
|
||||
|
||||
@@ -2387,6 +2434,10 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
volumePercent:(int)volumePercent
|
||||
eeCoreType:(int)eeCoreType
|
||||
mtvu:(BOOL)mtvu
|
||||
eeCycleRateOverride:(BOOL)eeCycleRateOverride
|
||||
eeCycleRate:(int)eeCycleRate
|
||||
fastBootOverride:(BOOL)fastBootOverride
|
||||
fastBoot:(BOOL)fastBoot
|
||||
enableCheats:(BOOL)enableCheats
|
||||
enablePatches:(BOOL)enablePatches
|
||||
enableGameFixes:(BOOL)enableGameFixes
|
||||
@@ -2412,6 +2463,7 @@ static void ARMSX2WriteGameSettingsForIdentity(const std::string& serial,
|
||||
textureOffsetYOverride, textureOffsetY, skipDrawStartOverride,
|
||||
skipDrawStart, skipDrawEndOverride, skipDrawEnd,
|
||||
volumeOverride, volumePercent, eeCoreType, mtvu,
|
||||
eeCycleRateOverride, eeCycleRate, fastBootOverride, fastBoot,
|
||||
enableCheats, enablePatches, enableGameFixes, enableGameDBHardwareFixes);
|
||||
|
||||
if (VMManager::HasValidVM()) {
|
||||
|
||||
@@ -1561,6 +1561,10 @@ struct PerGameSettingsPanel: View {
|
||||
|
||||
private static let useGlobalSentinel = -1
|
||||
private static let trilinearUseGlobalSentinel = Int(Int32.min)
|
||||
private static let eeCycleRateUseGlobalSentinel = Int(Int32.min)
|
||||
private static let fastBootUseGlobalSentinel = -1
|
||||
private static let fastBootOff = 0
|
||||
private static let fastBootOn = 1
|
||||
|
||||
private static let deinterlaceOptions = [
|
||||
PickerOption(id: 0, title: "None"),
|
||||
@@ -1626,8 +1630,15 @@ struct PerGameSettingsPanel: View {
|
||||
@State private var globalVolumePercent: Int
|
||||
@State private var volumeOverride: Bool
|
||||
@State private var volumePercent: Int
|
||||
@State private var padLayoutIdentity: PadLayoutGameIdentity?
|
||||
@State private var showPadLayoutEditor = false
|
||||
@State private var eeCoreType: Int
|
||||
@State private var mtvu: Bool
|
||||
@State private var globalEECycleRate: Int
|
||||
@State private var eeCycleRate: Int
|
||||
@State private var globalFastBoot: Bool
|
||||
@State private var fastBoot: Int
|
||||
@State private var hasGameSettingsIdentity: Bool
|
||||
@State private var enableCheats: Bool
|
||||
@State private var enablePatches: Bool
|
||||
@State private var enableGameFixes: Bool
|
||||
@@ -1652,6 +1663,11 @@ struct PerGameSettingsPanel: View {
|
||||
_globalVolumePercent = State(initialValue: inheritedVolume)
|
||||
_volumeOverride = State(initialValue: Self.boolValue(info["hasVolumeOverride"], defaultValue: false))
|
||||
_volumePercent = State(initialValue: loadedVolume)
|
||||
_padLayoutIdentity = State(initialValue: PadLayoutGameIdentity(
|
||||
serial: (info["serial"] as? String) ?? game.metadata["serial"],
|
||||
crc: (info["crc"] as? String) ?? game.metadata["crc"]
|
||||
))
|
||||
_hasGameSettingsIdentity = State(initialValue: !PadLayoutGameIdentity.normalizedCRC((info["crc"] as? String) ?? game.metadata["crc"]).isEmpty)
|
||||
_upscaleMultiplier = State(initialValue: Self.floatValue(info["upscaleMultiplier"], defaultValue: 1.0))
|
||||
_aspectRatio = State(initialValue: Self.normalizedAspect(info["aspectRatio"] as? String))
|
||||
_textureFiltering = State(initialValue: Self.intValue(info["textureFiltering"], defaultValue: 2))
|
||||
@@ -1686,6 +1702,12 @@ struct PerGameSettingsPanel: View {
|
||||
_skipDrawEnd = State(initialValue: initialSkipDrawEnd)
|
||||
_eeCoreType = State(initialValue: Self.intValue(info["eeCoreType"], defaultValue: 2))
|
||||
_mtvu = State(initialValue: Self.boolValue(info["mtvu"], defaultValue: true))
|
||||
let inheritedEECycleRate = Self.clampedEECycleRate(Self.intValue(info["globalEECycleRate"], defaultValue: 0))
|
||||
_globalEECycleRate = State(initialValue: inheritedEECycleRate)
|
||||
_eeCycleRate = State(initialValue: Self.boolValue(info["hasEECycleRateOverride"], defaultValue: false) ? Self.clampedEECycleRate(Self.intValue(info["eeCycleRate"], defaultValue: inheritedEECycleRate)) : Self.eeCycleRateUseGlobalSentinel)
|
||||
let inheritedFastBoot = Self.boolValue(info["globalFastBoot"], defaultValue: false)
|
||||
_globalFastBoot = State(initialValue: inheritedFastBoot)
|
||||
_fastBoot = State(initialValue: Self.boolValue(info["hasFastBootOverride"], defaultValue: false) ? (Self.boolValue(info["fastBoot"], defaultValue: inheritedFastBoot) ? Self.fastBootOn : Self.fastBootOff) : Self.fastBootUseGlobalSentinel)
|
||||
_enableCheats = State(initialValue: Self.boolValue(info["enableCheats"], defaultValue: false))
|
||||
_enablePatches = State(initialValue: Self.boolValue(info["enablePatches"], defaultValue: true))
|
||||
_enableGameFixes = State(initialValue: Self.boolValue(info["enableGameFixes"], defaultValue: true))
|
||||
@@ -1766,6 +1788,11 @@ struct PerGameSettingsPanel: View {
|
||||
Text(settings.localized("Overrides are saved for this game only and apply on the next boot/reset of this title."))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
if !hasGameSettingsIdentity {
|
||||
Text("Start this game once before saving its settings.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.orange)
|
||||
}
|
||||
}
|
||||
|
||||
Section(settings.localized("Audio")) {
|
||||
@@ -1836,6 +1863,41 @@ struct PerGameSettingsPanel: View {
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("Performance / Compatibility") {
|
||||
Picker("EE Cycle Rate", selection: $eeCycleRate) {
|
||||
Text("Global Default (\(Self.formatEECycleRate(globalEECycleRate)))").tag(Self.eeCycleRateUseGlobalSentinel)
|
||||
ForEach(-3...3, id: \.self) { value in
|
||||
Text(Self.formatEECycleRate(value)).tag(value)
|
||||
}
|
||||
}
|
||||
.disabled(!enabled)
|
||||
|
||||
Button("Reset EE Cycle Rate to Global") {
|
||||
eeCycleRate = Self.eeCycleRateUseGlobalSentinel
|
||||
}
|
||||
.disabled(!enabled || eeCycleRate == Self.eeCycleRateUseGlobalSentinel)
|
||||
|
||||
Text("Can improve performance in heavy games, but may cause timing or compatibility issues. Reset or relaunch the game after changing it.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
Picker("Fast Boot", selection: $fastBoot) {
|
||||
Text("Global Default (\(globalFastBoot ? "On" : "Off"))").tag(Self.fastBootUseGlobalSentinel)
|
||||
Text("On").tag(Self.fastBootOn)
|
||||
Text("Off").tag(Self.fastBootOff)
|
||||
}
|
||||
.disabled(!enabled)
|
||||
|
||||
Button("Reset Fast Boot to Global") {
|
||||
fastBoot = Self.fastBootUseGlobalSentinel
|
||||
}
|
||||
.disabled(!enabled || fastBoot == Self.fastBootUseGlobalSentinel)
|
||||
|
||||
Text("Some games may need Fast Boot on or off to avoid looping at the disc screen. Reset or relaunch the game after changing it.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section(settings.localized("Graphics")) {
|
||||
Picker(settings.localized("Internal Resolution"), selection: $upscaleMultiplier) {
|
||||
Text("0.25x (Fastest)").tag(Float(0.25))
|
||||
@@ -2038,6 +2100,10 @@ struct PerGameSettingsPanel: View {
|
||||
}
|
||||
|
||||
private func save() {
|
||||
guard hasGameSettingsIdentity else {
|
||||
statusMessage = "Start this game once before saving its settings."
|
||||
return
|
||||
}
|
||||
let normalizedSkipDraw = normalizedSkipDrawValues()
|
||||
if skipDrawStart != normalizedSkipDraw.start {
|
||||
skipDrawStart = normalizedSkipDraw.start
|
||||
@@ -2076,6 +2142,10 @@ struct PerGameSettingsPanel: View {
|
||||
volumePercent: Int32(volumePercent),
|
||||
eeCoreType: Int32(eeCoreType),
|
||||
mtvu: mtvu,
|
||||
eeCycleRateOverride: enabled && eeCycleRate != Self.eeCycleRateUseGlobalSentinel,
|
||||
eeCycleRate: Int32(Self.clampedEECycleRate(eeCycleRate == Self.eeCycleRateUseGlobalSentinel ? globalEECycleRate : eeCycleRate)),
|
||||
fastBootOverride: enabled && fastBoot != Self.fastBootUseGlobalSentinel,
|
||||
fastBoot: fastBoot == Self.fastBootOn,
|
||||
enableCheats: enableCheats,
|
||||
enablePatches: enablePatches,
|
||||
enableGameFixes: enableGameFixes,
|
||||
@@ -2112,6 +2182,10 @@ struct PerGameSettingsPanel: View {
|
||||
volumePercent: Int32(volumePercent),
|
||||
eeCoreType: Int32(eeCoreType),
|
||||
mtvu: mtvu,
|
||||
eeCycleRateOverride: enabled && eeCycleRate != Self.eeCycleRateUseGlobalSentinel,
|
||||
eeCycleRate: Int32(Self.clampedEECycleRate(eeCycleRate == Self.eeCycleRateUseGlobalSentinel ? globalEECycleRate : eeCycleRate)),
|
||||
fastBootOverride: enabled && fastBoot != Self.fastBootUseGlobalSentinel,
|
||||
fastBoot: fastBoot == Self.fastBootOn,
|
||||
enableCheats: enableCheats,
|
||||
enablePatches: enablePatches,
|
||||
enableGameFixes: enableGameFixes,
|
||||
@@ -2190,10 +2264,19 @@ struct PerGameSettingsPanel: View {
|
||||
SettingsStore.clampedEmulatorVolumePercent(value)
|
||||
}
|
||||
|
||||
private static func clampedEECycleRate(_ value: Int) -> Int {
|
||||
min(max(value, -3), 3)
|
||||
}
|
||||
|
||||
private static func formatPercent(_ value: Int) -> String {
|
||||
"\(clampedVolume(value))%"
|
||||
}
|
||||
|
||||
private static func formatEECycleRate(_ value: Int) -> String {
|
||||
let clamped = clampedEECycleRate(value)
|
||||
return clamped > 0 ? "+\(clamped)" : "\(clamped)"
|
||||
}
|
||||
|
||||
private static func normalizedSkipDrawEnd(start: Int, end: Int, startOverride: Bool, endOverride: Bool) -> Int {
|
||||
let clampedEnd = clampedSkipDraw(end)
|
||||
guard startOverride && endOverride else {
|
||||
|
||||
Reference in New Issue
Block a user