You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
8.0 KiB
260 lines
8.0 KiB
|
|
using System; |
|
using UnityEngine; |
|
|
|
namespace Cysharp.Threading.Tasks.Internal |
|
{ |
|
internal sealed class PlayerLoopRunner |
|
{ |
|
const int InitialSize = 16; |
|
|
|
readonly PlayerLoopTiming timing; |
|
readonly object runningAndQueueLock = new object(); |
|
readonly object arrayLock = new object(); |
|
readonly Action<Exception> unhandledExceptionCallback; |
|
|
|
int tail = 0; |
|
bool running = false; |
|
IPlayerLoopItem[] loopItems = new IPlayerLoopItem[InitialSize]; |
|
MinimumQueue<IPlayerLoopItem> waitQueue = new MinimumQueue<IPlayerLoopItem>(InitialSize); |
|
|
|
|
|
|
|
public PlayerLoopRunner(PlayerLoopTiming timing) |
|
{ |
|
this.unhandledExceptionCallback = ex => Debug.LogException(ex); |
|
this.timing = timing; |
|
} |
|
|
|
public void AddAction(IPlayerLoopItem item) |
|
{ |
|
lock (runningAndQueueLock) |
|
{ |
|
if (running) |
|
{ |
|
waitQueue.Enqueue(item); |
|
return; |
|
} |
|
} |
|
|
|
lock (arrayLock) |
|
{ |
|
// Ensure Capacity |
|
if (loopItems.Length == tail) |
|
{ |
|
Array.Resize(ref loopItems, checked(tail * 2)); |
|
} |
|
loopItems[tail++] = item; |
|
} |
|
} |
|
|
|
public int Clear() |
|
{ |
|
lock (arrayLock) |
|
{ |
|
var rest = 0; |
|
|
|
for (var index = 0; index < loopItems.Length; index++) |
|
{ |
|
if (loopItems[index] != null) |
|
{ |
|
rest++; |
|
} |
|
|
|
loopItems[index] = null; |
|
} |
|
|
|
tail = 0; |
|
return rest; |
|
} |
|
} |
|
|
|
// delegate entrypoint. |
|
public void Run() |
|
{ |
|
// for debugging, create named stacktrace. |
|
#if DEBUG |
|
switch (timing) |
|
{ |
|
case PlayerLoopTiming.Initialization: |
|
Initialization(); |
|
break; |
|
case PlayerLoopTiming.LastInitialization: |
|
LastInitialization(); |
|
break; |
|
case PlayerLoopTiming.EarlyUpdate: |
|
EarlyUpdate(); |
|
break; |
|
case PlayerLoopTiming.LastEarlyUpdate: |
|
LastEarlyUpdate(); |
|
break; |
|
case PlayerLoopTiming.FixedUpdate: |
|
FixedUpdate(); |
|
break; |
|
case PlayerLoopTiming.LastFixedUpdate: |
|
LastFixedUpdate(); |
|
break; |
|
case PlayerLoopTiming.PreUpdate: |
|
PreUpdate(); |
|
break; |
|
case PlayerLoopTiming.LastPreUpdate: |
|
LastPreUpdate(); |
|
break; |
|
case PlayerLoopTiming.Update: |
|
Update(); |
|
break; |
|
case PlayerLoopTiming.LastUpdate: |
|
LastUpdate(); |
|
break; |
|
case PlayerLoopTiming.PreLateUpdate: |
|
PreLateUpdate(); |
|
break; |
|
case PlayerLoopTiming.LastPreLateUpdate: |
|
LastPreLateUpdate(); |
|
break; |
|
case PlayerLoopTiming.PostLateUpdate: |
|
PostLateUpdate(); |
|
break; |
|
case PlayerLoopTiming.LastPostLateUpdate: |
|
LastPostLateUpdate(); |
|
break; |
|
#if UNITY_2020_2_OR_NEWER |
|
case PlayerLoopTiming.TimeUpdate: |
|
TimeUpdate(); |
|
break; |
|
case PlayerLoopTiming.LastTimeUpdate: |
|
LastTimeUpdate(); |
|
break; |
|
#endif |
|
default: |
|
break; |
|
} |
|
#else |
|
RunCore(); |
|
#endif |
|
} |
|
|
|
void Initialization() => RunCore(); |
|
void LastInitialization() => RunCore(); |
|
void EarlyUpdate() => RunCore(); |
|
void LastEarlyUpdate() => RunCore(); |
|
void FixedUpdate() => RunCore(); |
|
void LastFixedUpdate() => RunCore(); |
|
void PreUpdate() => RunCore(); |
|
void LastPreUpdate() => RunCore(); |
|
void Update() => RunCore(); |
|
void LastUpdate() => RunCore(); |
|
void PreLateUpdate() => RunCore(); |
|
void LastPreLateUpdate() => RunCore(); |
|
void PostLateUpdate() => RunCore(); |
|
void LastPostLateUpdate() => RunCore(); |
|
#if UNITY_2020_2_OR_NEWER |
|
void TimeUpdate() => RunCore(); |
|
void LastTimeUpdate() => RunCore(); |
|
#endif |
|
|
|
[System.Diagnostics.DebuggerHidden] |
|
void RunCore() |
|
{ |
|
lock (runningAndQueueLock) |
|
{ |
|
running = true; |
|
} |
|
|
|
lock (arrayLock) |
|
{ |
|
var j = tail - 1; |
|
|
|
for (int i = 0; i < loopItems.Length; i++) |
|
{ |
|
var action = loopItems[i]; |
|
if (action != null) |
|
{ |
|
try |
|
{ |
|
if (!action.MoveNext()) |
|
{ |
|
loopItems[i] = null; |
|
} |
|
else |
|
{ |
|
continue; // next i |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
loopItems[i] = null; |
|
try |
|
{ |
|
unhandledExceptionCallback(ex); |
|
} |
|
catch { } |
|
} |
|
} |
|
|
|
// find null, loop from tail |
|
while (i < j) |
|
{ |
|
var fromTail = loopItems[j]; |
|
if (fromTail != null) |
|
{ |
|
try |
|
{ |
|
if (!fromTail.MoveNext()) |
|
{ |
|
loopItems[j] = null; |
|
j--; |
|
continue; // next j |
|
} |
|
else |
|
{ |
|
// swap |
|
loopItems[i] = fromTail; |
|
loopItems[j] = null; |
|
j--; |
|
goto NEXT_LOOP; // next i |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
loopItems[j] = null; |
|
j--; |
|
try |
|
{ |
|
unhandledExceptionCallback(ex); |
|
} |
|
catch { } |
|
continue; // next j |
|
} |
|
} |
|
else |
|
{ |
|
j--; |
|
} |
|
} |
|
|
|
tail = i; // loop end |
|
break; // LOOP END |
|
|
|
NEXT_LOOP: |
|
continue; |
|
} |
|
|
|
|
|
lock (runningAndQueueLock) |
|
{ |
|
running = false; |
|
while (waitQueue.Count != 0) |
|
{ |
|
if (loopItems.Length == tail) |
|
{ |
|
Array.Resize(ref loopItems, checked(tail * 2)); |
|
} |
|
loopItems[tail++] = waitQueue.Dequeue(); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|