using UnityEngine;
using UnityEngine.LowLevel;
using System;
using System.Collections.Concurrent;
using System.Threading;
 
namespace JDWTaskSystem
{
    /// <summary>
    /// Unity PlayerLoop 통합 스케줄러 (Lock-Free 링버버전)
    /// </summary>
    public static class JDWPlayerLoopScheduler
    {
        private struct Node
        {
            public ITaskCompletionAction Action;
            public ITaskSource Source;
        }
 
        // 비차단 링버퍼 설정
        private const int InitialBufferSize = 256;
        private const int MaxProcessPerFrame = 1000;
        private static Node[] buffer = new Node[InitialBufferSize];
        private static volatile int head = 0;
        private static volatile int tail = 0;
 
        [RuntimeInitializeOnLoadMethod]
        private static void Integrate()
        {
            // 새로운 PlayerLoop 시스템 정의
            PlayerLoopSystem loop = PlayerLoop.GetDefaultPlayerLoop();
            PlayerLoopSystem system = new PlayerLoopSystem
            {
                type = typeof(JDWPlayerLoopScheduler),
                updateDelegate = Process
            };
            // Update 시스템 뒤에 커스텀 스케줄러 시스템 삽입
            InsertSystem(ref loop, typeof(UnityEngine.PlayerLoop.Update), system);
            PlayerLoop.SetPlayerLoop(loop);
        }
 
        private static void InsertSystem(ref PlayerLoopSystem root, Type anchor, PlayerLoopSystem custom)
        {
            for (int i = 0; i < root.subSystemList.Length; i++)
            {
                ref PlayerLoopSystem subsystem = ref root.subSystemList[i];
                if (subsystem.type == anchor)
                {
                    // 기존 Update 시스템의 뒤에 새로운 시스템을 삽입하도록 리스트 복사 및 변경
                    PlayerLoopSystem[] newList = new PlayerLoopSystem[subsystem.subSystemList.Length + 1];
                    Array.Copy(subsystem.subSystemList, newList, subsystem.subSystemList.Length);
                    newList[newList.Length - 1= custom;
                    subsystem.subSystemList = newList;
                    break;
                }
            }
        }
        /// <summary>
        /// 스케줄러에 작업 등록
        /// </summary>
        /// <param name="action">스케줄링할 작업</param>
        /// <param name="source">작업 완료 소스</param>
        public static void Schedule(ITaskCompletionAction action, ITaskSource source)
        {
            int currentTail = Interlocked.Increment(ref tail) - 1;
            int index = currentTail % buffer.Length;
 
            // 버퍼 확장 필요 시
            if (currentTail >= buffer.Length)
            {
                ResizeBuffer(currentTail + 1);
            }
 
            buffer[index] = new Node { Action = action, Source = source };
        }
 
        private static void ResizeBuffer(int requiredCapacity)
        {
            lock (buffer)
            {
                if (requiredCapacity <= buffer.Length) return;
 
                int newSize = buffer.Length * 2;
                while (newSize <= requiredCapacity)
                {
                    newSize *= 2;
                }
 
                var newBuffer = new Node[newSize];
                Array.Copy(buffer, newBuffer, buffer.Length);
                buffer = newBuffer;
            }
        }
 
        private static void Process()
        {
            int processed = 0;
            int currentHead = head;
            int currentTail = tail;
 
            while (processed++ < MaxProcessPerFrame && currentHead < currentTail)
            {
                int index = currentHead % buffer.Length;
                Node node = buffer[index];
 
                try
                {
                    node.Action.Invoke(node.Source);
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
 
                Interlocked.Exchange(ref head, ++currentHead);
            }
        }
    }
}
cs

유니티 Update 루프 끝난직후에 스케쥴러가 실행되게

UnityEngine.PlayerLoop.Update 시스템 다음에 스케쥴러 삽입시킴.

Integrate는 게임 플레이 or 에디터 시작 자동호출하고, 

InsertSystem()으로 삽입함.

Typeanchor는 삽입위치인데, 여기서 기준점은 Update뒤로 구현