Last active
August 4, 2023 10:20
-
-
Save pardeike/bbca95e843358ec84ef91bd71a156197 to your computer and use it in GitHub Desktop.
A debouncer for RimWorld modding - delaying actions to a global tick method if necessary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using HarmonyLib; | |
using Verse; | |
public class Debouncer | |
{ | |
private Debouncer() { } | |
private readonly int tickThrottle; | |
private readonly bool onlyWhenRunning; | |
private int nextExecution; | |
private Action delayedAction; | |
private static readonly List<Debouncer> debouncers = new(); | |
private static int gameTicks; | |
private static Harmony harmony; | |
private const string harmonyID = "brrainz.debouncer"; | |
public Debouncer(int tickThrottle, bool onlyWhenRunning) | |
{ | |
this.tickThrottle = tickThrottle; | |
this.onlyWhenRunning = onlyWhenRunning; | |
if (harmony == null) | |
{ | |
var m_UpdatePlay = SymbolExtensions.GetMethodInfo((Game game) => game.UpdatePlay()); | |
var m_Tick = SymbolExtensions.GetMethodInfo(() => Tick()); | |
harmony = new Harmony(harmonyID); | |
harmony.Patch(m_UpdatePlay, postfix: new HarmonyMethod(m_Tick) { priority = Priority.VeryLow }); | |
} | |
debouncers.Add(this); | |
} | |
private static void Tick() | |
{ | |
gameTicks++; | |
var debouncerCount = debouncers.Count; | |
var running = Find.TickManager.Paused == false; | |
for (var i = 0; i < debouncerCount; i++) | |
{ | |
var debouncer = debouncers[i]; | |
if (gameTicks >= debouncer.nextExecution && (debouncer.onlyWhenRunning == false || running)) | |
{ | |
var action = debouncer.delayedAction; | |
if (action != null) | |
{ | |
debouncer.nextExecution = gameTicks + debouncer.tickThrottle; | |
debouncer.delayedAction = null; | |
action(); | |
return; | |
} | |
} | |
} | |
} | |
public void Remove() => debouncers.Remove(this); | |
public void Run(Action action) | |
{ | |
if (delayedAction == null && tickThrottle > 0 && gameTicks >= nextExecution) | |
{ | |
nextExecution = gameTicks + tickThrottle; | |
delayedAction = null; | |
action(); | |
return; | |
} | |
delayedAction = action; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment