railroader-setons-special-s.../src/Modules/BaseGamePerf/BaseGamePerfModule.cs
seton e8aeb2d6a3 BaseGamePerf: GC smoothing and Nature Renderer grass streaming caps
Spreads incremental GC across more frames and caps grass-cell work so
abrupt camera looks hitch less. Density, draw distance, and simulation
stay the same. Original values restore when the module is disabled.
2026-09-11 15:19:22 -04:00

82 lines
2.6 KiB
C#

using S3.Core;
using UnityEngine;
using UnityEngine.Scripting;
namespace S3.Modules.BaseGamePerf;
public sealed class BaseGamePerfModule : IModule
{
const string SettingsFile = "S3.basegame.json";
static bool _hasOriginal;
static ulong _originalSliceNanoseconds;
public static BaseGamePerfSettings Settings { get; private set; } = new();
public BaseGamePerfModule() =>
Settings = SettingsStore.Load<BaseGamePerfSettings>(SettingsFile);
public string Id => "basegame";
public string DisplayName => "Base Game Performance";
public string Description =>
"Evidence-backed vanilla-game hitch controls. Smooths incremental GC and " +
"Nature Renderer grass-cell streaming without reducing density, draw distance, " +
"resolution, or simulation quality.";
public bool Enabled
{
get => Settings.enabled;
set => Settings.enabled = value;
}
public void OnEnable()
{
if (!_hasOriginal)
{
_originalSliceNanoseconds = GarbageCollector.incrementalTimeSliceNanoseconds;
_hasOriginal = true;
}
try { NatureStreamingOptimizer.Enable(); }
catch (System.Exception ex)
{
Log.Warn(
"[basegame] Nature streaming smoothing unavailable: " +
ex.GetBaseException().Message);
}
ApplyRuntimeSettings();
}
public void OnDisable()
{
NatureStreamingOptimizer.Disable();
if (_hasOriginal)
{
GarbageCollector.incrementalTimeSliceNanoseconds = _originalSliceNanoseconds;
Log.Info(
$"[basegame] Restored incremental GC slice to " +
$"{_originalSliceNanoseconds / 1_000_000.0:0.###}ms.");
}
}
public static void ApplyRuntimeSettings()
{
if (!GarbageCollector.isIncremental)
{
Log.Warn("[basegame] Unity incremental GC is disabled; smoothing was not applied.");
return;
}
ulong desired = Settings.gcSmoothingEnabled
? (ulong)(Mathf.Clamp(Settings.incrementalSliceMs, 0.25f, 5f) * 1_000_000f)
: _originalSliceNanoseconds;
GarbageCollector.incrementalTimeSliceNanoseconds = desired;
Log.Info(
$"[basegame] Incremental GC slice={desired / 1_000_000.0:0.###}ms " +
$"(smoothing={Settings.gcSmoothingEnabled}).");
NatureStreamingOptimizer.ApplySettings();
}
public void SaveSettings() => Persist();
public static void Persist() => SettingsStore.Save(SettingsFile, Settings);
public void DrawSettings() => BaseGamePerfSettingsUI.Draw();
}