feat(gameplay): 更新单位属性和材质配置 - 调整多个单位的基础生命值和攻击力数值平衡 - 修改CoreBattleGround材质的纹理缩放比例 - 更新地砖材质颜色为白色 - 优化纹理资源设置,调整最大纹理尺寸并添加PlayableAds平台支持 - 修复弓箭手技能目标查找逻辑,改用统一的敌人检测方法 - 为水晶矿添加中立阵营设置和光球视觉效果同步 - 调整预制体中的全局缩放参数 - 为狼人和石巨人添加NavMeshAgent组件支持 - 优化水晶矿血条显示位置计算方式 ```
120 lines
3.9 KiB
C#
120 lines
3.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Codely.Newtonsoft.Json.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityTcp.Editor.Helpers;
|
|
|
|
namespace UnityTcp.Editor.Notifier
|
|
{
|
|
/// <summary>
|
|
/// Broadcasts the current Editor selection to notifier clients whenever it
|
|
/// changes. The emitted payload mirrors the structure returned by
|
|
/// <see cref="UnityTcp.Editor.Tools.ManageEditor"/>'s get_selection action.
|
|
/// </summary>
|
|
[InitializeOnLoad]
|
|
public static class SelectionChangedNotifier
|
|
{
|
|
private const string EventType = "selection_changed";
|
|
|
|
private static bool _flushScheduled;
|
|
|
|
static SelectionChangedNotifier()
|
|
{
|
|
Selection.selectionChanged += OnSelectionChanged;
|
|
}
|
|
|
|
private static void OnSelectionChanged() => ScheduleFlush();
|
|
|
|
private static void ScheduleFlush()
|
|
{
|
|
if (_flushScheduled) return;
|
|
_flushScheduled = true;
|
|
EditorApplication.delayCall += Flush;
|
|
}
|
|
|
|
private static void Flush()
|
|
{
|
|
_flushScheduled = false;
|
|
try
|
|
{
|
|
if (!UnityTcpBridge.IsRunning) return;
|
|
|
|
JObject payload = BuildSelectionPayload();
|
|
if (payload == null) return;
|
|
|
|
UnityTcpBridge.NotifyAll(EventType, payload);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
try { CodelyLogger.LogError($"[SelectionChangedNotifier] flush failed: {e.Message}"); } catch { }
|
|
}
|
|
}
|
|
|
|
private static JObject BuildSelectionPayload()
|
|
{
|
|
var assetGUIDs = Selection.assetGUIDs;
|
|
var assetPaths = assetGUIDs?.Select(AssetDatabase.GUIDToAssetPath).ToArray();
|
|
|
|
string activeAssetPath = Selection.activeObject != null
|
|
? AssetDatabase.GetAssetPath(Selection.activeObject)
|
|
: null;
|
|
string activeAsset = string.IsNullOrEmpty(activeAssetPath)
|
|
? null
|
|
: Path.GetFullPath(activeAssetPath).Replace('\\', '/');
|
|
|
|
var payload = new
|
|
{
|
|
activeObject = Selection.activeObject?.name,
|
|
activeAsset = activeAsset,
|
|
activeGameObject = Selection.activeGameObject?.name,
|
|
activeTransform = Selection.activeTransform?.name,
|
|
activeInstanceID = InstanceIdExtensions.ActiveSelectionInstanceId(),
|
|
#if UNITY_2020_1_OR_NEWER
|
|
count = Selection.count,
|
|
#else
|
|
count = Selection.objects?.Length ?? 0,
|
|
#endif
|
|
objects = Selection.objects
|
|
.Where(obj => obj != null)
|
|
.Select(obj => new
|
|
{
|
|
name = obj.name,
|
|
type = obj.GetType().FullName,
|
|
instanceID = obj.GetStableInstanceId(),
|
|
})
|
|
.ToList(),
|
|
gameObjects = Selection.gameObjects
|
|
.Where(go => go != null)
|
|
.Select(go => new
|
|
{
|
|
name = go.name,
|
|
path = GetGameObjectHierarchyPath(go),
|
|
instanceID = go.GetStableInstanceId(),
|
|
})
|
|
.ToList(),
|
|
assetGUIDs = assetGUIDs,
|
|
assetPaths = assetPaths,
|
|
};
|
|
|
|
return JObject.FromObject(payload);
|
|
}
|
|
|
|
private static string GetGameObjectHierarchyPath(GameObject obj)
|
|
{
|
|
if (obj == null) return string.Empty;
|
|
|
|
var path = obj.name;
|
|
var parent = obj.transform != null ? obj.transform.parent : null;
|
|
while (parent != null)
|
|
{
|
|
path = $"{parent.name}/{path}";
|
|
parent = parent.parent;
|
|
}
|
|
return path;
|
|
}
|
|
}
|
|
}
|