Skip to content

Commit 65632d5

Browse files
committed
Launcher: frame rate and frame rate counter in Settings
Settings > Graphics > Frame rate: 30, 60, 120 (the game's own, default) or 240 frames a second, passed as NFSU2_FPS, and a switch for the on-screen counter (NFSU2_FPSCOUNTER, off by default). Restore Original Game puts them back to 120 and off.
1 parent c926f35 commit 65632d5

3 files changed

Lines changed: 29 additions & 0 deletions

File tree

‎launcher/Game.swift‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,17 @@ enum Prefs {
7171
static let engine = "LauncherEngine" // "original" | "hd"
7272
static let showAtStartup = "LauncherShowAtStartup"
7373
static let wideHUD = "LauncherWideHUD" // HUDPOS=1 for the engine
74+
static let frameRate = "LauncherFrameRate" // 30 | 60 | 120 | 240 -> NFSU2_FPS
75+
static let fpsCounter = "LauncherFPSCounter" // -> NFSU2_FPSCOUNTER
7476

7577
/// Each game option with its value in the original, unmodified game: Settings ›
7678
/// Restore Original Game sets them all. A new option adds its line here. (The
7779
/// game folder, full screen and showAtStartup are not game options.)
7880
static let originalGame: [OriginalValue] = [
7981
OriginalValue(\.engine, .original),
8082
OriginalValue(\.wideHUD, false),
83+
OriginalValue(\.frameRate, 120),
84+
OriginalValue(\.fpsCounter, false),
8185
]
8286
}
8387

‎launcher/Model.swift‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ final class LauncherModel: ObservableObject {
2121
@Published var showAtStartup: Bool { didSet { defaults.set(showAtStartup, forKey: Prefs.showAtStartup) } }
2222
@Published var wideHUD: Bool { didSet { defaults.set(wideHUD, forKey: Prefs.wideHUD) } }
2323
private var setHUDPOS = false // HUDPOS was set by us (not by the caller)
24+
/// Frames a second (the game's own is 120); passed as NFSU2_FPS.
25+
@Published var frameRate: Int { didSet { defaults.set(frameRate, forKey: Prefs.frameRate) } }
26+
@Published var fpsCounter: Bool { didSet { defaults.set(fpsCounter, forKey: Prefs.fpsCounter) } }
27+
private var setFPS = false // NFSU2_FPS / NFSU2_FPSCOUNTER were set by us
2428
@Published var controller: Bool { didSet { defaults.set(controller, forKey: Prefs.controller) } }
2529
@Published var stickDeadzone: Double { didSet { defaults.set(stickDeadzone, forKey: Prefs.stickDeadzone) } }
2630
private var setPad = false // NFSU2_PAD / NFSU2_PAD_DEADZONE were set by us
@@ -54,6 +58,9 @@ final class LauncherModel: ObservableObject {
5458
fullscreen = defaults.bool(forKey: Prefs.fullscreen)
5559
showAtStartup = defaults.bool(forKey: Prefs.showAtStartup)
5660
wideHUD = defaults.bool(forKey: Prefs.wideHUD)
61+
let fr = defaults.integer(forKey: Prefs.frameRate)
62+
frameRate = [30, 60, 120, 240].contains(fr) ? fr : 120
63+
fpsCounter = defaults.bool(forKey: Prefs.fpsCounter)
5764
controller = defaults.bool(forKey: Prefs.controller)
5865
stickDeadzone = min(0.5, max(0, defaults.double(forKey: Prefs.stickDeadzone)))
5966
}
@@ -123,6 +130,12 @@ final class LauncherModel: ObservableObject {
123130
if wideHUD { setenv("HUDPOS", "1", 1); setHUDPOS = true }
124131
else if setHUDPOS { unsetenv("HUDPOS"); setHUDPOS = false }
125132
}
133+
// Frame rate and counter (engine: overrides.c, metal.m); values set by hand win.
134+
if setFPS || (env["NFSU2_FPS"] == nil && env["NFSU2_FPSCOUNTER"] == nil) {
135+
if frameRate == 120 { unsetenv("NFSU2_FPS") } else { setenv("NFSU2_FPS", String(frameRate), 1) }
136+
setenv("NFSU2_FPSCOUNTER", fpsCounter ? "1" : "0", 1)
137+
setFPS = true
138+
}
126139
// Controller settings; NFSU2_PAD / NFSU2_PAD_DEADZONE set by hand still win. Ours
127140
// are overwritten on every Play, so a change takes effect without restarting.
128141
if setPad || (env["NFSU2_PAD"] == nil && env["NFSU2_PAD_DEADZONE"] == nil) {

‎launcher/Settings.swift‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ struct GraphicsSettings: View {
102102
description: "On wide screens the minimap moves to the left and the gauges to the right. Off: the HUD stays in the 4:3 middle.",
103103
isOn: $model.wideHUD)
104104
}
105+
Card("Frame rate") {
106+
SettingRow(title: "Frames a second",
107+
description: "The game's own limit is 120. 60 uses less power and suits 60 Hz screens; the screen's refresh rate is the upper limit. The game runs at the same speed either way.") {
108+
Picker("", selection: $model.frameRate) {
109+
Text("30").tag(30); Text("60").tag(60); Text("120").tag(120); Text("240").tag(240)
110+
}
111+
.pickerStyle(SegmentedPickerStyle()).labelsHidden().fixedSize()
112+
}
113+
SettingRow(title: "Show the frame rate",
114+
description: "Frames a second in the top left corner while playing.",
115+
isOn: $model.fpsCounter)
116+
}
105117
}
106118
}
107119
}

0 commit comments

Comments
 (0)