protected void FixedUpdate() { BeginFrame(); float deltaTime = Time.fixedDeltaTime; for (int iBehaviour = 0; iBehaviour < m_BehavioursForTraverse.Count; iBehaviour++) { BaseBehaviour iterBehaviour = m_BehavioursForTraverse[iBehaviour]; if (!iterBehaviour.CanUpdate()) { continue; } try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnFixedUpdate"); iterBehaviour.OnFixedUpdate(deltaTime); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnFixedUpdate"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnFixedUpdate Exception:{e.ToString()}"); } } }
private void SafeInvoke(int eventId, bool isImmediately, IUserData userData) { EventFunction listener = m_Listeners[eventId]; if (listener == null) { MDebug.LogVerbose("EventCenter", $"Event ({m_EventIdToName[eventId]}) not have listener."); if (userData is IObjectPoolItem poolItem) { Kernel.ObjectPool.Release(poolItem); } return; } try { MDebug.LogVerbose("EventCenter" , $"Event ({m_EventIdToName[eventId]}) begin invoke."); listener.Invoke(eventId, isImmediately, userData); if (userData is IObjectPoolItem poolItem) { Kernel.ObjectPool.Release(poolItem); } MDebug.LogVerbose("EventCenter" , $"Event ({m_EventIdToName[eventId]}) end invoke."); } catch (Exception e) { MDebug.LogError("EventCenter" , $"Event ({m_EventIdToName[eventId]}) invoke Exception:\n{e.ToString()}"); } }
private void EndFrame() { TaskUpdate(Time.deltaTime); #region Handle Disable for (int iBehaviour = 0; iBehaviour < m_BehavioursForTraverse.Count; iBehaviour++) { BaseBehaviour behaviour = m_BehavioursForTraverse[iBehaviour]; DisableBehaviour(behaviour); } #endregion #region Handle Release for (int iBehaviour = 0; iBehaviour < m_RemoveBehavioursCache.Count; iBehaviour++) { BaseBehaviour behaviour = m_RemoveBehavioursCache[iBehaviour]; ReleaseBehaviour(behaviour); } m_RemoveBehavioursCache.Clear(); #endregion m_BehavioursForTraverse.Clear(); MDebug.LogVerbose("Core", "EndFrame " + Time.frameCount); }
public AssetAction RemoveReference() { MDebug.LogVerbose(LOG_TAG, $"Asset Remove Reference:{m_AssetKey}, Reference Count: {m_ReferenceCount}"); MDebug.Assert(m_ReferenceCount > 0, LOG_TAG, "m_ReferenceCount = 0 cant remove"); if (m_ReferenceCount == 0) { return(AssetAction.Null); } m_ReferenceCount--; switch (m_AssetState) { case AssetState.WaitLoad: case AssetState.Loading: MDebug.Assert(false, LOG_TAG, "Asset Not Load But Remove Reference"); return(AssetAction.Null); case AssetState.Loaded: if (m_ReferenceCount == 0) { m_AssetState = AssetState.NeedUnload; return(AssetAction.Unload); } else { return(AssetAction.Null); } default: MDebug.Assert(false, LOG_TAG, "Asset Not Support AssetState"); return(AssetAction.Null); } }
private void DisableBehaviour(BaseBehaviour behaviour) { if (!behaviour.IsEnable() && behaviour.IsLastEnable()) { try { MDebug.LogVerbose("Core" , $"Before execute {behaviour.GetName()}.OnDisable"); behaviour.OnDisable(); MDebug.LogVerbose("Core" , $"After execute {behaviour.GetName()}.OnDisable"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {behaviour.GetName()}.OnDisable Exception:{e.ToString()}"); } finally { behaviour.SetLastEnable(false); } } }
public BundleAction RemoveReference() { MDebug.LogVerbose(LOG_TAG, $"Bundle Remove Reference:{ms_AssetManager.m_BundleInfos[m_BundleIndex].BundleName}, Reference Count: {m_ReferenceCount}"); MDebug.Assert(m_ReferenceCount > 0, LOG_TAG, "m_ReferenceCount = 0, Cant Remove!"); m_ReferenceCount--; switch (m_BundleState) { case BundleState.NotLoad: case BundleState.NeedLoad: MDebug.Assert(false, LOG_TAG, "BundleState.NotLoad"); return(BundleAction.Null); case BundleState.Loaded: if (m_ReferenceCount == 0) { m_BundleState = BundleState.NeedUnload; return(BundleAction.Unload); } else { return(BundleAction.Null); } case BundleState.Loading: MDebug.Assert(m_ReferenceCount > 0, LOG_TAG, "m_ReferenceCount > 0"); return(BundleAction.Null); default: MDebug.Assert(false, LOG_TAG, "Not support BundleState: " + m_BundleState); return(BundleAction.Null); } }
public AssetAction AddReference(Action <AssetKey, UnityEngine.Object> callback) { m_OnAssetLoaded += callback; m_ReferenceCount++; MDebug.LogVerbose(LOG_TAG, $"Asset Add Reference:{m_AssetKey}, Reference Count: {m_ReferenceCount}"); switch (m_AssetState) { case AssetState.Loaded: MDebug.Assert(m_Asset != null, LOG_TAG, "m_Asset != null"); return(AssetAction.LoadedCallback); case AssetState.NotLoad: m_AssetState = AssetState.WaitLoad; return(AssetAction.RequestLoadBundle); case AssetState.WaitLoad: case AssetState.Loading: return(AssetAction.Null); case AssetState.NeedUnload: MDebug.Assert(m_Asset != null, LOG_TAG, "m_Asset != null"); m_AssetState = AssetState.Loaded; return(AssetAction.LoadedCallback); default: MDebug.Assert(false, LOG_TAG, "Asset Not Support AssetState"); return(AssetAction.Null); } }
public BundleAction AddReference() { m_ReferenceCount++; MDebug.LogVerbose(LOG_TAG, $"Bundle Add Reference:{ms_AssetManager.m_BundleInfos[m_BundleIndex].BundleName}, Reference Count: {m_ReferenceCount}"); switch (m_BundleState) { case BundleState.NotLoad: m_BundleState = BundleState.NeedLoad; return(BundleAction.Load); case BundleState.Loaded: case BundleState.Loading: case BundleState.NeedLoad: return(BundleAction.Null); case BundleState.NeedUnload: m_BundleState = BundleState.Loaded; return(BundleAction.Null); default: MDebug.Assert(false, LOG_TAG, "Not support BundleState: " + m_BundleState); return(BundleAction.Null); } }
/// <summary> /// 包含Bundle是否需要加载判断,添加资源引用计数,并在尚未加载Bundle时,设置加载完成时回调 /// </summary> /// <param name="bundleIndex"></param> /// <param name="assetIndex"></param> private void LoadBundleForLoadAsset(int bundleIndex, int assetIndex) { BundleHandler bundleHandler = m_BundleHandlers[bundleIndex]; if (bundleHandler == null) { bundleHandler = m_BundleHandlerPool.Alloc(); bundleHandler.SetBundleIndex(bundleIndex); m_BundleHandlers[bundleIndex] = bundleHandler; } BundleAction bundleAction = bundleHandler.AddReference(); if (bundleAction == BundleAction.Load) { m_BundleActionRequests.Enqueue(new BundleActionRequest(bundleIndex, bundleAction)); MDebug.LogVerbose(LOG_TAG, $"Add load bundle action. Bundle:({m_BundleInfos[bundleIndex].BundleName}) Asset:({(AssetKey)assetIndex})"); } else if (bundleAction == BundleAction.Null) { // Dont need handle } else { MDebug.Assert(false, "AsestBundle", "Not support BundleAction: " + bundleAction); } bundleHandler.TryAddDependencyAsset(m_AssetHandlers[assetIndex]); }
/// <summary> /// 等待所有的<see cref="TaskUpdate"/>完成 /// </summary> private void WaitTaskUpdate() { for (int iTask = 0; iTask < m_TaskItemsCache.Count; iTask++) { TaskUpdateItem taskItem = m_TaskItemsCache[iTask]; taskItem.ManualResetEvent.WaitOne(); BaseBehaviour iterBehaviour = taskItem.Behaviour; try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnAfterTaskUpdate"); iterBehaviour.OnAfterTaskUpdate(taskItem.Output); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnAfterTaskUpdate"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnAfterTaskUpdate Exception:{e.ToString()}"); } m_TaskItemPool.Release(taskItem); } m_TaskItemsCache.Clear(); }
private int PointToGridIndex(Vector2 point) { int indexX = (int)(point.x / m_CellSize); int indexY = (int)(point.y / m_CellSize); MDebug.LogVerbose("Sampling", $"PointToGridIndex({point}) indexX({indexX}) indexY({indexY})"); return(indexX + indexY * m_YCellCount); }
protected void Update() { // 这里也要调用一次的原因是,当前帧可能没执行FixedUpdate BeginFrame(); float deltaTime = Time.deltaTime; int frameCount = Time.frameCount; ParallelUpdate(deltaTime); for (int iBehaviour = 0; iBehaviour < m_BehavioursForTraverse.Count; iBehaviour++) { BaseBehaviour iterBehaviour = m_BehavioursForTraverse[iBehaviour]; if (!iterBehaviour.CanUpdate()) { continue; } float behaviourDeltaTime; if (iterBehaviour.HasFeature(FeatureFlag.UpdateFrequency)) { try { if (!iterBehaviour.ControlUpdateFrequency(out behaviourDeltaTime, deltaTime, frameCount)) { continue; } } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.ControlUpdateFrequency Exception:{e.ToString()}"); continue; } } else { behaviourDeltaTime = deltaTime; } try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnUpdate"); iterBehaviour.OnUpdate(behaviourDeltaTime); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnUpdate"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnUpdate Exception:{e.ToString()}"); } } }
private static int Verbose(IntPtr luaState) { int success = GetLog(luaState, out string tag, out string message); if (success == 1) { MDebug.LogVerbose(tag, message); } return(success); }
private void ReleaseBehaviour(BaseBehaviour behaviour) { try { MDebug.LogVerbose("Core" , $"Before execute {behaviour.GetName()}.OnRelease"); behaviour.OnRelease(); MDebug.LogVerbose("Core" , $"After execute {behaviour.GetName()}.OnRelease"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {behaviour.GetName()}.OnRelease Exception:{e.ToString()}"); } }
private void ProcessReceive(object sender, SocketAsyncEventArgs e) { if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { MDebug.LogVerbose(LOG_TAG , $"Client({GetName()}) 接收长度: {e.BytesTransferred}"); OnReceived(m_ReceiveBuffer.GetBuffer() , m_ReceiveBuffer.GetOffset() , e.BytesTransferred); StartReceive(); } else { MDebug.LogError(LOG_TAG , $"Client({GetName()}) 接受消息失败: {e.SocketError.ToString()}, 即将断开连接。{e.BytesTransferred}|{e.SocketError}"); Disconnect(e); } }
/// <summary> /// 对<see cref="OnTaskUpdate_Thread"/>的一层封装 /// 错误处理 /// 处理<see cref="System.Threading.ManualResetEvent"/> /// </summary> internal void DoTaskUpdate_Thread(object state) { TaskUpdateItem taskItem = state as TaskUpdateItem; try { MDebug.LogVerbose("Core" , $"Before execute {GetName()}.OnTaskUpdate_Thread"); taskItem.Output = OnTaskUpdate_Thread(taskItem.Input, taskItem.DeltaTime); MDebug.LogVerbose("Core" , $"After execute {GetName()}.OnTaskUpdate_Thread"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {GetName()}.OnTaskUpdate_Thread Exception:{e.ToString()}"); } taskItem.ManualResetEvent.Set(); }
public override object OnTaskUpdate_Thread(object input, float deltaTime) { unsafe { int bufferLength = CallLuaAPI.lua_gfloginternal_getbufferlength(); byte *logBuffer = (byte *)CallLuaAPI.lua_gfloginternal_getbuffer().ToPointer(); CallLuaAPI.lua_gfloginternal_swapbuffer(); while (bufferLength > 0) { logBuffer = ConvertToIntFromLogBuffer(logBuffer, ref bufferLength, out int type); logBuffer = ConvertToStringFromLogBuffer(logBuffer, ref bufferLength, out string tag); logBuffer = ConvertToStringFromLogBuffer(logBuffer, ref bufferLength, out string message); switch (type) { case LOGTYPE_VERBOSE: MDebug.LogVerbose(tag, message); break; case (int)LogType.Log: MDebug.Log(tag, message); break; case (int)LogType.Warning: MDebug.LogWarning(tag, message); break; case (int)LogType.Error: MDebug.LogError(tag, message); break; default: throw new Exception("Not handle LogType: " + type); } } } return(null); }
/// <summary> /// 减少指定Bundle包中的资源引用计数 /// </summary> /// <param name="bundleIndex"></param> private void RemoveAssetDependency(int bundleIndex, int assetIndex) { BundleHandler bundleHandler = m_BundleHandlers[bundleIndex]; if (bundleHandler != null) { BundleAction bundleAction = bundleHandler.RemoveReference(); if (bundleAction == BundleAction.Unload) { m_BundleActionRequests.Enqueue(new BundleActionRequest(bundleIndex, bundleAction)); MDebug.LogVerbose(LOG_TAG, $"Add remove bundle action. Bundle:({m_BundleInfos[bundleIndex].BundleName}) Asset:({(AssetKey)assetIndex})"); } else if (bundleAction == BundleAction.Null) { // Dont need handle } else { MDebug.Assert(false, "AsestBundle", "Not support BundleAction: " + bundleAction); } } }
private void TaskUpdate(float deltaTime) { MDebug.Assert(m_TaskItemsCache.Count == 0, "Core", "m_TaskItemsCache.Count == 0"); for (int iBehaviour = 0; iBehaviour < m_BehavioursForTraverse.Count; iBehaviour++) { BaseBehaviour iterBehaviour = m_BehavioursForTraverse[iBehaviour]; if (!iterBehaviour.CanUpdate() || !iterBehaviour.HasFeature(FeatureFlag.TaskUpdate)) { continue; } TaskUpdateItem iterTaskItem = m_TaskItemPool.Alloc() .SetData(iterBehaviour, deltaTime); m_TaskItemsCache.Add(iterTaskItem); try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnBeforeTastUpdate"); iterTaskItem.Input = iterBehaviour.OnBeforeTastUpdate(); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnBeforeTastUpdate"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnBeforeTastUpdate Exception:{e.ToString()}"); } System.Threading.ThreadPool.QueueUserWorkItem(iterBehaviour.DoTaskUpdate_Thread, iterTaskItem); } }
public Node AllocBuffer(int size) { MDebug.Assert(size > 0 , "ArrayPool" , "size > 0"); Node iterNode = m_Root; #if GF_DEBUG int remainTime = 10000; #endif while (true) { #if GF_DEBUG if (remainTime-- == 0) { throw new Exception("代码逻辑可能写错了"); } #endif // 可以在当前Node分配 if (!iterNode.IsUsed() && iterNode.GetSize() >= size) { int remainSize = iterNode.GetSize() - size; Node afterNode = iterNode._After; // 处理分配后的剩余空间 if (remainSize != 0) { // 不能和下一个Node合并,把剩余空间当成一个新的Node if (afterNode == null || afterNode.IsUsed()) { afterNode = ms_NodePool.Alloc().SetData(this , iterNode.GetOffset() + size , remainSize , false , iterNode , afterNode); iterNode._After = afterNode; if (afterNode._After != null) { afterNode._After._Before = afterNode; } } // 剩余空间合并到下一个Node else { #if GF_DEBUG MDebug.Assert(afterNode.GetOffset() - iterNode.GetSize() == iterNode.GetOffset() , "ArrayPool" , "afterNode.GetOffset() - iterNode.GetSize() == iterNode.GetOffset()"); #endif afterNode.SetData(this , iterNode.GetOffset() + size , afterNode.GetSize() + remainSize , false , afterNode._Before , afterNode._After); } } iterNode.SetData(this , iterNode.GetOffset() , size , true , iterNode._Before , iterNode._After); break; } // 寻找下一个Node if (iterNode._After != null) { iterNode = iterNode._After; } // iterNode是LastNode,尝试扩容 else { // 扩容后空间肯定能分配一个size的Buffer EnsureCapacity(m_Buffer.Length + size); // 最后一个Node已经被使用了,分配一个新Node if (iterNode.IsUsed()) { iterNode = ms_NodePool.Alloc().SetData(this , iterNode.GetOffset() + iterNode.GetSize() , size , true , iterNode , null); iterNode._Before._After = iterNode; } // 把最后一个Node扩容成size大小 else { iterNode.SetData(this , iterNode.GetOffset() , size , true , iterNode._Before , null); } int lastOffset = iterNode.GetOffset() + iterNode.GetSize(); if (lastOffset < m_Buffer.Length) { // 把扩容后的剩余空间当成一个新Node Node lastNode = ms_NodePool.Alloc().SetData(this , lastOffset , m_Buffer.Length - lastOffset , false , iterNode , null); iterNode._After = lastNode; } break; } } MDebug.LogVerbose("ArrayPool" , $"Alloc buffer offset:{iterNode.GetOffset()} size:{iterNode.GetSize()}"); return(iterNode); }
protected override void OnProcessShaderInternal(Shader shader , ShaderSnippetData snippet , IList <ShaderCompilerData> data) { #region Builtin bool isBuiltinShader = AssetUtility.IsBuiltinOrLibraryAsset(shader); if (isBuiltinShader) { m_BuiltinShaders[shader.name] = data.Count + (m_BuiltinShaders.TryGetValue(shader.name, out int count) ? count : 0); } #endregion #region ProcessInfo ProcessInfo processInfo = new ProcessInfo(); processInfo.IsBuiltinShader = isBuiltinShader; processInfo.ShaderName = shader.name; processInfo.ShaderType = snippet.shaderType; processInfo.PassType = snippet.passType; processInfo.PassName = snippet.passName; processInfo.Compilers = new CompilerInfo[data.Count]; Parallel.For(0, data.Count, (iShader) => { processInfo.Compilers[iShader] = GenerateCompilerInfo(data[iShader]); }); processInfo.Keywords = CollectionKeywords(processInfo.Compilers); #endregion #region Summary { string shaderName = (processInfo.IsBuiltinShader ? "B_" : "") + processInfo.ShaderName; if (!m_ShaderInfos.TryGetValue(shaderName, out ShaderInfo shaderInfo)) { shaderInfo = new ShaderInfo(); m_ShaderInfos.Add(shaderName, shaderInfo); } shaderInfo.ShaderTypes.Add(processInfo.ShaderType); shaderInfo.PassTypes.Add(processInfo.PassType); shaderInfo.VariantCount += processInfo.Compilers.Length; for (int iKeyword = 0; iKeyword < processInfo.Keywords.Length; iKeyword++) { shaderInfo.Keywords.Add(processInfo.Keywords[iKeyword]); } } #endregion int index = ++m_HandledShader; Task.Run(() => { try { string directory = $"{m_ReportDirectory}/{(processInfo.IsBuiltinShader ? "B_" : "")}{StringUtility.FormatToFileName(processInfo.ShaderName)}/"; if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } string processName = $"_({processInfo.ShaderType})_({processInfo.PassType})_({processInfo.PassName})_Count("; string path = $"{directory}{index}_{processName}{processInfo.Compilers.Length}).csv"; File.WriteAllText(path , GenerateCompilersReport(processInfo.Compilers, processInfo.Keywords)); MDebug.LogVerbose("Shader", "Save PreprocessShaderReport to path " + path); } catch (Exception e) { MDebug.LogError("Shader" , "Save PreprocessShaderReport Exception:\n" + e.ToString()); } }); }
private void BeginFrame() { if (Time.frameCount <= m_LastBeginFrame) { return; } m_LastBeginFrame = Time.frameCount; MDebug.LogVerbose("Core", "BeginFrame " + m_LastBeginFrame); WaitTaskUpdate(); CollectionBehavioursForTraverse(); #region Handle Initialize for (int iBehaviour = 0; iBehaviour < m_AddBehavioursCache.Count; iBehaviour++) { BaseBehaviour behaviour = m_AddBehavioursCache[iBehaviour]; try { MDebug.LogVerbose("Core" , $"Before execute {behaviour.GetName()}.OnInitialize"); behaviour.OnInitialize(); MDebug.LogVerbose("Core" , $"After execute {behaviour.GetName()}.OnInitialize"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {behaviour.GetName()}.OnInitialize Exception:{e.ToString()}"); } behaviour.SetAlive(true); } m_AddBehavioursCache.Clear(); #endregion #region Handle Enable for (int iBehaviour = 0; iBehaviour < m_BehavioursForTraverse.Count; iBehaviour++) { BaseBehaviour behaviour = m_BehavioursForTraverse[iBehaviour]; if (behaviour.IsEnable() && !behaviour.IsLastEnable()) { try { MDebug.LogVerbose("Core" , $"Before execute {behaviour.GetName()}.OnEnable"); behaviour.OnEnable(); MDebug.LogVerbose("Core" , $"After execute {behaviour.GetName()}.OnEnable"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {behaviour.GetName()}.OnEnable Exception:{e.ToString()}"); } finally { behaviour.SetLastEnable(true); } } } #endregion }
private void ExecuteParallelUpdateGroup() { if (m_ParallelItemsCache.Count == 0) { return; } for (int iBehaviour = 0; iBehaviour < m_ParallelItemsCache.Count; iBehaviour++) { ParallelUpdateItem iterTask = m_ParallelItemsCache[iBehaviour]; BaseBehaviour iterBehaviour = iterTask.Behaviour; try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnBeforeParallelUpdate"); iterTask.Input = iterBehaviour.OnBeforeParallelUpdate(iterTask.DeltaTime); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnBeforeParallelUpdate"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnBeforeParallelUpdate Exception:{e.ToString()}"); } } System.Threading.Tasks.Parallel.For(0, m_ParallelItemsCache.Count, (iBehaviour) => { ParallelUpdateItem iterTask = m_ParallelItemsCache[iBehaviour]; BaseBehaviour iterBehaviour = iterTask.Behaviour; try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnParallelUpdate_Thread"); iterTask.Output = iterBehaviour.OnParallelUpdate_Thread(iterTask.Input, iterTask.DeltaTime); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnParallelUpdate_Thread"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnParallelUpdate_Thread Exception:{e.ToString()}"); } }); for (int iBehaviour = 0; iBehaviour < m_ParallelItemsCache.Count; iBehaviour++) { ParallelUpdateItem iterTask = m_ParallelItemsCache[iBehaviour]; BaseBehaviour iterBehaviour = iterTask.Behaviour; try { MDebug.LogVerbose("Core" , $"Before execute {iterBehaviour.GetName()}.OnAfterParallelUpdate"); iterBehaviour.OnAfterParallelUpdate(iterTask.Output, iterTask.DeltaTime); MDebug.LogVerbose("Core" , $"After execute {iterBehaviour.GetName()}.OnAfterParallelUpdate"); } catch (Exception e) { MDebug.LogError("Core" , $"Execute {iterBehaviour.GetName()}.OnAfterParallelUpdate Exception:{e.ToString()}"); } m_ParallelItemPool.Release(iterTask); } m_ParallelItemsCache.Clear(); }