Custom Time Bridge / Integrations
v1.0
If your game has its own time system (e.g. a game “time manager” with variable clocks), you can integrate it with Juicy Actions by making your own bridge / resolver, similar to the Magic Time Integration.

1. Create a Clock Resolver
A resolver simply tells Juicy Actions:
"If this
GameObject
users my time system, give it my clock instead of the Juicy Action clock."
Here's an example. Here you'd replace IMyTimeProvider
with your own interface or component.
using UnityEngine;
using MagicPigGames.ActionSystem;
namespace YourNamespace.JuicyActionsIntegration
{
public sealed class MyTimeClockResolver : IClockResolver
{
public int Priority => 900; // Something high
public IClock ResolveFor(Component target, ActionExecutor executor)
{
// Look for your own time provider
var provider = target.GetComponentInParent<IMyTimeProvider>();
if (provider != null)
return new MyTimeObjectClock(provider);
return null; // fallback to default
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
private static void Install() => ActionClock.Register(new MyTimeClockResolver());
}
}
2. Wrap Your Time System in an IClock
Adapter
IClock
AdapterYou can call this something other than MyTimeObjectClock
if you'd prefer, and use the same interface as you did in step 1.
public sealed class MyTimeObjectClock : IClock
{
private readonly IMyTimeProvider _provider;
public MyTimeObjectClock(IMyTimeProvider provider) => _provider = provider;
// These are the values that will be brought over from your time system!
public float Time => _provider.CurrentTime;
public float UnscaledTime => _provider.UnscaledTime;
public float DeltaTime => _provider.Delta;
public float UnscaledDeltaTime => _provider.UnscaledDelta;
public float TimeScale => _provider.TimeScale;
public async ValueTask Delay(float seconds, CancellationToken ct)
{
float elapsed = 0f;
while (elapsed < seconds)
{
ct.ThrowIfCancellationRequested();
elapsed += _provider.DeltaTime;
await Task.Yield();
}
}
}
This pattern is exactly what MagicTimeClockResolver
and MagicTimeObjectClock
do internally — it’s just type-safe and localized to your own interfaces.
Interface Expectations
Your custom time provider (the thing your game already uses) only needs to expose the same shape of data expected by the adapter:
public interface IMyTimeProvider
{
float Time { get; }
float DeltaTime { get; }
float UnscaledTime { get; }
float UnscaledDeltaTime { get; }
float TimeScale { get; }
}
If your system already has different names (e.g., GameTime
, DeltaGameTime
), you can simply map them in your MyTimeObjectClock
.
Full Sample Code
This is a full code sample that you may wish to refer to, or pass into your favorite AI to help you create your bridge.
// File: YourTimeClockResolver.cs
// Namespace can match your package layout.
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace MagicPigGames.ActionSystem.CustomTimeIntegration
{
/// <summary>
/// Provide a minimal contract your time system can implement.
/// You can replace this with the actual interface from the other package.
/// </summary>
public interface IMyTimeProvider
{
float CurrentTime { get; }
float Delta { get; }
float UnscaledTime { get; }
float UnscaledDelta { get; }
float TimeScale { get; }
}
/// <summary>
/// Adapter that turns any IMyTimeProvider into an Action System IClock.
/// </summary>
public sealed class MyTimeObjectClock : IClock
{
private readonly IMyTimeProvider _src;
public MyTimeObjectClock(IMyTimeProvider src) => _src = src;
public float Time => _src?.CurrentTime ?? ActionSystemClock.Instance.Time;
public float UnscaledTime => _src?.UnscaledTime ?? ActionSystemClock.Instance.UnscaledTime;
public float DeltaTime => _src?.Delta ?? ActionSystemClock.Instance.DeltaTime;
public float UnscaledDeltaTime => _src?.UnscaledDelta ?? ActionSystemClock.Instance.UnscaledDeltaTime;
public float TimeScale => _src?.TimeScale ?? ActionSystemClock.Instance.TimeScale;
public async ValueTask Delay(float seconds, CancellationToken ct)
{
// Delegate to the active ActionSystemClock for consistency
var fallback = ActionSystemClock.Instance;
var remaining = Mathf.Max(0f, seconds);
while (remaining > 0f)
{
ct.ThrowIfCancellationRequested();
remaining -= (_src?.Delta ?? fallback.DeltaTime);
await Task.Yield();
}
}
}
/// <summary>
/// IClockResolver that auto-detects IMyTimeProvider on the target or its parents.
/// Registers itself automatically on load.
/// </summary>
public sealed class MyTimeClockResolver : IClockResolver
{
/// <summary>
/// Priority of this resolver. Higher beats lower.
/// Use something below Magic Time (1000) if you want Magic Time to win when both exist.
/// </summary>
public int Priority => 900;
public IClock ResolveFor(Component target, ActionExecutor executor)
{
if (!target) return null;
// Find a provider on target or in its parents.
var provider = target.GetComponentInParent<IMyTimeProvider>();
if (provider != null)
return new MyTimeObjectClock(provider);
return null; // fall back to default Unity clock
}
// Auto-register once the app domain is ready.
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
private static void Install()
{
ActionClock.Register(new MyTimeClockResolver());
}
}
}
Last updated
Was this helpful?