Branch data Line data Source code
1 : : #ifndef CONFIG_H
2 : : #define CONFIG_H
3 : :
4 : : #include "FFBEngine.h"
5 : : #include <string>
6 : : #include <vector>
7 : : #include <chrono>
8 : : #include <map>
9 : : #include <atomic>
10 : : #include "Version.h"
11 : :
12 : : struct Preset {
13 : : std::string name;
14 : : bool is_builtin = false;
15 : : std::string app_version = LMUFFB_VERSION; // NEW: Track if this is hardcoded or user-created
16 : :
17 : : // 1. SINGLE SOURCE OF TRUTH: Default Preset Values
18 : : // These defaults are used by:
19 : : // - FFBEngine constructor (via ApplyDefaultsToEngine)
20 : : // - "Default" preset in LoadPresets()
21 : : // - "Reset Defaults" button in GUI
22 : : // - Test presets that don't explicitly set these values
23 : : //
24 : : // âš ï¸ IMPORTANT: When changing these defaults, you MUST also update:
25 : : // 1. SetAdvancedBraking() default parameters below (abs_f, lockup_f)
26 : : // 2. test_ffb_engine.cpp: expected_abs_freq and expected_lockup_freq_scale
27 : : // 3. Any test presets in Config.cpp that rely on these defaults
28 : : //
29 : : // Current defaults match: GT3 DD 15 Nm (Simagic Alpha) - v0.6.35
30 : : float gain = 1.0f;
31 : : float understeer = 1.0f; // New scale: 0.0-2.0, where 1.0 = proportional
32 : : float sop = 1.666f;
33 : : float sop_scale = 1.0f;
34 : : float sop_smoothing = 1.0f;
35 : : float slip_smoothing = 0.002f;
36 : : float min_force = 0.0f;
37 : : float oversteer_boost = 2.52101f;
38 : : float dynamic_weight_gain = 0.0f; // NEW v0.7.46
39 : : float dynamic_weight_smoothing = 0.15f; // v0.7.47
40 : : float grip_smoothing_steady = 0.05f; // v0.7.47
41 : : float grip_smoothing_fast = 0.005f; // v0.7.47
42 : : float grip_smoothing_sensitivity = 0.1f; // v0.7.47
43 : :
44 : : bool lockup_enabled = true;
45 : : float lockup_gain = 0.37479f;
46 : : float lockup_start_pct = 1.0f; // New v0.5.11
47 : : float lockup_full_pct = 5.0f; // New v0.5.11
48 : : float lockup_rear_boost = 10.0f; // New v0.5.11
49 : : float lockup_gamma = 0.1f; // New v0.6.0
50 : : float lockup_prediction_sens = 10.0f; // New v0.6.0
51 : : float lockup_bump_reject = 0.1f; // New v0.6.0
52 : : float brake_load_cap = 2.0f; // New v0.5.11
53 : : float texture_load_cap = 1.5f; // NEW v0.6.25
54 : :
55 : : bool abs_pulse_enabled = false; // New v0.6.0
56 : : float abs_gain = 2.0f; // New v0.6.0
57 : : float abs_freq = 25.5f; // New v0.6.20
58 : :
59 : : bool spin_enabled = true;
60 : : float spin_gain = 0.5f;
61 : : float spin_freq_scale = 1.0f; // New v0.6.20
62 : :
63 : : bool slide_enabled = false;
64 : : float slide_gain = 0.226562f;
65 : : float slide_freq = 1.0f;
66 : :
67 : : bool road_enabled = true;
68 : : float road_gain = 0.0f;
69 : : float vibration_gain = 1.0f; // New v0.7.110 (Issue #206)
70 : :
71 : : bool dynamic_normalization_enabled = false;
72 : : bool auto_load_normalization_enabled = false;
73 : :
74 : : bool soft_lock_enabled = true;
75 : : float soft_lock_stiffness = 20.0f;
76 : : float soft_lock_damping = 0.5f;
77 : :
78 : : float wheelbase_max_nm = 15.0f; // Default DD
79 : : float target_rim_nm = 10.0f; // Default target
80 : :
81 : : float lockup_freq_scale = 1.02f; // New v0.6.20
82 : : int bottoming_method = 0;
83 : : float scrub_drag_gain = 0.0f;
84 : :
85 : : float rear_align_effect = 0.666f;
86 : : float sop_yaw_gain = 0.333f;
87 : : float gyro_gain = 0.0f;
88 : :
89 : : float steering_shaft_gain = 1.0f;
90 : : float ingame_ffb_gain = 1.0f; // New v0.7.71 (Issue #160)
91 : : int torque_source = 0; // 0=Shaft, 1=Direct
92 : : bool torque_passthrough = false; // v0.7.63
93 : :
94 : : // NEW: Grip & Smoothing (v0.5.7)
95 : : float optimal_slip_angle = 0.1f;
96 : : float optimal_slip_ratio = 0.12f;
97 : : float steering_shaft_smoothing = 0.0f;
98 : :
99 : : // NEW: Advanced Smoothing (v0.5.8)
100 : : float gyro_smoothing = 0.0f;
101 : : float yaw_smoothing = 0.001f;
102 : : float chassis_smoothing = 0.0f;
103 : :
104 : : // v0.4.41: Signal Filtering
105 : : bool flatspot_suppression = false;
106 : : float notch_q = 2.0f;
107 : : float flatspot_strength = 1.0f;
108 : :
109 : : bool static_notch_enabled = false;
110 : : float static_notch_freq = 11.0f;
111 : : float static_notch_width = 2.0f; // New v0.6.10
112 : : float yaw_kick_threshold = 0.0f; // New v0.6.10
113 : :
114 : : // v0.6.23 New Settings with HIGHER DEFAULTS
115 : : float speed_gate_lower = 1.0f; // 3.6 km/h
116 : : float speed_gate_upper = 5.0f; // 18.0 km/h (Fixes idle shake)
117 : :
118 : : // Reserved for future implementation (v0.6.23+)
119 : : float road_fallback_scale = 0.05f; // Planned: Road texture fallback scaling
120 : : bool understeer_affects_sop = false; // Planned: Understeer modulation of SoP
121 : :
122 : : // ===== SLOPE DETECTION (v0.7.0 → v0.7.1 defaults) =====
123 : : bool slope_detection_enabled = false;
124 : : int slope_sg_window = 15;
125 : : float slope_sensitivity = 0.5f; // Reduced from 1.0 (less aggressive)
126 : :
127 : : float slope_smoothing_tau = 0.04f; // Changed from 0.02 (smoother transitions)
128 : :
129 : : // v0.7.3: Slope detection stability fixes
130 : : float slope_alpha_threshold = 0.02f;
131 : : float slope_decay_rate = 5.0f;
132 : : bool slope_confidence_enabled = true;
133 : :
134 : : // v0.7.11: Min/Max Threshold System
135 : : float slope_min_threshold = -0.3f;
136 : : float slope_max_threshold = -2.0f;
137 : :
138 : : // NEW v0.7.40: Advanced Slope Settings
139 : : float slope_g_slew_limit = 50.0f;
140 : : bool slope_use_torque = true;
141 : : float slope_torque_sensitivity = 0.5f;
142 : : float slope_confidence_max_rate = 0.10f;
143 : :
144 : : bool rest_api_enabled = false;
145 : : int rest_api_port = 6397;
146 : :
147 : : // 2. Constructors
148 [ + - ]: 1818 : Preset(std::string n, bool builtin = false) : name(n), is_builtin(builtin), app_version(LMUFFB_VERSION) {}
149 [ + - + - ]: 5850 : Preset() : name("Unnamed"), is_builtin(false), app_version(LMUFFB_VERSION) {} // Default constructor for file loading
150 : :
151 : : // 3. Fluent Setters (The "Python Dictionary" feel)
152 : 286 : Preset& SetGain(float v) { gain = v; return *this; }
153 : 416 : Preset& SetUndersteer(float v) { understeer = v; return *this; }
154 : 416 : Preset& SetSoP(float v) { sop = v; return *this; }
155 : 156 : Preset& SetSoPScale(float v) { sop_scale = v; return *this; }
156 : 416 : Preset& SetSmoothing(float v) { sop_smoothing = v; return *this; }
157 : : Preset& SetMinForce(float v) { min_force = v; return *this; }
158 : 234 : Preset& SetOversteer(float v) { oversteer_boost = v; return *this; }
159 : : Preset& SetDynamicWeight(float v) { dynamic_weight_gain = v; return *this; }
160 : : Preset& SetDynamicWeightSmoothing(float v) { dynamic_weight_smoothing = v; return *this; }
161 : : Preset& SetGripSmoothing(float steady, float fast, float sens) {
162 : : grip_smoothing_steady = steady;
163 : : grip_smoothing_fast = fast;
164 : : grip_smoothing_sensitivity = sens;
165 : : return *this;
166 : : }
167 : 416 : Preset& SetSlipSmoothing(float v) { slip_smoothing = v; return *this; }
168 : :
169 : 260 : Preset& SetLockup(bool enabled, float g, float start = 5.0f, float full = 15.0f, float boost = 1.5f) {
170 : 260 : lockup_enabled = enabled;
171 : 260 : lockup_gain = g;
172 : 260 : lockup_start_pct = start;
173 : 260 : lockup_full_pct = full;
174 : 260 : lockup_rear_boost = boost;
175 : 260 : return *this;
176 : : }
177 : : Preset& SetBrakeCap(float v) { brake_load_cap = v; return *this; }
178 : 260 : Preset& SetSpin(bool enabled, float g, float scale = 1.0f) {
179 : 260 : spin_enabled = enabled;
180 : 260 : spin_gain = g;
181 : 260 : spin_freq_scale = scale;
182 : 260 : return *this;
183 : : }
184 : 416 : Preset& SetSlide(bool enabled, float g, float f = 1.0f) {
185 : 416 : slide_enabled = enabled;
186 : 416 : slide_gain = g;
187 : 416 : slide_freq = f;
188 : 416 : return *this;
189 : : }
190 : 260 : Preset& SetRoad(bool enabled, float g) { road_enabled = enabled; road_gain = g; return *this; }
191 : : Preset& SetVibrationGain(float v) { vibration_gain = v; return *this; }
192 : : Preset& SetDynamicNormalization(bool enabled) { dynamic_normalization_enabled = enabled; return *this; }
193 : :
194 : : Preset& SetSoftLock(bool enabled, float stiffness, float damping) {
195 : : soft_lock_enabled = enabled;
196 : : soft_lock_stiffness = stiffness;
197 : : soft_lock_damping = damping;
198 : : return *this;
199 : : }
200 : :
201 : : Preset& SetHardwareScaling(float wheelbase, float target) {
202 : : wheelbase_max_nm = wheelbase;
203 : : target_rim_nm = target;
204 : : return *this;
205 : : }
206 : :
207 : : Preset& SetBottoming(int method) { bottoming_method = method; return *this; }
208 : 234 : Preset& SetScrub(float v) { scrub_drag_gain = v; return *this; }
209 : 416 : Preset& SetRearAlign(float v) { rear_align_effect = v; return *this; }
210 : 234 : Preset& SetSoPYaw(float v) { sop_yaw_gain = v; return *this; }
211 : 156 : Preset& SetGyro(float v) { gyro_gain = v; return *this; }
212 : :
213 : : Preset& SetShaftGain(float v) { steering_shaft_gain = v; return *this; }
214 : : Preset& SetInGameGain(float v) { ingame_ffb_gain = v; return *this; }
215 : : Preset& SetTorqueSource(int v, bool passthrough = false) { torque_source = v; torque_passthrough = passthrough; return *this; }
216 : : Preset& SetFlatspot(bool enabled, float strength = 1.0f, float q = 2.0f) {
217 : : flatspot_suppression = enabled;
218 : : flatspot_strength = strength;
219 : : notch_q = q;
220 : : return *this;
221 : : }
222 : :
223 : : Preset& SetStaticNotch(bool enabled, float freq, float width = 2.0f) {
224 : : static_notch_enabled = enabled;
225 : : static_notch_freq = freq;
226 : : static_notch_width = width;
227 : : return *this;
228 : : }
229 : 26 : Preset& SetYawKickThreshold(float v) { yaw_kick_threshold = v; return *this; }
230 : 26 : Preset& SetSpeedGate(float lower, float upper) { speed_gate_lower = lower; speed_gate_upper = upper; return *this; }
231 : :
232 : 26 : Preset& SetOptimalSlip(float angle, float ratio) {
233 : 26 : optimal_slip_angle = angle;
234 : 26 : optimal_slip_ratio = ratio;
235 : 26 : return *this;
236 : : }
237 : : Preset& SetShaftSmoothing(float v) { steering_shaft_smoothing = v; return *this; }
238 : :
239 : : Preset& SetGyroSmoothing(float v) { gyro_smoothing = v; return *this; }
240 : 26 : Preset& SetYawSmoothing(float v) { yaw_smoothing = v; return *this; }
241 : : Preset& SetChassisSmoothing(float v) { chassis_smoothing = v; return *this; }
242 : :
243 : : Preset& SetSlopeDetection(bool enabled, int window = 15, float min_thresh = -0.3f, float max_thresh = -2.0f, float tau = 0.04f) {
244 : : slope_detection_enabled = enabled;
245 : : slope_sg_window = window;
246 : : slope_min_threshold = min_thresh;
247 : : slope_max_threshold = max_thresh;
248 : : slope_smoothing_tau = tau;
249 : : return *this;
250 : : }
251 : :
252 : : Preset& SetSlopeStability(float alpha_thresh = 0.02f, float decay = 5.0f, bool conf = true) {
253 : : slope_alpha_threshold = alpha_thresh;
254 : : slope_decay_rate = decay;
255 : : slope_confidence_enabled = conf;
256 : : return *this;
257 : : }
258 : :
259 : : Preset& SetSlopeAdvanced(float slew = 50.0f, bool use_torque = true, float torque_sens = 0.5f) {
260 : : slope_g_slew_limit = slew;
261 : : slope_use_torque = use_torque;
262 : : slope_torque_sensitivity = torque_sens;
263 : : return *this;
264 : : }
265 : :
266 : : Preset& SetRestApiFallback(bool enabled, int port = 6397) {
267 : : rest_api_enabled = enabled;
268 : : rest_api_port = port;
269 : : return *this;
270 : : }
271 : :
272 : : // Advanced Braking (v0.6.0)
273 : : // âš ï¸ IMPORTANT: Default parameters (abs_f, lockup_f) must match Config.h defaults!
274 : : // When changing Config.h defaults, update these values to match.
275 : : // Current: abs_f=25.5, lockup_f=1.02 (GT3 DD 15 Nm defaults - v0.6.35)
276 : 52 : Preset& SetAdvancedBraking(float gamma, float sens, float bump, bool abs, float abs_g, float abs_f = 25.5f, float lockup_f = 1.02f) {
277 : 52 : lockup_gamma = gamma;
278 : 52 : lockup_prediction_sens = sens;
279 : 52 : lockup_bump_reject = bump;
280 : 52 : abs_pulse_enabled = abs;
281 : 52 : abs_gain = abs_g;
282 : 52 : abs_freq = abs_f;
283 : 52 : lockup_freq_scale = lockup_f;
284 : 52 : return *this;
285 : : }
286 : :
287 : : // 4. Static method to apply defaults to FFBEngine (Single Source of Truth)
288 : : // This is called by FFBEngine constructor to initialize with T300 defaults
289 : 592 : static void ApplyDefaultsToEngine(FFBEngine& engine) {
290 [ + - ]: 592 : Preset defaults; // Uses default member initializers (T300 values)
291 [ + - ]: 592 : defaults.Apply(engine);
292 : 592 : }
293 : :
294 : : // Apply this preset to an engine instance
295 : : // v0.7.16: Added comprehensive safety clamping to prevent crashes/NaN from invalid config values
296 : 614 : void Apply(FFBEngine& engine) const {
297 : 614 : engine.m_dynamic_normalization_enabled = dynamic_normalization_enabled;
298 : 614 : engine.m_auto_load_normalization_enabled = auto_load_normalization_enabled;
299 : 614 : engine.m_gain = (std::max)(0.0f, gain);
300 : 614 : engine.m_understeer_effect = (std::max)(0.0f, (std::min)(2.0f, understeer));
301 : 614 : engine.m_sop_effect = (std::max)(0.0f, (std::min)(2.0f, sop));
302 : 614 : engine.m_sop_scale = (std::max)(0.01f, sop_scale);
303 : 614 : engine.m_sop_smoothing_factor = (std::max)(0.0f, (std::min)(1.0f, sop_smoothing));
304 : 614 : engine.m_slip_angle_smoothing = (std::max)(0.0001f, slip_smoothing);
305 : 614 : engine.m_min_force = (std::max)(0.0f, min_force);
306 : 614 : engine.m_oversteer_boost = (std::max)(0.0f, oversteer_boost);
307 : 614 : engine.m_dynamic_weight_gain = (std::max)(0.0f, (std::min)(2.0f, dynamic_weight_gain));
308 : 614 : engine.m_dynamic_weight_smoothing = (std::max)(0.0f, dynamic_weight_smoothing);
309 : 614 : engine.m_grip_smoothing_steady = (std::max)(0.0f, grip_smoothing_steady);
310 : 614 : engine.m_grip_smoothing_fast = (std::max)(0.0f, grip_smoothing_fast);
311 : 614 : engine.m_grip_smoothing_sensitivity = (std::max)(0.001f, grip_smoothing_sensitivity);
312 : :
313 : 614 : engine.m_lockup_enabled = lockup_enabled;
314 : 614 : engine.m_lockup_gain = (std::max)(0.0f, lockup_gain);
315 : 614 : engine.m_lockup_start_pct = (std::max)(0.1f, lockup_start_pct);
316 : 614 : engine.m_lockup_full_pct = (std::max)(0.2f, lockup_full_pct);
317 : 614 : engine.m_lockup_rear_boost = (std::max)(0.0f, lockup_rear_boost);
318 : 614 : engine.m_lockup_gamma = (std::max)(0.1f, lockup_gamma); // Critical: prevent pow(0, negative) crash
319 : 614 : engine.m_lockup_prediction_sens = (std::max)(1.0f, lockup_prediction_sens);
320 : 614 : engine.m_lockup_bump_reject = (std::max)(0.01f, lockup_bump_reject);
321 : 614 : engine.m_brake_load_cap = (std::max)(1.0f, brake_load_cap);
322 : 614 : engine.m_texture_load_cap = (std::max)(1.0f, texture_load_cap);
323 : :
324 : 614 : engine.m_abs_pulse_enabled = abs_pulse_enabled;
325 : 614 : engine.m_abs_gain = (std::max)(0.0f, abs_gain);
326 : :
327 : 614 : engine.m_spin_enabled = spin_enabled;
328 : 614 : engine.m_spin_gain = (std::max)(0.0f, spin_gain);
329 : 614 : engine.m_slide_texture_enabled = slide_enabled;
330 : 614 : engine.m_slide_texture_gain = (std::max)(0.0f, slide_gain);
331 : 614 : engine.m_slide_freq_scale = (std::max)(0.1f, slide_freq);
332 : 614 : engine.m_road_texture_enabled = road_enabled;
333 : 614 : engine.m_road_texture_gain = (std::max)(0.0f, road_gain);
334 : 614 : engine.m_vibration_gain = (std::max)(0.0f, (std::min)(2.0f, vibration_gain));
335 : :
336 : 614 : engine.m_soft_lock_enabled = soft_lock_enabled;
337 : 614 : engine.m_soft_lock_stiffness = (std::max)(0.0f, soft_lock_stiffness);
338 : 614 : engine.m_soft_lock_damping = (std::max)(0.0f, soft_lock_damping);
339 : :
340 : 614 : engine.m_wheelbase_max_nm = (std::max)(1.0f, wheelbase_max_nm);
341 : 614 : engine.m_target_rim_nm = (std::max)(1.0f, target_rim_nm);
342 : 614 : engine.m_abs_freq_hz = (std::max)(1.0f, abs_freq);
343 : 614 : engine.m_lockup_freq_scale = (std::max)(0.1f, lockup_freq_scale);
344 : 614 : engine.m_spin_freq_scale = (std::max)(0.1f, spin_freq_scale);
345 : 614 : engine.m_bottoming_method = bottoming_method;
346 : 614 : engine.m_scrub_drag_gain = (std::max)(0.0f, scrub_drag_gain);
347 : 614 : engine.m_rear_align_effect = (std::max)(0.0f, rear_align_effect);
348 : 614 : engine.m_sop_yaw_gain = (std::max)(0.0f, sop_yaw_gain);
349 : 614 : engine.m_gyro_gain = (std::max)(0.0f, gyro_gain);
350 : 614 : engine.m_steering_shaft_gain = (std::max)(0.0f, steering_shaft_gain);
351 : 614 : engine.m_ingame_ffb_gain = (std::max)(0.0f, ingame_ffb_gain);
352 : 614 : engine.m_torque_source = torque_source;
353 : 614 : engine.m_torque_passthrough = torque_passthrough;
354 : 614 : engine.m_flatspot_suppression = flatspot_suppression;
355 : 614 : engine.m_notch_q = (std::max)(0.1f, notch_q); // Critical for biquad division
356 : 614 : engine.m_flatspot_strength = (std::max)(0.0f, (std::min)(1.0f, flatspot_strength));
357 : 614 : engine.m_static_notch_enabled = static_notch_enabled;
358 : 614 : engine.m_static_notch_freq = (std::max)(1.0f, static_notch_freq);
359 : 614 : engine.m_static_notch_width = (std::max)(0.1f, static_notch_width);
360 : 614 : engine.m_yaw_kick_threshold = (std::max)(0.0f, yaw_kick_threshold);
361 : 614 : engine.m_speed_gate_lower = (std::max)(0.0f, speed_gate_lower);
362 : 614 : engine.m_speed_gate_upper = (std::max)(0.1f, speed_gate_upper);
363 : :
364 : : // NEW: Grip & Smoothing (v0.5.7/v0.5.8)
365 : 614 : engine.m_optimal_slip_angle = (std::max)(0.01f, optimal_slip_angle); // Critical for grip division
366 : 614 : engine.m_optimal_slip_ratio = (std::max)(0.01f, optimal_slip_ratio); // Critical for grip division
367 : 614 : engine.m_steering_shaft_smoothing = (std::max)(0.0f, steering_shaft_smoothing);
368 : 614 : engine.m_gyro_smoothing = (std::max)(0.0f, gyro_smoothing);
369 : 614 : engine.m_yaw_accel_smoothing = (std::max)(0.0f, yaw_smoothing);
370 : 614 : engine.m_chassis_inertia_smoothing = (std::max)(0.0f, chassis_smoothing);
371 : 614 : engine.m_road_fallback_scale = (std::max)(0.0f, road_fallback_scale);
372 : 614 : engine.m_understeer_affects_sop = understeer_affects_sop;
373 : :
374 : : // Slope Detection (v0.7.0)
375 : 614 : engine.m_slope_detection_enabled = slope_detection_enabled;
376 : 614 : engine.m_slope_sg_window = (std::max)(5, (std::min)(41, slope_sg_window));
377 [ - + ]: 614 : if (engine.m_slope_sg_window % 2 == 0) engine.m_slope_sg_window++; // Must be odd for SG
378 : 614 : engine.m_slope_sensitivity = (std::max)(0.1f, slope_sensitivity);
379 : :
380 : 614 : engine.m_slope_smoothing_tau = (std::max)(0.001f, slope_smoothing_tau);
381 : :
382 : : // v0.7.3: Slope stability fixes
383 : 614 : engine.m_slope_alpha_threshold = (std::max)(0.001f, slope_alpha_threshold); // Critical for slope division
384 : 614 : engine.m_slope_decay_rate = (std::max)(0.1f, slope_decay_rate);
385 : 614 : engine.m_slope_confidence_enabled = slope_confidence_enabled;
386 : 614 : engine.m_slope_confidence_max_rate = (std::max)(engine.m_slope_alpha_threshold + 0.01f, slope_confidence_max_rate);
387 : :
388 : : // v0.7.11: Min/Max thresholds
389 : 614 : engine.m_slope_min_threshold = slope_min_threshold;
390 : 614 : engine.m_slope_max_threshold = slope_max_threshold;
391 : :
392 : : // NEW v0.7.40: Advanced Slope Settings
393 : 614 : engine.m_slope_g_slew_limit = (std::max)(1.0f, slope_g_slew_limit);
394 : 614 : engine.m_slope_use_torque = slope_use_torque;
395 : 614 : engine.m_slope_torque_sensitivity = (std::max)(0.01f, slope_torque_sensitivity);
396 : :
397 : 614 : engine.m_rest_api_enabled = rest_api_enabled;
398 : 614 : engine.m_rest_api_port = (std::max)(1, rest_api_port);
399 : :
400 : : // Stage 1 & 2 Normalization (Issue #152 & #153)
401 : : // Initialize session peak from target rim torque to provide a sane starting point.
402 : 614 : engine.m_session_peak_torque = (std::max)(1.0, (double)target_rim_nm);
403 : 614 : engine.m_smoothed_structural_mult = 1.0 / engine.m_session_peak_torque;
404 : 614 : }
405 : :
406 : : // NEW: Ensure values are within safe ranges (v0.7.16)
407 : 24 : void Validate() {
408 : 24 : gain = (std::max)(0.0f, gain);
409 : 24 : understeer = (std::max)(0.0f, (std::min)(2.0f, understeer));
410 : 24 : sop = (std::max)(0.0f, (std::min)(2.0f, sop));
411 : 24 : sop_scale = (std::max)(0.01f, sop_scale);
412 : 24 : sop_smoothing = (std::max)(0.0f, (std::min)(1.0f, sop_smoothing));
413 : 24 : slip_smoothing = (std::max)(0.0001f, slip_smoothing);
414 : 24 : min_force = (std::max)(0.0f, min_force);
415 : 24 : oversteer_boost = (std::max)(0.0f, oversteer_boost);
416 : 24 : dynamic_weight_gain = (std::max)(0.0f, (std::min)(2.0f, dynamic_weight_gain));
417 : 24 : dynamic_weight_smoothing = (std::max)(0.0f, dynamic_weight_smoothing);
418 : 24 : grip_smoothing_steady = (std::max)(0.0f, grip_smoothing_steady);
419 : 24 : grip_smoothing_fast = (std::max)(0.0f, grip_smoothing_fast);
420 : 24 : grip_smoothing_sensitivity = (std::max)(0.001f, grip_smoothing_sensitivity);
421 : 24 : lockup_gain = (std::max)(0.0f, lockup_gain);
422 : 24 : lockup_start_pct = (std::max)(0.1f, lockup_start_pct);
423 : 24 : lockup_full_pct = (std::max)(0.2f, lockup_full_pct);
424 : 24 : lockup_rear_boost = (std::max)(0.0f, lockup_rear_boost);
425 : 24 : lockup_gamma = (std::max)(0.1f, lockup_gamma);
426 : 24 : lockup_prediction_sens = (std::max)(1.0f, lockup_prediction_sens);
427 : 24 : lockup_bump_reject = (std::max)(0.01f, lockup_bump_reject);
428 : 24 : brake_load_cap = (std::max)(1.0f, brake_load_cap);
429 : 24 : texture_load_cap = (std::max)(1.0f, texture_load_cap);
430 : 24 : abs_gain = (std::max)(0.0f, abs_gain);
431 : 24 : spin_gain = (std::max)(0.0f, spin_gain);
432 : 24 : slide_gain = (std::max)(0.0f, slide_gain);
433 : 24 : slide_freq = (std::max)(0.1f, slide_freq);
434 : 24 : road_gain = (std::max)(0.0f, road_gain);
435 : 24 : vibration_gain = (std::max)(0.0f, (std::min)(2.0f, vibration_gain));
436 : 24 : soft_lock_stiffness = (std::max)(0.0f, soft_lock_stiffness);
437 : 24 : soft_lock_damping = (std::max)(0.0f, soft_lock_damping);
438 : 24 : wheelbase_max_nm = (std::max)(1.0f, wheelbase_max_nm);
439 : 24 : target_rim_nm = (std::max)(1.0f, target_rim_nm);
440 : 24 : abs_freq = (std::max)(1.0f, abs_freq);
441 : 24 : lockup_freq_scale = (std::max)(0.1f, lockup_freq_scale);
442 : 24 : spin_freq_scale = (std::max)(0.1f, spin_freq_scale);
443 : 24 : scrub_drag_gain = (std::max)(0.0f, scrub_drag_gain);
444 : 24 : rear_align_effect = (std::max)(0.0f, rear_align_effect);
445 : 24 : sop_yaw_gain = (std::max)(0.0f, sop_yaw_gain);
446 : 24 : gyro_gain = (std::max)(0.0f, gyro_gain);
447 : 24 : steering_shaft_gain = (std::max)(0.0f, steering_shaft_gain);
448 : 24 : ingame_ffb_gain = (std::max)(0.0f, ingame_ffb_gain);
449 : 24 : torque_source = (std::max)(0, (std::min)(1, torque_source));
450 : : // torque_passthrough is bool, no clamp needed
451 : 24 : notch_q = (std::max)(0.1f, notch_q);
452 : 24 : flatspot_strength = (std::max)(0.0f, (std::min)(1.0f, flatspot_strength));
453 : 24 : static_notch_freq = (std::max)(1.0f, static_notch_freq);
454 : 24 : static_notch_width = (std::max)(0.1f, static_notch_width);
455 : 24 : speed_gate_upper = (std::max)(0.1f, speed_gate_upper);
456 : 24 : optimal_slip_angle = (std::max)(0.01f, optimal_slip_angle);
457 : 24 : optimal_slip_ratio = (std::max)(0.01f, optimal_slip_ratio);
458 : 24 : steering_shaft_smoothing = (std::max)(0.0f, steering_shaft_smoothing);
459 : 24 : gyro_smoothing = (std::max)(0.0f, gyro_smoothing);
460 : 24 : yaw_smoothing = (std::max)(0.0f, yaw_smoothing);
461 : 24 : chassis_smoothing = (std::max)(0.0f, chassis_smoothing);
462 : 24 : road_fallback_scale = (std::max)(0.0f, road_fallback_scale);
463 : 24 : slope_sg_window = (std::max)(5, (std::min)(41, slope_sg_window));
464 [ - + ]: 24 : if (slope_sg_window % 2 == 0) slope_sg_window++;
465 : 24 : slope_sensitivity = (std::max)(0.1f, slope_sensitivity);
466 : 24 : slope_smoothing_tau = (std::max)(0.001f, slope_smoothing_tau);
467 : 24 : slope_alpha_threshold = (std::max)(0.001f, slope_alpha_threshold);
468 : 24 : slope_decay_rate = (std::max)(0.1f, slope_decay_rate);
469 : 24 : slope_g_slew_limit = (std::max)(1.0f, slope_g_slew_limit);
470 : 24 : slope_torque_sensitivity = (std::max)(0.01f, slope_torque_sensitivity);
471 : 24 : slope_confidence_max_rate = (std::max)(slope_alpha_threshold + 0.01f, slope_confidence_max_rate);
472 : 24 : rest_api_port = (std::max)(1, rest_api_port);
473 : 24 : }
474 : :
475 : : // NEW: Capture current engine state into this preset
476 : 393 : void UpdateFromEngine(const FFBEngine& engine) {
477 : 393 : dynamic_normalization_enabled = engine.m_dynamic_normalization_enabled;
478 : 393 : auto_load_normalization_enabled = engine.m_auto_load_normalization_enabled;
479 : 393 : gain = engine.m_gain;
480 : 393 : understeer = engine.m_understeer_effect;
481 : 393 : sop = engine.m_sop_effect;
482 : 393 : sop_scale = engine.m_sop_scale;
483 : 393 : sop_smoothing = engine.m_sop_smoothing_factor;
484 : 393 : slip_smoothing = engine.m_slip_angle_smoothing;
485 : 393 : min_force = engine.m_min_force;
486 : 393 : oversteer_boost = engine.m_oversteer_boost;
487 : 393 : dynamic_weight_gain = engine.m_dynamic_weight_gain;
488 : 393 : dynamic_weight_smoothing = engine.m_dynamic_weight_smoothing;
489 : 393 : grip_smoothing_steady = engine.m_grip_smoothing_steady;
490 : 393 : grip_smoothing_fast = engine.m_grip_smoothing_fast;
491 : 393 : grip_smoothing_sensitivity = engine.m_grip_smoothing_sensitivity;
492 : 393 : lockup_enabled = engine.m_lockup_enabled;
493 : 393 : lockup_gain = engine.m_lockup_gain;
494 : 393 : lockup_start_pct = engine.m_lockup_start_pct;
495 : 393 : lockup_full_pct = engine.m_lockup_full_pct;
496 : 393 : lockup_rear_boost = engine.m_lockup_rear_boost;
497 : 393 : lockup_gamma = engine.m_lockup_gamma;
498 : 393 : lockup_prediction_sens = engine.m_lockup_prediction_sens;
499 : 393 : lockup_bump_reject = engine.m_lockup_bump_reject;
500 : 393 : brake_load_cap = engine.m_brake_load_cap;
501 : 393 : texture_load_cap = engine.m_texture_load_cap; // NEW v0.6.25
502 : 393 : abs_pulse_enabled = engine.m_abs_pulse_enabled;
503 : 393 : abs_gain = engine.m_abs_gain;
504 : :
505 : 393 : spin_enabled = engine.m_spin_enabled;
506 : 393 : spin_gain = engine.m_spin_gain;
507 : 393 : slide_enabled = engine.m_slide_texture_enabled;
508 : 393 : slide_gain = engine.m_slide_texture_gain;
509 : 393 : slide_freq = engine.m_slide_freq_scale;
510 : 393 : road_enabled = engine.m_road_texture_enabled;
511 : 393 : road_gain = engine.m_road_texture_gain;
512 : 393 : vibration_gain = engine.m_vibration_gain;
513 : :
514 : 393 : soft_lock_enabled = engine.m_soft_lock_enabled;
515 : 393 : soft_lock_stiffness = engine.m_soft_lock_stiffness;
516 : 393 : soft_lock_damping = engine.m_soft_lock_damping;
517 : :
518 : 393 : wheelbase_max_nm = engine.m_wheelbase_max_nm;
519 : 393 : target_rim_nm = engine.m_target_rim_nm;
520 : 393 : abs_freq = engine.m_abs_freq_hz;
521 : 393 : lockup_freq_scale = engine.m_lockup_freq_scale;
522 : 393 : spin_freq_scale = engine.m_spin_freq_scale;
523 : 393 : bottoming_method = engine.m_bottoming_method;
524 : 393 : scrub_drag_gain = engine.m_scrub_drag_gain;
525 : 393 : rear_align_effect = engine.m_rear_align_effect;
526 : 393 : sop_yaw_gain = engine.m_sop_yaw_gain;
527 : 393 : gyro_gain = engine.m_gyro_gain;
528 : 393 : steering_shaft_gain = engine.m_steering_shaft_gain;
529 : 393 : ingame_ffb_gain = engine.m_ingame_ffb_gain;
530 : 393 : torque_source = engine.m_torque_source;
531 : 393 : torque_passthrough = engine.m_torque_passthrough;
532 : 393 : flatspot_suppression = engine.m_flatspot_suppression;
533 : 393 : notch_q = engine.m_notch_q;
534 : 393 : flatspot_strength = engine.m_flatspot_strength;
535 : 393 : static_notch_enabled = engine.m_static_notch_enabled;
536 : 393 : static_notch_freq = engine.m_static_notch_freq;
537 : 393 : static_notch_width = engine.m_static_notch_width;
538 : 393 : yaw_kick_threshold = engine.m_yaw_kick_threshold;
539 : 393 : speed_gate_lower = engine.m_speed_gate_lower;
540 : 393 : speed_gate_upper = engine.m_speed_gate_upper;
541 : :
542 : : // NEW: Grip & Smoothing (v0.5.7/v0.5.8)
543 : 393 : optimal_slip_angle = engine.m_optimal_slip_angle;
544 : 393 : optimal_slip_ratio = engine.m_optimal_slip_ratio;
545 : 393 : steering_shaft_smoothing = engine.m_steering_shaft_smoothing;
546 : 393 : gyro_smoothing = engine.m_gyro_smoothing;
547 : 393 : yaw_smoothing = engine.m_yaw_accel_smoothing;
548 : 393 : chassis_smoothing = engine.m_chassis_inertia_smoothing;
549 : 393 : road_fallback_scale = engine.m_road_fallback_scale;
550 : 393 : understeer_affects_sop = engine.m_understeer_affects_sop;
551 : :
552 : : // Slope Detection (v0.7.0)
553 : 393 : slope_detection_enabled = engine.m_slope_detection_enabled;
554 : 393 : slope_sg_window = engine.m_slope_sg_window;
555 : 393 : slope_sensitivity = engine.m_slope_sensitivity;
556 : :
557 : 393 : slope_smoothing_tau = engine.m_slope_smoothing_tau;
558 : :
559 : : // v0.7.3: Slope stability fixes
560 : 393 : slope_alpha_threshold = engine.m_slope_alpha_threshold;
561 : 393 : slope_decay_rate = engine.m_slope_decay_rate;
562 : 393 : slope_confidence_enabled = engine.m_slope_confidence_enabled;
563 : 393 : slope_confidence_max_rate = engine.m_slope_confidence_max_rate;
564 : :
565 : : // v0.7.11: Min/Max thresholds
566 : 393 : slope_min_threshold = engine.m_slope_min_threshold;
567 : 393 : slope_max_threshold = engine.m_slope_max_threshold;
568 : :
569 : : // NEW v0.7.40: Advanced Slope Settings
570 : 393 : slope_g_slew_limit = engine.m_slope_g_slew_limit;
571 : 393 : slope_use_torque = engine.m_slope_use_torque;
572 : 393 : slope_torque_sensitivity = engine.m_slope_torque_sensitivity;
573 : :
574 : 393 : rest_api_enabled = engine.m_rest_api_enabled;
575 : 393 : rest_api_port = engine.m_rest_api_port;
576 : :
577 : 393 : app_version = LMUFFB_VERSION;
578 : 393 : }
579 : :
580 : 459 : bool Equals(const Preset& p) const {
581 : 459 : const float eps = 0.0001f;
582 : 11405 : auto is_near = [](float a, float b, float epsilon) { return std::abs(a - b) < epsilon; };
583 : :
584 [ + + ]: 459 : if (!is_near(gain, p.gain, eps)) return false;
585 [ + + ]: 457 : if (!is_near(understeer, p.understeer, eps)) return false;
586 [ + + ]: 456 : if (!is_near(sop, p.sop, eps)) return false;
587 [ + + ]: 451 : if (!is_near(sop_scale, p.sop_scale, eps)) return false;
588 [ + + ]: 450 : if (!is_near(sop_smoothing, p.sop_smoothing, eps)) return false;
589 [ + + ]: 449 : if (!is_near(slip_smoothing, p.slip_smoothing, eps)) return false;
590 [ + + ]: 448 : if (!is_near(min_force, p.min_force, eps)) return false;
591 [ + + ]: 447 : if (!is_near(oversteer_boost, p.oversteer_boost, eps)) return false;
592 [ + + ]: 440 : if (!is_near(dynamic_weight_gain, p.dynamic_weight_gain, eps)) return false;
593 [ + + ]: 439 : if (!is_near(dynamic_weight_smoothing, p.dynamic_weight_smoothing, eps)) return false;
594 [ + + ]: 438 : if (!is_near(grip_smoothing_steady, p.grip_smoothing_steady, eps)) return false;
595 [ + + ]: 437 : if (!is_near(grip_smoothing_fast, p.grip_smoothing_fast, eps)) return false;
596 [ + + ]: 436 : if (!is_near(grip_smoothing_sensitivity, p.grip_smoothing_sensitivity, eps)) return false;
597 : :
598 [ + + ]: 435 : if (lockup_enabled != p.lockup_enabled) return false;
599 [ + + ]: 434 : if (!is_near(lockup_gain, p.lockup_gain, eps)) return false;
600 [ + + ]: 433 : if (!is_near(lockup_start_pct, p.lockup_start_pct, eps)) return false;
601 [ + + ]: 432 : if (!is_near(lockup_full_pct, p.lockup_full_pct, eps)) return false;
602 [ + + ]: 431 : if (!is_near(lockup_rear_boost, p.lockup_rear_boost, eps)) return false;
603 [ + + ]: 430 : if (!is_near(lockup_gamma, p.lockup_gamma, eps)) return false;
604 [ + + ]: 429 : if (!is_near(lockup_prediction_sens, p.lockup_prediction_sens, eps)) return false;
605 [ + + ]: 428 : if (!is_near(lockup_bump_reject, p.lockup_bump_reject, eps)) return false;
606 [ + + ]: 427 : if (!is_near(brake_load_cap, p.brake_load_cap, eps)) return false;
607 [ + + ]: 426 : if (!is_near(texture_load_cap, p.texture_load_cap, eps)) return false;
608 : :
609 [ + + ]: 425 : if (abs_pulse_enabled != p.abs_pulse_enabled) return false;
610 [ + + ]: 68 : if (!is_near(abs_gain, p.abs_gain, eps)) return false;
611 [ + + ]: 67 : if (!is_near(abs_freq, p.abs_freq, eps)) return false;
612 : :
613 [ + + ]: 66 : if (spin_enabled != p.spin_enabled) return false;
614 [ - + ]: 65 : if (!is_near(spin_gain, p.spin_gain, eps)) return false;
615 [ + + ]: 65 : if (!is_near(spin_freq_scale, p.spin_freq_scale, eps)) return false;
616 : :
617 [ + + ]: 64 : if (slide_enabled != p.slide_enabled) return false;
618 [ + + ]: 63 : if (!is_near(slide_gain, p.slide_gain, eps)) return false;
619 [ + + ]: 62 : if (!is_near(slide_freq, p.slide_freq, eps)) return false;
620 : :
621 [ + + ]: 61 : if (road_enabled != p.road_enabled) return false;
622 [ + + ]: 60 : if (!is_near(road_gain, p.road_gain, eps)) return false;
623 [ - + ]: 59 : if (!is_near(vibration_gain, p.vibration_gain, eps)) return false;
624 : :
625 [ - + ]: 59 : if (dynamic_normalization_enabled != p.dynamic_normalization_enabled) return false;
626 [ - + ]: 59 : if (auto_load_normalization_enabled != p.auto_load_normalization_enabled) return false;
627 : :
628 [ + + ]: 59 : if (soft_lock_enabled != p.soft_lock_enabled) return false;
629 [ + + ]: 58 : if (!is_near(soft_lock_stiffness, p.soft_lock_stiffness, eps)) return false;
630 [ - + ]: 57 : if (!is_near(soft_lock_damping, p.soft_lock_damping, eps)) return false;
631 : :
632 [ + + ]: 57 : if (!is_near(wheelbase_max_nm, p.wheelbase_max_nm, eps)) return false;
633 [ + + ]: 56 : if (!is_near(target_rim_nm, p.target_rim_nm, eps)) return false;
634 [ + + ]: 55 : if (!is_near(lockup_freq_scale, p.lockup_freq_scale, eps)) return false;
635 [ + + ]: 54 : if (bottoming_method != p.bottoming_method) return false;
636 [ + + ]: 53 : if (!is_near(scrub_drag_gain, p.scrub_drag_gain, eps)) return false;
637 [ + + ]: 52 : if (!is_near(rear_align_effect, p.rear_align_effect, eps)) return false;
638 [ + + ]: 51 : if (!is_near(sop_yaw_gain, p.sop_yaw_gain, eps)) return false;
639 [ + + ]: 50 : if (!is_near(gyro_gain, p.gyro_gain, eps)) return false;
640 [ + + ]: 49 : if (!is_near(steering_shaft_gain, p.steering_shaft_gain, eps)) return false;
641 [ + + ]: 48 : if (!is_near(ingame_ffb_gain, p.ingame_ffb_gain, eps)) return false;
642 [ + + ]: 47 : if (torque_source != p.torque_source) return false;
643 [ + + ]: 42 : if (torque_passthrough != p.torque_passthrough) return false;
644 : :
645 [ + + ]: 41 : if (!is_near(optimal_slip_angle, p.optimal_slip_angle, eps)) return false;
646 [ + + ]: 40 : if (!is_near(optimal_slip_ratio, p.optimal_slip_ratio, eps)) return false;
647 [ + + ]: 39 : if (!is_near(steering_shaft_smoothing, p.steering_shaft_smoothing, eps)) return false;
648 [ + + ]: 38 : if (!is_near(gyro_smoothing, p.gyro_smoothing, eps)) return false;
649 [ + + ]: 37 : if (!is_near(yaw_smoothing, p.yaw_smoothing, eps)) return false;
650 [ + + ]: 36 : if (!is_near(chassis_smoothing, p.chassis_smoothing, eps)) return false;
651 : :
652 [ + + ]: 35 : if (flatspot_suppression != p.flatspot_suppression) return false;
653 [ + + ]: 34 : if (!is_near(notch_q, p.notch_q, eps)) return false;
654 [ + + ]: 33 : if (!is_near(flatspot_strength, p.flatspot_strength, eps)) return false;
655 : :
656 [ + + ]: 32 : if (static_notch_enabled != p.static_notch_enabled) return false;
657 [ + + ]: 31 : if (!is_near(static_notch_freq, p.static_notch_freq, eps)) return false;
658 [ + + ]: 30 : if (!is_near(static_notch_width, p.static_notch_width, eps)) return false;
659 [ + + ]: 29 : if (!is_near(yaw_kick_threshold, p.yaw_kick_threshold, eps)) return false;
660 : :
661 [ + + ]: 28 : if (!is_near(speed_gate_lower, p.speed_gate_lower, eps)) return false;
662 [ + + ]: 27 : if (!is_near(speed_gate_upper, p.speed_gate_upper, eps)) return false;
663 : :
664 [ + + ]: 26 : if (!is_near(road_fallback_scale, p.road_fallback_scale, eps)) return false;
665 [ + + ]: 25 : if (understeer_affects_sop != p.understeer_affects_sop) return false;
666 : :
667 [ + + ]: 24 : if (slope_detection_enabled != p.slope_detection_enabled) return false;
668 [ + + ]: 23 : if (slope_sg_window != p.slope_sg_window) return false;
669 [ - + ]: 22 : if (!is_near(slope_sensitivity, p.slope_sensitivity, eps)) return false;
670 : :
671 [ + + ]: 22 : if (!is_near(slope_smoothing_tau, p.slope_smoothing_tau, eps)) return false;
672 [ + + ]: 21 : if (!is_near(slope_alpha_threshold, p.slope_alpha_threshold, eps)) return false;
673 [ + + ]: 20 : if (!is_near(slope_decay_rate, p.slope_decay_rate, eps)) return false;
674 [ + + ]: 19 : if (slope_confidence_enabled != p.slope_confidence_enabled) return false;
675 [ + + ]: 18 : if (!is_near(slope_min_threshold, p.slope_min_threshold, eps)) return false;
676 [ + + ]: 17 : if (!is_near(slope_max_threshold, p.slope_max_threshold, eps)) return false;
677 : :
678 [ + + ]: 16 : if (!is_near(slope_g_slew_limit, p.slope_g_slew_limit, eps)) return false;
679 [ + + ]: 15 : if (slope_use_torque != p.slope_use_torque) return false;
680 [ - + ]: 14 : if (!is_near(slope_torque_sensitivity, p.slope_torque_sensitivity, eps)) return false;
681 [ + + ]: 14 : if (!is_near(slope_confidence_max_rate, p.slope_confidence_max_rate, eps)) return false;
682 : :
683 [ - + ]: 13 : if (rest_api_enabled != p.rest_api_enabled) return false;
684 [ - + ]: 13 : if (rest_api_port != p.rest_api_port) return false;
685 : :
686 : 13 : return true;
687 : : }
688 : : };
689 : :
690 : : class Config {
691 : : public:
692 : : static std::string m_config_path; // Default: "config.ini"
693 : : static void Save(const FFBEngine& engine, const std::string& filename = "");
694 : : static void Load(FFBEngine& engine, const std::string& filename = "");
695 : :
696 : : // Preset Management
697 : : static std::vector<Preset> presets;
698 : : static std::string m_last_preset_name; // NEW (v0.7.14)
699 : : static void LoadPresets(); // Populates presets vector
700 : : static void ApplyPreset(int index, FFBEngine& engine);
701 : :
702 : : // NEW: Add a user preset
703 : : static void AddUserPreset(const std::string& name, const FFBEngine& engine);
704 : :
705 : : // NEW: Delete and Duplicate (v0.7.14)
706 : : static void DeletePreset(int index, const FFBEngine& engine);
707 : : static void DuplicatePreset(int index, const FFBEngine& engine);
708 : : static bool IsEngineDirtyRelativeToPreset(int index, const FFBEngine& engine);
709 : :
710 : : // NEW: Import/Export (v0.7.12)
711 : : static void ExportPreset(int index, const std::string& filename);
712 : : static bool ImportPreset(const std::string& filename, const FFBEngine& engine);
713 : :
714 : : // NEW: Persist selected device
715 : : static std::string m_last_device_guid;
716 : :
717 : : // Global App Settings (not part of FFB Physics)
718 : : static bool m_always_on_top; // NEW: Keep window on top
719 : : static bool m_auto_start_logging; // NEW: Auto-start logging
720 : : static std::string m_log_path; // NEW: Path to save logs
721 : :
722 : : // Window Geometry Persistence (v0.5.5)
723 : : static int win_pos_x, win_pos_y;
724 : : static int win_w_small, win_h_small; // Dimensions for Config Only
725 : : static int win_w_large, win_h_large; // Dimensions for Config + Graphs
726 : : static bool show_graphs; // Remember if graphs were open
727 : :
728 : : // Persistent storage for vehicle static loads (v0.7.70)
729 : : static std::map<std::string, double> m_saved_static_loads;
730 : : static std::recursive_mutex m_static_loads_mutex;
731 : :
732 : : // Flag to request a save from the main thread (avoids File I/O on FFB thread)
733 : : static std::atomic<bool> m_needs_save;
734 : :
735 : : // Thread-safe access to static loads map (v0.7.70)
736 : : static void SetSavedStaticLoad(const std::string& vehicleName, double value);
737 : : static bool GetSavedStaticLoad(const std::string& vehicleName, double& value);
738 : :
739 : : private:
740 : : // Helper for parsing preset lines (v0.7.12)
741 : : static void ParsePresetLine(const std::string& line, Preset& p, std::string& version, bool& needs_save, bool& legacy_torque_hack, float& legacy_torque_val);
742 : : // Helper for writing preset fields (v0.7.12)
743 : : static void WritePresetFields(std::ofstream& file, const Preset& p);
744 : : };
745 : :
746 : :
747 : :
748 : :
749 : : #endif
750 : :
751 : :
752 : :
753 : :
754 : :
|