213 lines
6.9 KiB
C#
213 lines
6.9 KiB
C#
using System;
|
|
using System.Threading;
|
|
#if UNITY_2019_3_OR_NEWER
|
|
using UnityEngine.LowLevel;
|
|
using UnityEngine.PlayerLoop;
|
|
#else
|
|
using UnityEngine.Experimental.LowLevel;
|
|
using UnityEngine.Experimental.PlayerLoop;
|
|
#endif
|
|
|
|
namespace VContainer.Unity
|
|
{
|
|
public struct VContainerInitialization {}
|
|
public struct VContainerPostInitialization {}
|
|
public struct VContainerStartup {}
|
|
public struct VContainerPostStartup {}
|
|
public struct VContainerFixedUpdate {}
|
|
public struct VContainerPostFixedUpdate {}
|
|
public struct VContainerUpdate {}
|
|
public struct VContainerPostUpdate {}
|
|
public struct VContainerLateUpdate {}
|
|
public struct VContainerPostLateUpdate {}
|
|
|
|
enum PlayerLoopTiming
|
|
{
|
|
Initialization = 0,
|
|
PostInitialization = 1,
|
|
|
|
Startup = 2,
|
|
PostStartup = 3,
|
|
|
|
FixedUpdate = 4,
|
|
PostFixedUpdate = 5,
|
|
|
|
Update = 6,
|
|
PostUpdate = 7,
|
|
|
|
LateUpdate = 8,
|
|
PostLateUpdate = 9,
|
|
}
|
|
|
|
static class PlayerLoopHelper
|
|
{
|
|
static readonly PlayerLoopRunner[] Runners = new PlayerLoopRunner[10];
|
|
static long initialized;
|
|
|
|
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
|
public static void EnsureInitialized()
|
|
{
|
|
if (Interlocked.CompareExchange(ref initialized, 1, 0) != 0)
|
|
return;
|
|
|
|
for (var i = 0; i < Runners.Length; i++)
|
|
{
|
|
Runners[i] = new PlayerLoopRunner();
|
|
}
|
|
|
|
var playerLoop =
|
|
#if UNITY_2019_3_OR_NEWER
|
|
PlayerLoop.GetCurrentPlayerLoop();
|
|
#else
|
|
PlayerLoop.GetDefaultPlayerLoop();
|
|
#endif
|
|
|
|
var copyList = playerLoop.subSystemList;
|
|
|
|
ref var initializeSystem = ref FindSubSystem(typeof(Initialization), copyList);
|
|
InsertSubsystem(
|
|
ref initializeSystem,
|
|
null,
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerInitialization),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.Initialization].Run
|
|
},
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerPostInitialization),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.PostInitialization].Run
|
|
});
|
|
|
|
|
|
ref var earlyUpdateSystem = ref FindSubSystem(typeof(EarlyUpdate), copyList);
|
|
InsertSubsystem(
|
|
ref earlyUpdateSystem,
|
|
typeof(EarlyUpdate.ScriptRunDelayedStartupFrame),
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerStartup),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.Startup].Run
|
|
},
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerPostStartup),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.PostStartup].Run
|
|
});
|
|
|
|
ref var fixedUpdateSystem = ref FindSubSystem(typeof(FixedUpdate), copyList);
|
|
InsertSubsystem(
|
|
ref fixedUpdateSystem,
|
|
typeof(FixedUpdate.ScriptRunBehaviourFixedUpdate),
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerFixedUpdate),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.FixedUpdate].Run
|
|
},
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerPostFixedUpdate),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.PostFixedUpdate].Run
|
|
});
|
|
|
|
ref var updateSystem = ref FindSubSystem(typeof(Update), copyList);
|
|
InsertSubsystem(
|
|
ref updateSystem,
|
|
typeof(Update.ScriptRunBehaviourUpdate),
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerUpdate),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.Update].Run
|
|
},
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerPostUpdate),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.PostUpdate].Run
|
|
});
|
|
|
|
ref var lateUpdateSystem = ref FindSubSystem(typeof(PreLateUpdate), copyList);
|
|
InsertSubsystem(
|
|
ref lateUpdateSystem,
|
|
typeof(PreLateUpdate.ScriptRunBehaviourLateUpdate),
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerLateUpdate),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.LateUpdate].Run
|
|
},
|
|
new PlayerLoopSystem
|
|
{
|
|
type = typeof(VContainerPostLateUpdate),
|
|
updateDelegate = Runners[(int)PlayerLoopTiming.PostLateUpdate].Run
|
|
});
|
|
|
|
playerLoop.subSystemList = copyList;
|
|
PlayerLoop.SetPlayerLoop(playerLoop);
|
|
}
|
|
|
|
public static void Dispatch(PlayerLoopTiming timing, IPlayerLoopItem item)
|
|
{
|
|
EnsureInitialized();
|
|
Runners[(int)timing].Dispatch(item);
|
|
}
|
|
|
|
static ref PlayerLoopSystem FindSubSystem(Type targetType, PlayerLoopSystem[] systems)
|
|
{
|
|
for (var i = 0; i < systems.Length; i++)
|
|
{
|
|
if (systems[i].type == targetType)
|
|
return ref systems[i];
|
|
}
|
|
throw new InvalidOperationException($"{targetType.FullName} not in systems");
|
|
}
|
|
|
|
static void InsertSubsystem(
|
|
ref PlayerLoopSystem parentSystem,
|
|
Type beforeType,
|
|
PlayerLoopSystem newSystem,
|
|
PlayerLoopSystem newPostSystem)
|
|
{
|
|
var source = parentSystem.subSystemList;
|
|
var insertIndex = -1;
|
|
if (beforeType == null)
|
|
{
|
|
insertIndex = 0;
|
|
}
|
|
for (var i = 0; i < source.Length; i++)
|
|
{
|
|
if (source[i].type == beforeType)
|
|
{
|
|
insertIndex = i;
|
|
}
|
|
}
|
|
|
|
if (insertIndex < 0)
|
|
{
|
|
throw new ArgumentException($"{beforeType.FullName} not in system {parentSystem} {parentSystem.type.FullName}");
|
|
}
|
|
|
|
var dest = new PlayerLoopSystem[source.Length + 2];
|
|
for (var i = 0; i < dest.Length; i++)
|
|
{
|
|
if (i == insertIndex)
|
|
{
|
|
dest[i] = newSystem;
|
|
}
|
|
else if (i == dest.Length - 1)
|
|
{
|
|
dest[i] = newPostSystem;
|
|
}
|
|
else if (i < insertIndex)
|
|
{
|
|
dest[i] = source[i];
|
|
}
|
|
else
|
|
{
|
|
dest[i] = source[i - 1];
|
|
}
|
|
}
|
|
|
|
parentSystem.subSystemList = dest;
|
|
}
|
|
}
|
|
}
|