canto/Assets/Scripts/Extension/R3.cs
2025-07-16 23:35:29 -04:00

182 lines
No EOL
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using R3;
using UnityEngine;
namespace KitsuneCafe.Extension
{
public static class R3Extensions
{
private readonly struct TimeProviderInfo
{
public readonly FrameProvider FrameProvider;
public readonly TimeKind TimeKind;
public TimeProviderInfo(FrameProvider frameProvider, TimeKind timeKind)
{
FrameProvider = frameProvider;
TimeKind = timeKind;
}
}
private static readonly Dictionary<TimeProvider, TimeProviderInfo> timeProviderInfo = new()
{
{ UnityTimeProvider.Initialization, new (UnityFrameProvider.Initialization, TimeKind.Time) },
{ UnityTimeProvider.EarlyUpdate, new (UnityFrameProvider.EarlyUpdate, TimeKind.Time) },
{ UnityTimeProvider.FixedUpdate, new (UnityFrameProvider.FixedUpdate, TimeKind.Time) },
{ UnityTimeProvider.PreUpdate, new (UnityFrameProvider.PreUpdate, TimeKind.Time) },
{ UnityTimeProvider.Update, new (UnityFrameProvider.Update, TimeKind.Time) },
{ UnityTimeProvider.PreLateUpdate, new (UnityFrameProvider.PreLateUpdate, TimeKind.Time) },
{ UnityTimeProvider.PostLateUpdate, new (UnityFrameProvider.PostLateUpdate, TimeKind.Time) },
{ UnityTimeProvider.TimeUpdate, new (UnityFrameProvider.TimeUpdate, TimeKind.Time) },
{ UnityTimeProvider.InitializationIgnoreTimeScale, new (UnityFrameProvider.Initialization, TimeKind.UnscaledTime) },
{ UnityTimeProvider.EarlyUpdateIgnoreTimeScale, new (UnityFrameProvider.EarlyUpdate, TimeKind.UnscaledTime) },
{ UnityTimeProvider.FixedUpdateIgnoreTimeScale, new (UnityFrameProvider.FixedUpdate, TimeKind.UnscaledTime) },
{ UnityTimeProvider.PreUpdateIgnoreTimeScale, new (UnityFrameProvider.PreUpdate, TimeKind.UnscaledTime) },
{ UnityTimeProvider.UpdateIgnoreTimeScale, new (UnityFrameProvider.Update, TimeKind.UnscaledTime) },
{ UnityTimeProvider.PreLateUpdateIgnoreTimeScale, new (UnityFrameProvider.PreLateUpdate, TimeKind.UnscaledTime) },
{ UnityTimeProvider.PostLateUpdateIgnoreTimeScale, new (UnityFrameProvider.PostLateUpdate, TimeKind.UnscaledTime) },
{ UnityTimeProvider.TimeUpdateIgnoreTimeScale, new (UnityFrameProvider.TimeUpdate, TimeKind.UnscaledTime) },
{ UnityTimeProvider.InitializationRealtime, new (UnityFrameProvider.Initialization, TimeKind.Realtime) },
{ UnityTimeProvider.EarlyUpdateRealtime, new (UnityFrameProvider.EarlyUpdate, TimeKind.Realtime) },
{ UnityTimeProvider.FixedUpdateRealtime, new (UnityFrameProvider.FixedUpdate, TimeKind.Realtime) },
{ UnityTimeProvider.PreUpdateRealtime, new (UnityFrameProvider.PreUpdate, TimeKind.Realtime) },
{ UnityTimeProvider.UpdateRealtime, new (UnityFrameProvider.Update, TimeKind.Realtime) },
{ UnityTimeProvider.PreLateUpdateRealtime, new (UnityFrameProvider.PreLateUpdate, TimeKind.Realtime) },
{ UnityTimeProvider.PostLateUpdateRealtime, new (UnityFrameProvider.PostLateUpdate, TimeKind.Realtime) },
{ UnityTimeProvider.TimeUpdateRealtime, new (UnityFrameProvider.TimeUpdate, TimeKind.Realtime) }
};
public enum PlayerLoopTiming
{
Initialization,
EarlyUpdate,
FixedUpdate,
PreUpdate,
Update,
PreLateUpdate,
PostLateUpdate,
TimeUpdate,
PostFixedUpdate
}
private static readonly Dictionary<FrameProvider, PlayerLoopTiming> frameProviderTiming = new()
{
{ UnityFrameProvider.Initialization, PlayerLoopTiming.Initialization },
{ UnityFrameProvider.EarlyUpdate, PlayerLoopTiming.EarlyUpdate },
{ UnityFrameProvider.FixedUpdate, PlayerLoopTiming.FixedUpdate },
{ UnityFrameProvider.PreUpdate, PlayerLoopTiming.PreUpdate },
{ UnityFrameProvider.Update, PlayerLoopTiming.Update },
{ UnityFrameProvider.PreLateUpdate, PlayerLoopTiming.PreLateUpdate },
{ UnityFrameProvider.PostLateUpdate, PlayerLoopTiming.PostLateUpdate },
{ UnityFrameProvider.TimeUpdate, PlayerLoopTiming.TimeUpdate },
{ UnityFrameProvider.PostFixedUpdate, PlayerLoopTiming.PostFixedUpdate },
};
public static bool TryGetFrameProvider(this TimeProvider provider, out FrameProvider frameProvider)
{
if (timeProviderInfo.TryGetValue(provider, out var info))
{
frameProvider = info.FrameProvider;
return true;
}
else
{
frameProvider = null;
return false;
}
}
public static FrameProvider GetFrameProvider(this TimeProvider provider)
{
return TryGetFrameProvider(provider, out var frameProvider) ? frameProvider : null;
}
public static bool TryGetDeltaTime(this TimeProvider provider, out float deltaTime)
{
if (
timeProviderInfo.TryGetValue(provider, out var info)
&& info.FrameProvider.TryGetFrameTiming(out var timing)
&& (info.TimeKind != TimeKind.Realtime)
)
{
deltaTime = (timing, info.TimeKind) switch
{
(PlayerLoopTiming.FixedUpdate, TimeKind.Time) => Time.fixedDeltaTime,
(PlayerLoopTiming.FixedUpdate, TimeKind.UnscaledTime) => Time.fixedUnscaledDeltaTime,
(_, TimeKind.Time) => Time.deltaTime,
(_, TimeKind.UnscaledTime) => Time.unscaledDeltaTime,
(_, _) => default
};
return true;
}
else
{
deltaTime = default;
return false;
}
}
public static float GetDeltaTime(this TimeProvider provider, float defaultValue = default)
{
return TryGetDeltaTime(provider, out var deltaTime) ? deltaTime : defaultValue;
}
public static bool TryGetFrameTiming(this FrameProvider provider, out PlayerLoopTiming timing)
{
return frameProviderTiming.TryGetValue(provider, out timing);
}
public static PlayerLoopTiming? GetFrameTiming(this UnityFrameProvider provider)
{
return provider.TryGetFrameTiming(out var timing) ? timing : null;
}
public static TimeProvider GetTimeProvider(PlayerLoopTiming timing, TimeKind kind)
{
return (timing, kind) switch
{
(PlayerLoopTiming.Initialization, TimeKind.Time) => UnityTimeProvider.Initialization,
(PlayerLoopTiming.Initialization, TimeKind.UnscaledTime) => UnityTimeProvider.InitializationIgnoreTimeScale,
(PlayerLoopTiming.Initialization, TimeKind.Realtime) => UnityTimeProvider.InitializationRealtime,
(PlayerLoopTiming.EarlyUpdate, TimeKind.Time) => UnityTimeProvider.EarlyUpdate,
(PlayerLoopTiming.EarlyUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.EarlyUpdate,
(PlayerLoopTiming.EarlyUpdate, TimeKind.Realtime) => UnityTimeProvider.EarlyUpdate,
(PlayerLoopTiming.FixedUpdate, TimeKind.Time) => UnityTimeProvider.FixedUpdate,
(PlayerLoopTiming.FixedUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.FixedUpdate,
(PlayerLoopTiming.FixedUpdate, TimeKind.Realtime) => UnityTimeProvider.FixedUpdate,
(PlayerLoopTiming.PreUpdate, TimeKind.Time) => UnityTimeProvider.PreUpdate,
(PlayerLoopTiming.PreUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.PreUpdate,
(PlayerLoopTiming.PreUpdate, TimeKind.Realtime) => UnityTimeProvider.PreUpdate,
(PlayerLoopTiming.Update, TimeKind.Time) => UnityTimeProvider.Update,
(PlayerLoopTiming.Update, TimeKind.UnscaledTime) => UnityTimeProvider.Update,
(PlayerLoopTiming.Update, TimeKind.Realtime) => UnityTimeProvider.Update,
(PlayerLoopTiming.PreLateUpdate, TimeKind.Time) => UnityTimeProvider.PreLateUpdate,
(PlayerLoopTiming.PreLateUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.PreLateUpdate,
(PlayerLoopTiming.PreLateUpdate, TimeKind.Realtime) => UnityTimeProvider.PreLateUpdate,
(PlayerLoopTiming.PostLateUpdate, TimeKind.Time) => UnityTimeProvider.PostLateUpdate,
(PlayerLoopTiming.PostLateUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.PostLateUpdate,
(PlayerLoopTiming.PostLateUpdate, TimeKind.Realtime) => UnityTimeProvider.PostLateUpdate,
(PlayerLoopTiming.TimeUpdate, TimeKind.Time) => UnityTimeProvider.TimeUpdate,
(PlayerLoopTiming.TimeUpdate, TimeKind.UnscaledTime) => UnityTimeProvider.TimeUpdate,
(PlayerLoopTiming.TimeUpdate, TimeKind.Realtime) => UnityTimeProvider.TimeUpdate,
(var t, var k) => throw new ArgumentException("({t}, {k}) are not valid values.")
};
}
}
}