| name | oxgkit-unity-skill |
| description | Use when developing or reviewing Unity projects that use OxGKit.TimeSystem, including RealTime startup time, RealTimer and DeltaTimer (timer/tick/mark), RTUpdater and DTUpdater update loops with timeScale and targetFrameRate, IntervalSetter/IntervalTimer periodic calls, and NtpTime NTP server clock synchronization. |
OxGKit.TimeSystem Unity Skill
Purpose
Make the agent behave like an experienced OxGKit.TimeSystem user. The module (UPM package com.michaelo.oxgkit.timesystem, UniTask-based) provides time controllers: real-time and delta-time timers, standalone update loops that run independently of MonoBehaviours, setInterval-style periodic tickers, and NTP clock synchronization for server-authoritative time.
First response rules
- Reply in the user's language; keep code and identifiers in English.
- Start with the conclusion, then implementation details.
- Verify APIs against the installed package (
Library/PackageCache/com.michaelo.oxgkit.timesystem@* or Assets/OxGKit/TimeSystem/Scripts when embedded). Do not invent APIs.
- When choosing a timer/updater, state whether the use case must ignore
Time.timeScale (real time) or follow it (game time) — that decides Real* vs Delta*/DT*.
Install
- UPM git URL:
https://github.com/michael811125/OxGKit.git?path=Assets/OxGKit/TimeSystem/Scripts
- Auto dependencies:
com.cysharp.unitask, com.michaelo.oxgkit.loggingsystem.
- Samples (Package Manager > OxGKit.TimeSystem > Samples):
Timer Demo, AI Agent Skills (this skill).
Module map (pick the right tool)
| Type | Time base | Driven by | Use for |
|---|
RealTimer | real clock (needs RealTime.InitStartupTime()) | self (query-based) | cooldowns/countdowns that must ignore pause & timeScale |
DeltaTimer | accumulated dt you feed | owner calls UpdateTimer(dt) | game-time cooldowns that pause with your feature |
RTUpdater | real clock (UniTask loop) | Start() / StartOnThread() | update loops independent of Unity timeScale (e.g. network heartbeat) |
DTUpdater | Unity-scaled time (UniTask loop) | Start() | update loops that respect Time.timeScale |
IntervalSetter / IntervalTimer | ms interval | static helper | fire an Action every N milliseconds |
NtpTime | NTP / time API server | Synchronize() once | anti-cheat server clock, daily reset timing |
Core API (verified)
using OxGKit.TimeSystem;
RealTime.InitStartupTime();
bool inited = RealTime.IsInitStartupTime();
System.DateTime startup = RealTime.timeSinceStartup;
var timer = new RealTimer(true);
timer.Play(); timer.Pause(); timer.Stop(); timer.Reset();
timer.IsPlaying(); timer.IsPause();
timer.GetTime();
timer.SetTimeSpeed(2f); timer.GetTimeSpeed();
timer.SetTimer(3f);
timer.TimerCountdown();
timer.IsTimerTimeout();
timer.GetTimerCountdownRatio();
timer.SetTick(0.5f);
if (timer.IsTickTimeout()) { }
timer.GetTick(); timer.TickCountdown(); timer.GetTickCountdownRatio();
timer.SetMark();
float elapsed = timer.GetElapsedMarkTime();
var dTimer = new DeltaTimer(true);
void Update() { dTimer.UpdateTimer(Time.deltaTime); }
var updater = new RTUpdater();
updater.onUpdate += dt => { };
updater.onFixedUpdate += fdt => { };
updater.onLateUpdate += dt => { };
updater.timeScale = 1f;
updater.targetFrameRate = ;
updater.Start();
updater.Stop();
updater.IsRunning();
IntervalSetter.SetInterval(, () => Poll(), );
IntervalSetter.SetInterval(, () => Poll(), );
IntervalTimer handle = IntervalSetter.SetInterval(() => Poll(), );
IntervalSetter.SetIntervalOnThread(...);
IntervalSetter.CheckIsRunning();
IntervalSetter.TryClearInterval();
IntervalSetter.ClearAllIntervalTimers();
NtpTime.Synchronize();
ok = NtpTime.IsSynchronized();
System.DateTime utc = NtpTime.GetUtcNow();
System.DateTime local = NtpTime.GetNow();
System.DateTime raw = NtpTime.GetNtpDate();
zone = NtpTime.GetTimeZone();
off = NtpTime.GetUtcOffset();
Usage patterns
Cooldown that survives pause menus (real time):
RealTime.InitStartupTime();
var cd = new RealTimer(true);
cd.SetTimer(10f);
if (cd.IsTimerTimeout()) { }
Feature-owned game-time ticker:
var ticker = new DeltaTimer(true);
ticker.SetTick(1f);
void Update()
{
ticker.UpdateTimer(Time.deltaTime);
if (ticker.IsTickTimeout()) RefreshPerSecondUI();
}
Non-MonoBehaviour system loop (e.g., driving OxGKit.ActionSystem or a network node):
var rt = new RTUpdater();
rt.onUpdate += dt => runner.DriveUpdate(dt);
rt.Start();
rt.Stop();
Rules & pitfalls
- Call
RealTime.InitStartupTime() once at app start before using RealTimer; all real-time values are measured from it.
IsTickTimeout() re-arms the tick automatically — call it exactly once per frame per consumer, or ticks will be consumed by the wrong caller.
DeltaTimer/DTUpdater freeze when their owner stops feeding/Time.timeScale is 0; RealTimer/RTUpdater do not — pick deliberately.
- Always
Stop() updaters and TryClearInterval interval timers when the owning feature/scene exits; they are UniTask loops and keep running otherwise.
NtpTime.Synchronize() is async — gate reads on IsSynchronized(); unsynced getters silently return local time with only a log warning. UDP NTP may be blocked on some platforms (e.g., WebGL); the generic Synchronize<TResponseFormat> overload supports HTTP time-API responses instead.
StartOnThread/SetIntervalOnThread callbacks run off the Unity main thread — do not touch UnityEngine objects from them (marshal back, e.g. with a main-thread dispatcher).
Verify
- Enter Play mode: pause the game (
Time.timeScale = 0) and confirm Real* keeps counting while DT*/DeltaTimer stops.
- Confirm interval callbacks stop after
TryClearInterval/Stop() (no logs after leaving the scene).