feat(gameplay): 更新单位属性和材质配置 - 调整多个单位的基础生命值和攻击力数值平衡 - 修改CoreBattleGround材质的纹理缩放比例 - 更新地砖材质颜色为白色 - 优化纹理资源设置,调整最大纹理尺寸并添加PlayableAds平台支持 - 修复弓箭手技能目标查找逻辑,改用统一的敌人检测方法 - 为水晶矿添加中立阵营设置和光球视觉效果同步 - 调整预制体中的全局缩放参数 - 为狼人和石巨人添加NavMeshAgent组件支持 - 优化水晶矿血条显示位置计算方式 ```
101 lines
3.5 KiB
C#
101 lines
3.5 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using UnityEditor;
|
|
|
|
namespace UnityTcp.Editor.Helpers
|
|
{
|
|
/// <summary>
|
|
/// Helper class for main thread operations
|
|
/// </summary>
|
|
public static class MainThreadHelper
|
|
{
|
|
private static int mainThreadId;
|
|
|
|
/// <summary>
|
|
/// Initialize the main thread ID for safe thread checks
|
|
/// Call this from the main thread during static constructor
|
|
/// </summary>
|
|
public static void InitializeMainThreadId()
|
|
{
|
|
try { mainThreadId = Thread.CurrentThread.ManagedThreadId; } catch { mainThreadId = 0; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// True when called from the Unity main thread. False when the main thread id was never
|
|
/// initialized — callers that need a "safe on main thread" fast path should treat that
|
|
/// as "not the main thread".
|
|
/// </summary>
|
|
public static bool IsMainThread
|
|
{
|
|
get
|
|
{
|
|
try { return mainThreadId != 0 && Thread.CurrentThread.ManagedThreadId == mainThreadId; }
|
|
catch { return false; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invoke the given function on the Unity main thread and wait up to timeoutMs for the result.
|
|
/// Returns null on timeout or error; caller should provide a fallback error response.
|
|
/// </summary>
|
|
public static object InvokeOnMainThreadWithTimeout(Func<object> func, int timeoutMs)
|
|
{
|
|
if (func == null) return null;
|
|
try
|
|
{
|
|
// If mainThreadId is unknown, assume we're on main thread to avoid blocking the editor.
|
|
if (mainThreadId == 0)
|
|
{
|
|
try { return func(); }
|
|
catch (Exception ex) { throw new InvalidOperationException($"Main thread handler error: {ex.Message}", ex); }
|
|
}
|
|
// If we are already on the main thread, execute directly to avoid deadlocks
|
|
try
|
|
{
|
|
if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
|
|
{
|
|
return func();
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
object result = null;
|
|
Exception captured = null;
|
|
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
EditorApplication.delayCall += () =>
|
|
{
|
|
try
|
|
{
|
|
result = func();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
captured = ex;
|
|
}
|
|
finally
|
|
{
|
|
try { tcs.TrySetResult(true); } catch { }
|
|
}
|
|
};
|
|
|
|
// Wait for completion with timeout (Editor thread will pump delayCall)
|
|
bool completed = tcs.Task.Wait(timeoutMs);
|
|
if (!completed)
|
|
{
|
|
return null; // timeout
|
|
}
|
|
if (captured != null)
|
|
{
|
|
throw new InvalidOperationException($"Main thread handler error: {captured.Message}", captured);
|
|
}
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new InvalidOperationException($"Failed to invoke on main thread: {ex.Message}", ex);
|
|
}
|
|
}
|
|
}
|
|
}
|