Universal - Game Time - Detector (Pro)
In Unity, frame-based calculations rely heavily on UnityEngine.Time.deltaTime. Unfortunately, this time calculation is vulnerable to manipulation by cheat or hacking tools that allow unwanted acceleration, deceleration, or interruption of your game. AntiCheat has introduced a way to counteract such time manipulation.
Detector
The 'GameTimeCheatingDetector' (class GameTimeCheatingDetector, namespace GUPS.AntiCheat.Detector) detects manipulation of Unity's game time (UnityEngine.Time.deltaTime and fixedDeltaTime), commonly caused by SpeedHack-style tools. It subscribes to the 'GameTimeMonitor' and evaluates the reported time deviations. In addition, once cheating is detected it starts a countermeasure: it calculates the game time from system ticks so that the value stays correct even while Time is being manipulated, and exposes it through GUPS.AntiCheat.Protected.Time.ProtectedTime.
Observed subject
The detector subscribes in Awake to the GameTimeStatus published by the 'GameTimeMonitor' that sits on the same GameObject. If no monitor is present on the same GameObject, the detector logs a warning and stays idle.
Status
The detector notifies its observers with a CheatingDetectionStatus, which implements IDetectorStatus:
public struct CheatingDetectionStatus : IDetectorStatus
{
// Probability that the detection is a false positive, in the range [0.0, 1.0].
public float PossibilityOfFalsePositive { get; }
// The threat rating reported with this detection.
public uint ThreatRating { get; }
}
Threat rating and false positives
- PossibilityOfFalsePositive:
0.45(fixed). It is intentionally high because the game time monitor is sensitive to legitimate CPU or GC spikes. - ThreatRating: default
25(inspector field, recommended 25). It is kept low because false positives are likely and many small detections may be sent to the AntiCheat-Monitor.
Lifecycle and timing
- Subscribes to the monitor in
Awakeand resets its time state. - Refreshes its internal time every frame in
Update; resets the UTC reference onOnApplicationFocus/OnApplicationPause, and resets the level time on scene load. - Delta-time detection is windowed: it feeds each
DeltaDeviationinto a rolling window of 25 samples and reports cheating once at least half of the window shows the same non-Nonedeviation. - After cheating is detected the detector is one-shot: it stops processing further monitor notifications and switches
ProtectedTimeto the system-tick fallback.
Configuration
- Is Active (
isActive, bool, default true) - whether the detector is active and watching. - Threat Rating (
threatRating, uint, default 25) - the threat rating reported on each detection. - Detect Delta Time Cheating (
DetectDeltaTimeCheating, bool, default true) - react todeltaTimemanipulation, commonly used to speed up or slow down the game. - Detect Fixed Delta Time Cheating (
DetectFixedDeltaTimeCheating, bool, default false) - react tofixedDeltaTimemanipulation, often used to skip physics updates (e.g. to walk through walls). When enabled, you must use theProtectedTime.fixedDeltaTimesetter to update the fixed delta time. - On Cheating Detection Event (
OnCheatingDetectionEvent) - a UnityEvent raised on every detection; wire up reactions in the inspector without writing an observer.
Supported platforms
The detector is available on all platforms.
Requirements
There are no requirements. A 'GameTimeMonitor' must be present on the same GameObject.
How To Use
Attach a 'GameTimeMonitor' (if not already done) and the 'GameTimeCheatingDetector' to a child GameObject of the 'AntiCheat-Monitor', then define a reaction to detected cheating.
Add Monitor Component
To detect game time manipulation, a source of game time deviation data is required. Add the 'GameTimeMonitor' to the same GameObject you attach the 'GameTimeCheatingDetector' to. The detector subscribes to the 'GameTimeStatus' sent by the monitor.
Add Detector Component
Manual
Add the 'GameTimeCheatingDetector' MonoBehavior from the 'GUPS.AntiCheat.Detector' namespace to your 'AntiCheat-Monitor' GameObject, or better, to a child GameObject, next to your 'GameTimeMonitor' MonoBehavior.

Add the 'GameTimeCheatingDetector' as a Component.
Prefab
There is also a prefab, including the detector and the monitor, which you can directly attach as a GameObject to the 'AntiCheat-Monitor'.

Add the 'Game Time Cheating Detector' prefab to the 'AntiCheat-Monitor'.
Settings
After attaching the 'GameTimeCheatingDetector' MonoBehavior to a GameObject, you will see the following in the inspector:

The settings of the 'GameTimeCheatingDetector' Component.
- General Settings: Define here whether the detector should be active.
- Threat Rating Settings: Define here the severity of the detected cheating.
- Detection Settings: Choose whether to react to delta time and/or fixed delta time cheating.
- Observable Settings: Add here callbacks invoked when cheating is detected.
Runtime
Once cheating is detected, the detector provides a trustworthy game time derived from system ticks, exposed by the ProtectedTime class. Replace your usage of UnityEngine.Time with GUPS.AntiCheat.Protected.Time.ProtectedTime:
// Replace your usage of the UnityEngine.Time class with GUPS.AntiCheat.Protected.Time.ProtectedTime.
public static class ProtectedTime
{
// The time in seconds it took to complete the last frame (Read Only).
public static float deltaTime { get; }
// The real time in seconds since the game started (Read Only).
public static float realtimeSinceStartup { get; }
// The time at the beginning of this frame (Read Only). This is the time in seconds since the start of the game.
public static float time { get; }
// The scale at which the time is passing. This can be used for slow motion effects.
public static float timeScale { get; set; }
// The time this frame has started (Read Only). This is the time in seconds since the last level has been loaded.
public static float timeSinceLevelLoad { get; }
// The timeScale-independent interval in seconds from the last frame to the current one (Read Only).
public static float unscaledDeltaTime { get; }
// The timeScale-independent time for this frame (Read Only). This is the time in seconds since the start of the game.
public static float unscaledTime { get; }
}
Consume the detection in code
Besides the inspector event, you can subscribe your own observer. Every detector derives from ADetector and exposes Subscribe(IObserver<IDetectorStatus>), which returns an IDisposable you can dispose to unsubscribe. Get the detector via the AntiCheat-Monitor:
using System;
using GUPS.AntiCheat;
using GUPS.AntiCheat.Core.Detector;
using GUPS.AntiCheat.Detector;
using UnityEngine;
public class GameTimeDetectionLogger : MonoBehaviour, IObserver<IDetectorStatus>
{
private void Start()
{
var detector = AntiCheatMonitor.Instance.GetDetector<GameTimeCheatingDetector>();
detector.Subscribe(this);
}
public void OnNext(IDetectorStatus status)
{
Debug.LogWarning($"Game time cheating detected (threat={status.ThreatRating}, fp={status.PossibilityOfFalsePositive}).");
}
public void OnError(Exception error) { }
public void OnCompleted() { }
}
React On Cheating
When the monitor (data provider) and detector (data validator) are set up, you surely want to react to detected cheating.
Punisher
In general, any cheat detected is forwarded to the 'AntiCheat-Monitor', which calculates an overall threat level. Based on the threat level, you can apply punishments by using Punisher components added to a child GameObject of the 'AntiCheat-Monitor'. There are some built-in punishers that you can find here as prefabs:

The location of the built-in Punisher prefabs.
Inspector
You can set a callback in the Unity Inspector view of the detector. This callback is invoked as soon as the specific cheating is detected.

A list of callbacks invoked when cheating is detected by the detector.
Code
If you would like to write a custom listener for the detector, you can attach an observer:
// Get the detector.
var detector = AntiCheatMonitor.Instance
.GetDetector<GameTimeCheatingDetector>();
// Subscribe as observer and get notified on inconsistency.
detector.Subscribe(myObserver);
The detector also has an inherited property 'PossibleCheatingDetected' which is set to true once cheating has been detected.