This commit is contained in:
DESKTOP-5RP3AKU\Jisol
2024-10-17 03:20:22 +08:00
parent dd2e0e8a46
commit 0d600a2786
1490 changed files with 12905 additions and 7825 deletions

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 262a8509f1a5bf741b5f85a2139411fe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 6c507488b29c44aeba9cf9bd600ce661
timeCreated: 1727603074

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 6701e67e7fd5443dbf09a11f89c08b4a
timeCreated: 1727603101

View File

@@ -1,326 +0,0 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using JNGame.Runtime.Util;
using JNGame.Map;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEditor;
using JNGame.Math;
using JNGame.Util;
namespace JNGame.Game.Editor
{
/// <summary>
/// 简易地图数据导出器
/// </summary>
[CustomEditor(typeof(GenMapConfigHelper))]
public class MapConfigExporter : UnityEditor.Editor
{
/// <summary>
/// 导出地图数据存储路径
/// </summary>
private string m_ExportMapFolder;
/// <summary>
/// 原始Unity烘焙的导航网格数据
/// </summary>
private UnityEngine.AI.NavMeshTriangulation m_OriginNavMeshTriangulation;
/// <summary>
/// 优化后的Unity烘焙的导航网格数据
/// </summary>
private UnityEngine.AI.NavMeshTriangulation m_OptimizeNavMeshTriangulation;
/// <summary>
/// 地图配置生成器辅助
/// </summary>
private GenMapConfigHelper m_GenMapCfgHelper;
/// <summary>
/// 运行时使用的地图数据
/// </summary>
private StaticMapData m_MapData;
private void OnEnable()
{
m_ExportMapFolder = UnityEngine.Application.dataPath + "/Resources/Battle/Map/NavMesh/";
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
m_GenMapCfgHelper = target as GenMapConfigHelper;
if (GUILayout.Button("构建地图配置"))
{
if (m_GenMapCfgHelper == null) { return; }
// 检查地图导出目录是否存在,不存在则创建
if (!Directory.Exists(m_ExportMapFolder))
{
Directory.CreateDirectory(m_ExportMapFolder);
Debug.LogWarning($"导出路径 = {m_ExportMapFolder} 不存在,先创建导出目录!");
}
m_MapData = new StaticMapData();
m_MapData.mapID = m_GenMapCfgHelper.mapID;
m_MapData.mapName = string.IsNullOrEmpty(m_GenMapCfgHelper.mapName) ? $"Map_{m_MapData.mapID}" : m_GenMapCfgHelper.mapName;
// 导出地图导航数据
ExportNavMeshData();
// 地图数据写入文件
StaticMapDataToFile(m_MapData);
AssetDatabase.Refresh();
}
if (GUILayout.Button("地图可视化"))
{
// m_GenMapCfgHelper.MapVisualize();
}
}
/// <summary>
/// 导出地图的导航网格数据
/// </summary>
/// <param name="mapRootNode"></param>
/// <param name="mapCfg"></param>
public void ExportNavMeshData()
{
NavMeshSurface navMeshSurface = m_GenMapCfgHelper.navMeshSurface;
navMeshSurface.gameObject.SetActive(false);
// 通过Unity构建原生的导航网格数据
// navMeshSurface.BuildNavMesh();
Profiler.ResetElapseTime();
UnityEngine.AI.NavMeshDataInstance handle = UnityEngine.AI.NavMesh.AddNavMeshData(navMeshSurface.navMeshData);
m_OriginNavMeshTriangulation = UnityEngine.AI.NavMesh.CalculateTriangulation();
Profiler.LogElapseTime("[构建导航网格]");
// 优化Unity的NavMesh数据
OptimizeNavMeshTriangulation();
Profiler.LogElapseTime("[优化导航网格]");
// 导出游戏使用的导航网格数据
float minX = float.MaxValue;
float maxX = float.MinValue;
float minZ = float.MaxValue;
float maxZ = float.MinValue;
foreach (var vertex in m_OptimizeNavMeshTriangulation.vertices)
{
if (vertex.x > maxX) maxX = vertex.x;
if (vertex.x < minX) minX = vertex.x;
if (vertex.y > maxX) maxX = vertex.y;
if (vertex.y < minX) minX = vertex.y;
if (vertex.z > maxZ) maxZ = vertex.z;
if (vertex.z < minZ) minZ = vertex.z;
}
m_MapData.navMeshData = new PathFinding.NavMeshData
{
mapID = m_MapData.mapID,
radius = navMeshSurface.GetBuildSettings().agentRadius.ToLFloat(),
xMin = minX.ToLFloat(),
zMin = minZ.ToLFloat(),
xMax = maxX.ToLFloat(),
zMax = maxZ.ToLFloat(),
pathTriangles = m_OptimizeNavMeshTriangulation.indices
};
MergeVertices(m_MapData, m_OptimizeNavMeshTriangulation.vertices);
Profiler.LogElapseTime("[合并导航网格]");
navMeshSurface.gameObject.SetActive(true);
// 移除导航网格数据
handle.Remove();
}
/// <summary>
/// 过滤落在阻挡区域的NavMesh顶点
/// </summary>
private void OptimizeNavMeshTriangulation()
{
NavMeshSurface navMeshSurface = m_GenMapCfgHelper.navMeshSurface;
NavMeshStaticObstacle[] obstacles = navMeshSurface.gameObject.GetComponentsInChildren<NavMeshStaticObstacle>();
m_OptimizeNavMeshTriangulation = m_OriginNavMeshTriangulation;
// for (int i = 0; i < m_OptimizeNavMeshTriangulation.vertices.Length; ++i)
// {
// Vector3 point = m_OptimizeNavMeshTriangulation.vertices[i];
// m_OptimizeNavMeshTriangulation.vertices[i] = new Vector3(point.x, 0, point.z);
// }
if (obstacles == null || obstacles.Length == 0) { return; }
List<Vector3> vertices = m_OriginNavMeshTriangulation.vertices.ToList();
List<int> indices = m_OriginNavMeshTriangulation.indices.ToList();
List<int> delVertexIndices = new List<int>();
// 遍历顶点,筛选在阻挡中的顶点
for (int i = 0; i < vertices.Count; ++i)
{
for (int j = 0; j < obstacles.Length; ++j)
{
if (obstacles[j].IsInObstacle(new Vector3(vertices[i].x, 0, vertices[i].z)))
{
delVertexIndices.Add(i);
break; //
}
}
}
// 移除阻挡内的导航网格顶点,更新索引
for (int i = delVertexIndices.Count - 1; i >= 0; --i)
{
vertices.RemoveAt(delVertexIndices[i]);
for (int j = 0; j < indices.Count; ++j)
{
if (indices[j] == delVertexIndices[i])
{
indices[j] = -1;
}
else if (indices[j] > delVertexIndices[i])
{
--indices[j];
}
}
}
// 移除所有标记的索引
for (int j = indices.Count - 1; j >= 0; --j)
{
if (indices[j] == -1)
{
indices.RemoveAt(j);
}
}
m_OptimizeNavMeshTriangulation = m_OriginNavMeshTriangulation;
m_OptimizeNavMeshTriangulation.vertices = vertices.ToArray();
m_OptimizeNavMeshTriangulation.indices = indices.ToArray();
}
/// <summary>
/// 将Unity生成导航网格顶点数据合并到地图导航数据中
/// </summary>
/// <param name="mapData">目标地图文件</param>
/// <param name="pathVertices">Unity生成的导航网格顶点数据</param>
private void MergeVertices(StaticMapData mapData, Vector3[] pathVertices)
{
var rawCount = pathVertices.Length;
var rawVertices = pathVertices;
double minGap = 0.05;
var dictHashCache = new Dictionary<double, List<Vector3>>();
double Hash31(Vector3 vec)
{
return (long)(((double)vec.sqrMagnitude) / minGap) * minGap;
}
bool CanMerge(double hash, Vector3 vertex)
{
bool canMerge = false;
for (int j = -1; j <= 1; j++)
{
var nearHash = hash + minGap * j;
if (dictHashCache.TryGetValue(nearHash, out var lst))
{
foreach (var ver in lst)
{
if ((ver - vertex).sqrMagnitude < minGap)
{
canMerge = true;
break;
}
}
}
if (canMerge) break;
}
return canMerge;
}
for (int i = 0; i < rawVertices.Length; i++)
{
var vertex = rawVertices[i];
var hash = Hash31(vertex);
bool canMerge = CanMerge(hash, vertex);
if (!canMerge)
{
if (dictHashCache.TryGetValue(hash, out var lst))
{
lst.Add(vertex);
}
else
{
dictHashCache.Add(hash, new List<Vector3>() { vertex });
}
}
}
var newVertices = new List<Vector3>();
var pos2Idx = new Dictionary<Vector3, int>();
int posIds = 0;
foreach (var pair in dictHashCache)
{
foreach (var vec in pair.Value)
{
newVertices.Add(vec);
pos2Idx.Add(vec, posIds++);
}
}
mapData.navMeshData.pathVertices = newVertices.ToArray().ToLVecArray();
var rawIdxs = mapData.navMeshData.pathTriangles;
var newIdxs = new int[mapData.navMeshData.pathTriangles.Length];
for (int i = 0; i < rawIdxs.Length; i++)
{
var rawVertex = rawVertices[rawIdxs[i]];
var hash = Hash31(rawVertex);
bool merged = false;
for (int j = -1; j <= 1; j++)
{
var nearHash = hash + minGap * j;
if (dictHashCache.TryGetValue(nearHash, out var lst))
{
foreach (var ver in lst)
{
if ((ver - rawVertex).magnitude < minGap)
{
newIdxs[i] = pos2Idx[ver];
merged = true;
break;
}
}
}
if (merged) break;
}
if (!merged)
{
Debug.LogError($"hehe can not find merge point" + rawVertex);
}
}
//check the same
for (int i = 0; i < rawIdxs.Length; i++)
{
var rawPos = rawVertices[rawIdxs[i]];
var newPos = newVertices[newIdxs[i]];
if (rawPos != newPos)
{
var diff = (rawPos - newPos).sqrMagnitude;
if (diff > 0.01f)
{
Debug.LogError("Miss match pos rawPos:{rawPos} newPos:{newPos} diff = " + diff);
}
}
}
mapData.navMeshData.pathTriangles = newIdxs;
Debug.Log($"MergeVertices {rawCount}->{mapData.navMeshData.pathVertices.Length}");
}
/// <summary>
/// 地图数据写入到文件中
/// </summary>
/// <param name="filename"></param>
/// <param name="mapData"></param>
private void StaticMapDataToFile(StaticMapData staticMapData)
{
string strMapDataJsonData = JsonUtil.ToJson(staticMapData);
Profiler.LogElapseTime("[构建地图Json数据]");
string strMapDataPath = m_ExportMapFolder + m_MapData.mapName + ".navmesh.json";
using (StreamWriter sw = new StreamWriter(strMapDataPath))
{
sw.Write(strMapDataJsonData);
}
Profiler.LogElapseTime("[写入地图文件]");
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 3b9429c876a94cdf85e1829719847076
timeCreated: 1715151925

View File

@@ -1,24 +0,0 @@
using UnityEngine;
namespace JNGame.Game.Editor
{
/// <summary>
/// 地图编辑时静态阻挡的标记,运行时无用
/// </summary>
public class NavMeshStaticObstacle : MonoBehaviour
{
/// <summary>
/// 判读点是否在阻挡内
/// </summary>
/// <param name="position"></param>
/// <returns></returns>
public bool IsInObstacle(in Vector3 position)
{
MeshFilter meshFilter = GetComponent<MeshFilter>();
if (meshFilter == null || meshFilter.sharedMesh == null) { return false; }
Vector3 localPosition = transform.worldToLocalMatrix.MultiplyPoint(position);
return meshFilter.sharedMesh.bounds.Contains(localPosition);
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: d90ecad448df4047b9f38f928cc9e15b
timeCreated: 1715153091

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f5d0c5be78d74f4989de7e063e90e52b
timeCreated: 1715335958

View File

@@ -1,31 +0,0 @@
using UnityEditor;
using UnityEngine;
namespace JNGame.Map.DotRecast.Editor
{
[CustomEditor(typeof(DotRecastController))]
public class DotRecastEditor : UnityEditor.Editor
{
private DotRecastController dotRecast;
private void OnEnable()
{
dotRecast = target as DotRecastController;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (GUILayout.Button("Save"))
{
dotRecast.Save();
}
if (GUILayout.Button("Load"))
{
dotRecast.Load();
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: d8673655a79141d48eb9e89c85ee1a9a
timeCreated: 1715335972

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 3a463afa3ce24cebb875da044c666e7c
timeCreated: 1728890378

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 0fd5fb833d7052844bccf8586bf6c6f2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 031306aa4d4844c41a6e49716a1aa275
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,91 +0,0 @@
using System.Linq;
using DesperateDevs.Serialization;
using DesperateDevs.Unity.Editor;
using UnityEditor;
using UnityEngine;
namespace Entitas.Unity.Editor
{
public class EntitasPreferencesDrawer : AbstractPreferencesDrawer
{
public override string Title => "Entitas";
const string ENTITAS_FAST_AND_UNSAFE = "ENTITAS_FAST_AND_UNSAFE";
enum AERCMode
{
Safe,
FastAndUnsafe
}
Texture2D _headerTexture;
ScriptingDefineSymbols _scriptingDefineSymbols;
AERCMode _aercMode;
public override void Initialize(Preferences preferences)
{
_headerTexture = EditorLayout.LoadTexture("l:EntitasHeader");
_scriptingDefineSymbols = new ScriptingDefineSymbols();
_aercMode = ScriptingDefineSymbols.BuildTargetGroups
.All(buildTarget => PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTarget).Contains(ENTITAS_FAST_AND_UNSAFE))
? AERCMode.FastAndUnsafe
: AERCMode.Safe;
}
public override void DrawHeader(Preferences preferences)
{
drawToolbar();
drawHeader(preferences);
}
void drawToolbar()
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
{
if (GUILayout.Button("Check for Updates", EditorStyles.toolbarButton))
CheckForUpdates.DisplayUpdates();
if (GUILayout.Button("Chat", EditorStyles.toolbarButton))
EntitasFeedback.EntitasChat();
if (GUILayout.Button("Wiki", EditorStyles.toolbarButton))
EntitasFeedback.EntitasWiki();
if (GUILayout.Button("Donate", EditorStyles.toolbarButton))
EntitasFeedback.Donate();
}
EditorGUILayout.EndHorizontal();
}
void drawHeader(Preferences preferences) => EditorLayout.DrawTexture(_headerTexture);
protected override void OnDrawContent(Preferences preferences)
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField("Automatic Entity Reference Counting");
var buttonStyle = new GUIStyle(EditorStyles.miniButtonLeft);
if (_aercMode == AERCMode.Safe)
buttonStyle.normal = buttonStyle.active;
if (GUILayout.Button("Safe", buttonStyle))
{
_aercMode = AERCMode.Safe;
_scriptingDefineSymbols.RemoveForAll(ENTITAS_FAST_AND_UNSAFE);
}
buttonStyle = new GUIStyle(EditorStyles.miniButtonRight);
if (_aercMode == AERCMode.FastAndUnsafe)
buttonStyle.normal = buttonStyle.active;
if (GUILayout.Button("Fast And Unsafe", buttonStyle))
{
_aercMode = AERCMode.FastAndUnsafe;
_scriptingDefineSymbols.AddForAll(ENTITAS_FAST_AND_UNSAFE);
}
}
EditorGUILayout.EndHorizontal();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: de51c8dd81efa9c4495de6eb534faa74
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,27 +0,0 @@
using System;
using DesperateDevs.Unity.Editor;
using UnityEditor;
using UnityEngine;
namespace Entitas.Unity.Editor
{
public class EntitasPreferencesWindow : PreferencesWindow
{
[MenuItem(EntitasMenuItems.preferences, false, EntitasMenuItemPriorities.preferences)]
public static void OpenPreferences()
{
var window = GetWindow<EntitasPreferencesWindow>(true, $"Entitas {CheckForUpdates.GetLocalVersion()}");
window.minSize = new Vector2(415f, 348f);
window.Initialize(
"Entitas.properties",
$"{Environment.UserName}.userproperties",
false,
false,
"Entitas.Unity.Editor.EntitasPreferencesDrawer",
"Entitas.VisualDebugging.Unity.Editor.VisualDebuggingPreferencesDrawer"
);
window.Show();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 02609bede7ea43b4d98b7d87ad79e9c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: cfbaabc5b8b6bfb45b20060aef9c2b8d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,123 +0,0 @@
fileFormatVersion: 2
guid: 65fb57b88da1f40c59682763366ab260
labels:
- EntitasHeader
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 2
aniso: 1
mipBias: -100
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 2330149993debea4b80f6d48b28484bf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,148 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
namespace Entitas.Unity.Editor
{
public enum UpdateState
{
UpToDate,
UpdateAvailable,
AheadOfLatestRelease,
NoConnection
}
public class UpdateInfo
{
public UpdateState updateState => _updateState;
public readonly string localVersionString;
public readonly string remoteVersionString;
readonly UpdateState _updateState;
public UpdateInfo(string localVersionString, string remoteVersionString)
{
this.localVersionString = localVersionString.Trim();
this.remoteVersionString = remoteVersionString.Trim();
if (remoteVersionString != string.Empty)
{
var localVersion = new Version(localVersionString);
var remoteVersion = new Version(remoteVersionString);
switch (remoteVersion.CompareTo(localVersion))
{
case 1:
_updateState = UpdateState.UpdateAvailable;
break;
case 0:
_updateState = UpdateState.UpToDate;
break;
case -1:
_updateState = UpdateState.AheadOfLatestRelease;
break;
}
}
else
{
_updateState = UpdateState.NoConnection;
}
}
}
public static class CheckForUpdates
{
const string URL_GITHUB_API_LATEST_RELEASE = "https://api.github.com/repos/sschmid/Entitas/releases/latest";
const string URL_GITHUB_RELEASES = "https://github.com/sschmid/Entitas/releases";
const string URL_ASSET_STORE = "http://u3d.as/NuJ";
[MenuItem(EntitasMenuItems.check_for_updates, false, EntitasMenuItemPriorities.check_for_updates)]
public static void DisplayUpdates() => displayUpdateInfo(GetUpdateInfo());
public static UpdateInfo GetUpdateInfo() => new UpdateInfo(GetLocalVersion(), GetRemoteVersion());
public static string GetLocalVersion() => EntitasResources.GetVersion();
public static string GetRemoteVersion()
{
try
{
return JsonUtility.FromJson<ResponseData>(requestLatestRelease()).tag_name;
}
catch (Exception)
{
// ignored
}
return string.Empty;
}
static string requestLatestRelease()
{
var response = string.Empty;
using (var www = UnityWebRequest.Get(URL_GITHUB_API_LATEST_RELEASE))
{
var asyncOperation = www.SendWebRequest();
while (!asyncOperation.isDone) { }
if (www.result != UnityWebRequest.Result.ConnectionError &&
www.result != UnityWebRequest.Result.ProtocolError)
{
response = asyncOperation.webRequest.downloadHandler.text;
}
}
return response;
}
static void displayUpdateInfo(UpdateInfo info)
{
switch (info.updateState)
{
case UpdateState.UpdateAvailable:
if (EditorUtility.DisplayDialog("Entitas Update",
$"A newer version of Entitas is available!\n\nCurrently installed version: {info.localVersionString}\nNew version: {info.remoteVersionString}",
"Show in Unity Asset Store",
"Cancel"))
{
Application.OpenURL(URL_ASSET_STORE);
}
break;
case UpdateState.UpToDate:
EditorUtility.DisplayDialog("Entitas Update",
$"Entitas is up to date ({info.localVersionString})",
"Ok");
break;
case UpdateState.AheadOfLatestRelease:
if (EditorUtility.DisplayDialog("Entitas Update",
$"Your Entitas version seems to be newer than the latest release?!?\n\nCurrently installed version: {info.localVersionString}\nLatest release: {info.remoteVersionString}",
"Show in Unity Asset Store",
"Cancel"))
{
Application.OpenURL(URL_ASSET_STORE);
}
break;
case UpdateState.NoConnection:
if (EditorUtility.DisplayDialog("Entitas Update",
"Could not request latest Entitas version!\n\nMake sure that you are connected to the internet.\n",
"Try again",
"Cancel"
))
{
DisplayUpdates();
}
break;
}
}
struct ResponseData
{
public string tag_name;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: dfc6e6102a7183f44a4acdc6513abbba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,49 +0,0 @@
using UnityEditor;
using UnityEngine;
namespace Entitas.Unity.Editor
{
public static class EntitasMenuItems
{
public const string preferences = "Tools/Entitas/Preferences... #%e";
public const string check_for_updates = "Tools/Entitas/Check for Updates...";
public const string feedback_report_a_bug = "Tools/Entitas/Feedback/Report a bug...";
public const string feedback_request_a_feature = "Tools/Entitas/Feedback/Request a feature...";
public const string feedback_join_the_entitas_chat = "Tools/Entitas/Feedback/Join the Entitas chat...";
public const string feedback_entitas_wiki = "Tools/Entitas/Feedback/Entitas Wiki...";
public const string feedback_donate = "Tools/Entitas/Feedback/Donate...";
}
public static class EntitasMenuItemPriorities
{
public const int preferences = 1;
public const int check_for_updates = 10;
public const int feedback_report_a_bug = 20;
public const int feedback_request_a_feature = 21;
public const int feedback_join_the_entitas_chat = 22;
public const int feedback_entitas_wiki = 23;
public const int feedback_donate = 24;
}
public static class EntitasFeedback
{
[MenuItem(EntitasMenuItems.feedback_report_a_bug, false, EntitasMenuItemPriorities.feedback_report_a_bug)]
public static void ReportBug() => Application.OpenURL("https://github.com/sschmid/Entitas/issues");
[MenuItem(EntitasMenuItems.feedback_request_a_feature, false, EntitasMenuItemPriorities.feedback_request_a_feature)]
public static void RequestFeature() => Application.OpenURL("https://github.com/sschmid/Entitas/issues");
[MenuItem(EntitasMenuItems.feedback_join_the_entitas_chat, false, EntitasMenuItemPriorities.feedback_join_the_entitas_chat)]
public static void EntitasChat() => Application.OpenURL("https://discord.gg/uHrVx5Z");
[MenuItem(EntitasMenuItems.feedback_entitas_wiki, false, EntitasMenuItemPriorities.feedback_entitas_wiki)]
public static void EntitasWiki() => Application.OpenURL("https://github.com/sschmid/Entitas/wiki");
[MenuItem(EntitasMenuItems.feedback_donate, false, EntitasMenuItemPriorities.feedback_donate)]
public static void Donate() => Application.OpenURL("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BTMLSDQULZ852");
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b307fa4290196f64592af67f758feada
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 65c6c8e35d22fc34d8a2289d8e2a85c1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 9464c0d053f4303478bfa9e5921cd048
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 471340db3cc1f454bb11f398ad5c14e1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,75 +0,0 @@
using System.Linq;
using DesperateDevs.Unity.Editor;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
[CustomEditor(typeof(ContextObserverBehaviour))]
public class ContextObserverInspector : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
var contextObserver = ((ContextObserverBehaviour)target).contextObserver;
EditorLayout.BeginVerticalBox();
{
EditorGUILayout.LabelField(contextObserver.context.contextInfo.name, EditorStyles.boldLabel);
EditorGUILayout.LabelField("Entities", contextObserver.context.count.ToString());
EditorGUILayout.LabelField("Reusable entities", contextObserver.context.reusableEntitiesCount.ToString());
var retainedEntitiesCount = contextObserver.context.retainedEntitiesCount;
if (retainedEntitiesCount != 0)
{
var c = GUI.color;
GUI.color = Color.red;
EditorGUILayout.LabelField("Retained entities", retainedEntitiesCount.ToString());
GUI.color = c;
EditorGUILayout.HelpBox("WARNING: There are retained entities.\nDid you call entity.Retain(owner) and forgot to call entity.Release(owner)?", MessageType.Warning);
}
EditorGUILayout.BeginHorizontal();
{
if (GUILayout.Button("Create Entity"))
{
var entity = contextObserver.context.CreateEntity();
var entityBehaviour = Object.FindObjectsOfType<EntityBehaviour>()
.Single(eb => eb.entity == entity);
Selection.activeGameObject = entityBehaviour.gameObject;
}
var bgColor = GUI.backgroundColor;
GUI.backgroundColor = Color.red;
if (GUILayout.Button("Destroy All Entities"))
contextObserver.context.DestroyAllEntities();
GUI.backgroundColor = bgColor;
}
EditorGUILayout.EndHorizontal();
}
EditorLayout.EndVerticalBox();
var groups = contextObserver.groups;
if (groups.Length != 0)
{
EditorLayout.BeginVerticalBox();
{
EditorGUILayout.LabelField($"Groups ({groups.Length})", EditorStyles.boldLabel);
foreach (var group in groups.OrderByDescending(g => g.count))
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(group.ToString());
EditorGUILayout.LabelField(group.count.ToString(), GUILayout.Width(48));
}
EditorGUILayout.EndHorizontal();
}
}
EditorLayout.EndVerticalBox();
}
EditorUtility.SetDirty(target);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 73115cfc10a3cb7428b480fc912472fa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: a4526b5c12716c64fa1941c83e4cc5da
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,417 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DesperateDevs.Serialization;
using DesperateDevs.Unity.Editor;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
[CustomEditor(typeof(DebugSystemsBehaviour))]
public class DebugSystemsInspector : UnityEditor.Editor
{
enum SortMethod
{
OrderOfOccurrence,
Name,
NameDescending,
ExecutionTime,
ExecutionTimeDescending
}
Graph _systemsMonitor;
Queue<float> _systemMonitorData;
const int SYSTEM_MONITOR_DATA_LENGTH = 60;
static bool _showDetails = false;
static bool _showSystemsMonitor = true;
static bool _showSystemsList = true;
static bool _showInitializeSystems = true;
static bool _showExecuteSystems = true;
static bool _showSyncSystems = true;
static bool _showCleanupSystems = true;
static bool _showTearDownSystems = true;
static bool _hideEmptySystems = true;
static string _systemNameSearchString = string.Empty;
int _systemWarningThreshold;
float _threshold;
SortMethod _systemSortMethod;
int _lastRenderedFrameCount;
GUIContent _stepButtonContent;
GUIContent _pauseButtonContent;
void OnEnable()
{
try
{
var preferences = new Preferences("Entitas.properties", $"{Environment.UserName}.userproperties");
var config = preferences.CreateAndConfigure<VisualDebuggingConfig>();
_systemWarningThreshold = config.systemWarningThreshold;
}
catch (Exception)
{
_systemWarningThreshold = int.MaxValue;
}
}
public override void OnInspectorGUI()
{
var debugSystemsBehaviour = (DebugSystemsBehaviour)target;
var systems = debugSystemsBehaviour.systems;
EditorGUILayout.Space();
drawSystemsOverview(systems);
EditorGUILayout.Space();
drawSystemsMonitor(systems);
EditorGUILayout.Space();
drawSystemList(systems);
EditorGUILayout.Space();
EditorUtility.SetDirty(target);
}
static void drawSystemsOverview(DebugSystems systems)
{
_showDetails = EditorLayout.DrawSectionHeaderToggle("Details", _showDetails);
if (_showDetails)
{
EditorLayout.BeginSectionContent();
{
EditorGUILayout.LabelField(systems.name, EditorStyles.boldLabel);
EditorGUILayout.LabelField("Initialize Systems", systems.totalInitializeSystemsCount.ToString());
EditorGUILayout.LabelField("Execute Systems", systems.totalExecuteSystemsCount.ToString());
EditorGUILayout.LabelField("Cleanup Systems", systems.totalCleanupSystemsCount.ToString());
EditorGUILayout.LabelField("TearDown Systems", systems.totalTearDownSystemsCount.ToString());
EditorGUILayout.LabelField("Total Systems", systems.totalSystemsCount.ToString());
}
EditorLayout.EndSectionContent();
}
}
void drawSystemsMonitor(DebugSystems systems)
{
if (_systemsMonitor == null)
{
_systemsMonitor = new Graph(SYSTEM_MONITOR_DATA_LENGTH);
_systemMonitorData = new Queue<float>(new float[SYSTEM_MONITOR_DATA_LENGTH]);
}
_showSystemsMonitor = EditorLayout.DrawSectionHeaderToggle("Performance", _showSystemsMonitor);
if (_showSystemsMonitor)
{
EditorLayout.BeginSectionContent();
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.BeginVertical();
{
EditorGUILayout.LabelField("Execution duration", systems.executeDuration.ToString());
EditorGUILayout.LabelField("NSync duration", systems.SyncDuration.ToString());
EditorGUILayout.LabelField("Cleanup duration", systems.cleanupDuration.ToString());
}
EditorGUILayout.EndVertical();
if (_stepButtonContent == null)
_stepButtonContent = EditorGUIUtility.IconContent("StepButton On");
if (_pauseButtonContent == null)
_pauseButtonContent = EditorGUIUtility.IconContent("PauseButton On");
systems.paused = GUILayout.Toggle(systems.paused, _pauseButtonContent, "CommandLeft");
if (GUILayout.Button(_stepButtonContent, "CommandRight"))
{
systems.paused = true;
systems.StepExecute();
systems.StepCleanup();
addDuration((float)systems.executeDuration + (float)systems.cleanupDuration + (float)systems.SyncDuration);
}
}
EditorGUILayout.EndHorizontal();
if (!EditorApplication.isPaused && !systems.paused)
addDuration((float)systems.executeDuration + (float)systems.cleanupDuration + (float)systems.SyncDuration);
_systemsMonitor.Draw(_systemMonitorData.ToArray(), 80f);
}
EditorLayout.EndSectionContent();
}
}
void drawSystemList(DebugSystems systems)
{
_showSystemsList = EditorLayout.DrawSectionHeaderToggle("Systems", _showSystemsList);
if (_showSystemsList)
{
EditorLayout.BeginSectionContent();
{
EditorGUILayout.BeginHorizontal();
{
DebugSystems.avgResetInterval = (AvgResetInterval)EditorGUILayout.EnumPopup("Reset average duration Ø", DebugSystems.avgResetInterval);
if (GUILayout.Button("Reset Ø now", EditorStyles.miniButton, GUILayout.Width(88)))
systems.ResetDurations();
}
EditorGUILayout.EndHorizontal();
_threshold = EditorGUILayout.Slider("Threshold Ø ms", _threshold, 0f, 33f);
_hideEmptySystems = EditorGUILayout.Toggle("Hide empty systems", _hideEmptySystems);
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
{
_systemSortMethod = (SortMethod)EditorGUILayout.EnumPopup(_systemSortMethod, EditorStyles.popup, GUILayout.Width(150));
_systemNameSearchString = EditorLayout.SearchTextField(_systemNameSearchString);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
_showInitializeSystems = EditorLayout.DrawSectionHeaderToggle("Initialize Systems", _showInitializeSystems);
if (_showInitializeSystems && shouldShowSystems(systems, SystemInterfaceFlags.IInitializeSystem))
{
EditorLayout.BeginSectionContent();
{
var systemsDrawn = drawSystemInfos(systems, SystemInterfaceFlags.IInitializeSystem);
if (systemsDrawn == 0)
EditorGUILayout.LabelField(string.Empty);
}
EditorLayout.EndSectionContent();
}
_showExecuteSystems = EditorLayout.DrawSectionHeaderToggle("Execute Systems", _showExecuteSystems);
if (_showExecuteSystems && shouldShowSystems(systems, SystemInterfaceFlags.IExecuteSystem))
{
EditorLayout.BeginSectionContent();
{
var systemsDrawn = drawSystemInfos(systems, SystemInterfaceFlags.IExecuteSystem);
if (systemsDrawn == 0)
EditorGUILayout.LabelField(string.Empty);
}
EditorLayout.EndSectionContent();
}
_showSyncSystems = EditorLayout.DrawSectionHeaderToggle("JNSync Systems", _showSyncSystems);
if (_showSyncSystems && shouldShowSystems(systems, SystemInterfaceFlags.ISyncSystem))
{
EditorLayout.BeginSectionContent();
{
var systemsDrawn = drawSystemInfos(systems, SystemInterfaceFlags.ISyncSystem);
if (systemsDrawn == 0)
EditorGUILayout.LabelField(string.Empty);
}
EditorLayout.EndSectionContent();
}
_showCleanupSystems = EditorLayout.DrawSectionHeaderToggle("Cleanup Systems", _showCleanupSystems);
if (_showCleanupSystems && shouldShowSystems(systems, SystemInterfaceFlags.ICleanupSystem))
{
EditorLayout.BeginSectionContent();
{
var systemsDrawn = drawSystemInfos(systems, SystemInterfaceFlags.ICleanupSystem);
if (systemsDrawn == 0)
EditorGUILayout.LabelField(string.Empty);
}
EditorLayout.EndSectionContent();
}
_showTearDownSystems = EditorLayout.DrawSectionHeaderToggle("TearDown Systems", _showTearDownSystems);
if (_showTearDownSystems && shouldShowSystems(systems, SystemInterfaceFlags.ITearDownSystem))
{
EditorLayout.BeginSectionContent();
{
var systemsDrawn = drawSystemInfos(systems, SystemInterfaceFlags.ITearDownSystem);
if (systemsDrawn == 0)
EditorGUILayout.LabelField(string.Empty);
}
EditorLayout.EndSectionContent();
}
}
EditorLayout.EndSectionContent();
}
}
int drawSystemInfos(DebugSystems systems, SystemInterfaceFlags type)
{
IEnumerable<SystemInfo> systemInfos = null;
switch (type)
{
case SystemInterfaceFlags.IInitializeSystem:
systemInfos = systems.initializeSystemInfos.Where(systemInfo => systemInfo.initializationDuration >= _threshold);
break;
case SystemInterfaceFlags.IExecuteSystem:
systemInfos = systems.executeSystemInfos.Where(systemInfo => systemInfo.averageExecutionDuration >= _threshold);
break;
case SystemInterfaceFlags.ISyncSystem:
systemInfos = systems.syncSystemInfos.Where(systemInfo => systemInfo.averageSyncDuration >= _threshold);
break;
case SystemInterfaceFlags.ICleanupSystem:
systemInfos = systems.cleanupSystemInfos.Where(systemInfo => systemInfo.cleanupDuration >= _threshold);
break;
case SystemInterfaceFlags.ITearDownSystem:
systemInfos = systems.tearDownSystemInfos.Where(systemInfo => systemInfo.teardownDuration >= _threshold);
break;
}
systemInfos = getSortedSystemInfos(systemInfos, _systemSortMethod);
var systemsDrawn = 0;
foreach (var systemInfo in systemInfos)
{
if (systemInfo.system is DebugSystems debugSystems)
if (!shouldShowSystems(debugSystems, type))
continue;
if (EditorLayout.MatchesSearchString(systemInfo.systemName.ToLower(), _systemNameSearchString.ToLower()))
{
EditorGUILayout.BeginHorizontal();
{
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
var wasActive = systemInfo.isActive;
if (systemInfo.areAllParentsActive)
{
systemInfo.isActive = EditorGUILayout.Toggle(systemInfo.isActive, GUILayout.Width(20));
}
else
{
EditorGUI.BeginDisabledGroup(true);
{
EditorGUILayout.Toggle(false, GUILayout.Width(20));
}
}
EditorGUI.EndDisabledGroup();
EditorGUI.indentLevel = indent;
if (systemInfo.isActive != wasActive)
{
var reactiveSystem = systemInfo.system as IReactiveSystem;
if (reactiveSystem != null)
{
if (systemInfo.isActive)
reactiveSystem.Activate();
else
reactiveSystem.Deactivate();
}
}
switch (type)
{
case SystemInterfaceFlags.IInitializeSystem:
EditorGUILayout.LabelField(systemInfo.systemName, systemInfo.initializationDuration.ToString(), getSystemStyle(systemInfo, SystemInterfaceFlags.IInitializeSystem));
break;
case SystemInterfaceFlags.IExecuteSystem:
var avgE = $"Ø {systemInfo.averageExecutionDuration:00.000}".PadRight(12);
var minE = $"▼ {systemInfo.minExecutionDuration:00.000}".PadRight(12);
var maxE = $"▲ {systemInfo.maxExecutionDuration:00.000}";
EditorGUILayout.LabelField(systemInfo.systemName, avgE + minE + maxE, getSystemStyle(systemInfo, SystemInterfaceFlags.IExecuteSystem));
break;
case SystemInterfaceFlags.ISyncSystem:
var avgE1 = $"Ø {systemInfo.averageSyncDuration:00.000}".PadRight(12);
var minE1 = $"▼ {systemInfo.minSyncDuration:00.000}".PadRight(12);
var maxE1 = $"▲ {systemInfo.maxSyncDuration:00.000}";
EditorGUILayout.LabelField(systemInfo.systemName, avgE1 + minE1 + maxE1, getSystemStyle(systemInfo, SystemInterfaceFlags.ISyncSystem));
break;
case SystemInterfaceFlags.ICleanupSystem:
var avgC = $"Ø {systemInfo.averageCleanupDuration:00.000}".PadRight(12);
var minC = $"▼ {systemInfo.minCleanupDuration:00.000}".PadRight(12);
var maxC = $"▲ {systemInfo.maxCleanupDuration:00.000}";
EditorGUILayout.LabelField(systemInfo.systemName, avgC + minC + maxC, getSystemStyle(systemInfo, SystemInterfaceFlags.ICleanupSystem));
break;
case SystemInterfaceFlags.ITearDownSystem:
EditorGUILayout.LabelField(systemInfo.systemName, systemInfo.teardownDuration.ToString(), getSystemStyle(systemInfo, SystemInterfaceFlags.ITearDownSystem));
break;
}
}
EditorGUILayout.EndHorizontal();
systemsDrawn += 1;
}
if (systemInfo.system is DebugSystems debugSystem)
{
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel += 1;
systemsDrawn += drawSystemInfos(debugSystem, type);
EditorGUI.indentLevel = indent;
}
}
return systemsDrawn;
}
static IEnumerable<SystemInfo> getSortedSystemInfos(IEnumerable<SystemInfo> systemInfos, SortMethod sortMethod) => sortMethod switch
{
SortMethod.Name => systemInfos.OrderBy(systemInfo => systemInfo.systemName),
SortMethod.NameDescending => systemInfos.OrderByDescending(systemInfo => systemInfo.systemName),
SortMethod.ExecutionTime => systemInfos.OrderBy(systemInfo => systemInfo.averageExecutionDuration),
SortMethod.ExecutionTimeDescending => systemInfos.OrderByDescending(systemInfo => systemInfo.averageExecutionDuration),
_ => systemInfos
};
static bool shouldShowSystems(DebugSystems systems, SystemInterfaceFlags type)
{
if (!_hideEmptySystems)
return true;
return type switch
{
SystemInterfaceFlags.IInitializeSystem => systems.totalInitializeSystemsCount > 0,
SystemInterfaceFlags.IExecuteSystem => systems.totalExecuteSystemsCount > 0,
SystemInterfaceFlags.ISyncSystem => systems.totalSystemsCount > 0,
SystemInterfaceFlags.ICleanupSystem => systems.totalCleanupSystemsCount > 0,
SystemInterfaceFlags.ITearDownSystem => systems.totalTearDownSystemsCount > 0,
_ => true
};
}
GUIStyle getSystemStyle(SystemInfo systemInfo, SystemInterfaceFlags systemFlag)
{
var style = new GUIStyle(GUI.skin.label);
var color = systemInfo.isReactiveSystems && EditorGUIUtility.isProSkin
? Color.white
: style.normal.textColor;
if (systemFlag == SystemInterfaceFlags.ISyncSystem && systemInfo.averageExecutionDuration >= _systemWarningThreshold)
color = Color.red;
if (systemFlag == SystemInterfaceFlags.IExecuteSystem && systemInfo.averageExecutionDuration >= _systemWarningThreshold)
color = Color.red;
if (systemFlag == SystemInterfaceFlags.ICleanupSystem && systemInfo.averageCleanupDuration >= _systemWarningThreshold)
color = Color.red;
style.normal.textColor = color;
return style;
}
void addDuration(float duration)
{
// OnInspectorGUI is called twice per frame - only add duration once
if (Time.renderedFrameCount != _lastRenderedFrameCount)
{
_lastRenderedFrameCount = Time.renderedFrameCount;
if (_systemMonitorData.Count >= SYSTEM_MONITOR_DATA_LENGTH)
_systemMonitorData.Dequeue();
_systemMonitorData.Enqueue(duration);
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7aa873373c3dc324ea22f1033d425ac6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,181 +0,0 @@
using System;
using DesperateDevs.Serialization;
using DesperateDevs.Unity.Editor;
using Entitas.Unity;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
[InitializeOnLoad]
public static class EntitasHierarchyIcon
{
static Texture2D contextHierarchyIcon
{
get
{
if (_contextHierarchyIcon == null)
_contextHierarchyIcon = EditorLayout.LoadTexture("l:EntitasContextHierarchyIcon");
return _contextHierarchyIcon;
}
}
static Texture2D contextErrorHierarchyIcon
{
get
{
if (_contextErrorHierarchyIcon == null)
_contextErrorHierarchyIcon = EditorLayout.LoadTexture("l:EntitasContextErrorHierarchyIcon");
return _contextErrorHierarchyIcon;
}
}
static Texture2D entityHierarchyIcon
{
get
{
if (_entityHierarchyIcon == null)
_entityHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityHierarchyIcon");
return _entityHierarchyIcon;
}
}
static Texture2D entityErrorHierarchyIcon
{
get
{
if (_entityErrorHierarchyIcon == null)
_entityErrorHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityErrorHierarchyIcon");
return _entityErrorHierarchyIcon;
}
}
static Texture2D entityLinkHierarchyIcon
{
get
{
if (_entityLinkHierarchyIcon == null)
_entityLinkHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityLinkHierarchyIcon");
return _entityLinkHierarchyIcon;
}
}
static Texture2D entityLinkWarnHierarchyIcon
{
get
{
if (_entityLinkWarnHierarchyIcon == null)
_entityLinkWarnHierarchyIcon = EditorLayout.LoadTexture("l:EntitasEntityLinkWarnHierarchyIcon");
return _entityLinkWarnHierarchyIcon;
}
}
static Texture2D systemsHierarchyIcon
{
get
{
if (_systemsHierarchyIcon == null)
_systemsHierarchyIcon = EditorLayout.LoadTexture("l:EntitasSystemsHierarchyIcon");
return _systemsHierarchyIcon;
}
}
static Texture2D systemsWarnHierarchyIcon
{
get
{
if (_systemsWarnHierarchyIcon == null)
_systemsWarnHierarchyIcon = EditorLayout.LoadTexture("l:EntitasSystemsWarnHierarchyIcon");
return _systemsWarnHierarchyIcon;
}
}
static Texture2D _contextHierarchyIcon;
static Texture2D _contextErrorHierarchyIcon;
static Texture2D _entityHierarchyIcon;
static Texture2D _entityErrorHierarchyIcon;
static Texture2D _entityLinkHierarchyIcon;
static Texture2D _entityLinkWarnHierarchyIcon;
static Texture2D _systemsHierarchyIcon;
static Texture2D _systemsWarnHierarchyIcon;
static readonly int _systemWarningThreshold;
static EntitasHierarchyIcon()
{
try
{
var preferences = new Preferences("Entitas.properties", $"{Environment.UserName}.userproperties");
var config = preferences.CreateAndConfigure<VisualDebuggingConfig>();
_systemWarningThreshold = config.systemWarningThreshold;
}
catch (Exception)
{
_systemWarningThreshold = int.MaxValue;
}
EditorApplication.hierarchyWindowItemOnGUI += onHierarchyWindowItemOnGUI;
}
static void onHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect)
{
var gameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (gameObject != null)
{
const float iconSize = 16f;
const float iconOffset = iconSize + 2f;
var rect = new Rect(selectionRect.x + selectionRect.width - iconOffset, selectionRect.y, iconSize, iconSize);
var contextObserver = gameObject.GetComponent<ContextObserverBehaviour>();
if (contextObserver != null)
{
if (contextObserver.contextObserver.context.retainedEntitiesCount != 0)
GUI.DrawTexture(rect, contextErrorHierarchyIcon);
else
GUI.DrawTexture(rect, contextHierarchyIcon);
return;
}
var entityBehaviour = gameObject.GetComponent<EntityBehaviour>();
if (entityBehaviour != null)
{
if (entityBehaviour.entity.isEnabled)
GUI.DrawTexture(rect, entityHierarchyIcon);
else
GUI.DrawTexture(rect, entityErrorHierarchyIcon);
return;
}
var entityLink = gameObject.GetComponent<EntityLink>();
if (entityLink != null)
{
if (entityLink.entity != null)
GUI.DrawTexture(rect, entityLinkHierarchyIcon);
else
GUI.DrawTexture(rect, entityLinkWarnHierarchyIcon);
return;
}
var debugSystemsBehaviour = gameObject.GetComponent<DebugSystemsBehaviour>();
if (debugSystemsBehaviour != null)
{
// if (debugSystemsBehaviour.systems.executeDuration < _systemWarningThreshold)
// GUI.DrawTexture(rect, systemsHierarchyIcon);
// else
// GUI.DrawTexture(rect, systemsWarnHierarchyIcon);
}
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 87ffb92133ceb4a4a99874c57b40aa16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,87 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DesperateDevs.Extensions;
using DesperateDevs.Reflection;
using Entitas.CodeGeneration.Attributes;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public static class EntitasStats
{
[MenuItem("Tools/Entitas/Show Stats", false, 200)]
public static void ShowStats()
{
var stats = string.Join("\n", GetStats().Select(kv => $"{kv.Key}: {kv.Value}"));
Debug.Log(stats);
EditorUtility.DisplayDialog("Entitas Stats", stats, "Close");
}
public static Dictionary<string, int> GetStats()
{
var types = AppDomain.CurrentDomain.GetAllTypes();
var components = types
.Where(type => type.ImplementsInterface<IComponent>())
.ToArray();
var systems = types
.Where(isSystem)
.ToArray();
var contexts = getContexts(components);
var stats = new Dictionary<string, int>
{
{"Total Components", components.Length},
{"Systems", systems.Length}
};
foreach (var context in contexts)
stats.Add($"Components in {context.Key}", context.Value);
return stats;
}
static Dictionary<string, int> getContexts(Type[] components) => components
.Aggregate(new Dictionary<string, int>(), (contexts, type) =>
{
var contextNames = getContextNamesOrDefault(type);
foreach (var contextName in contextNames)
{
if (!contexts.ContainsKey(contextName))
contexts.Add(contextName, 0);
contexts[contextName] += 1;
}
return contexts;
});
static string[] getContextNames(Type type) => Attribute
.GetCustomAttributes(type)
.OfType<ContextAttribute>()
.Select(attr => attr.contextName)
.ToArray();
static string[] getContextNamesOrDefault(Type type)
{
var contextNames = getContextNames(type);
if (contextNames.Length == 0)
contextNames = new[] {"Default"};
return contextNames;
}
static bool isSystem(Type type) =>
type.ImplementsInterface<ISystem>()
&& type != typeof(ReactiveSystem<>)
&& type != typeof(MultiReactiveSystem<,>)
&& type != typeof(Systems)
&& type != typeof(DebugSystems)
&& type != typeof(JobSystem<>)
&& type.FullName != "Feature";
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 4a2f2ad9c544c4a4f9356a5ecb9e899c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 4503a6064910c7d48935484707cd5ac4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 36803bc65992ec547a5a3e51c6c1e9c1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,12 +0,0 @@
using System;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class DefaultArrayCreator : IDefaultInstanceCreator
{
public bool HandlesType(Type type) => type.IsArray;
public object CreateDefault(Type type) =>
Array.CreateInstance(type.GetElementType(), new int[type.GetArrayRank()]);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7839da582b1d07a45963c45229305968
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,11 +0,0 @@
using System;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class DefaultStringCreator : IDefaultInstanceCreator
{
public bool HandlesType(Type type) => type == typeof(string);
public object CreateDefault(Type type) => string.Empty;
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cefc30582be2fc14eabcae7e6f561d8e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,11 +0,0 @@
using System;
namespace Entitas.VisualDebugging.Unity.Editor
{
public interface IDefaultInstanceCreator
{
bool HandlesType(Type type);
object CreateDefault(Type type);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 0d7964946744bd84dab0de37f121559d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 5df6568d01ad91547a054f87e486122c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,452 +0,0 @@
using System;
using System.IO;
using System.Linq;
using DesperateDevs.Extensions;
using DesperateDevs.Reflection;
using DesperateDevs.Serialization;
using DesperateDevs.Unity.Editor;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public static partial class EntityDrawer
{
public static void DrawEntity(IEntity entity)
{
var bgColor = GUI.backgroundColor;
GUI.backgroundColor = Color.red;
if (GUILayout.Button("Destroy Entity"))
entity.Destroy();
GUI.backgroundColor = bgColor;
DrawComponents(entity);
EditorGUILayout.Space();
EditorGUILayout.LabelField($"Retained by ({entity.retainCount})", EditorStyles.boldLabel);
var safeAerc = entity.aerc as SafeAERC;
if (safeAerc != null)
{
EditorLayout.BeginVerticalBox();
{
foreach (var owner in safeAerc.owners.OrderBy(o => o.GetType().Name))
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(owner.ToString());
if (EditorLayout.MiniButton("Release"))
entity.Release(owner);
EditorGUILayout.EndHorizontal();
}
}
}
EditorLayout.EndVerticalBox();
}
}
public static void DrawMultipleEntities(IEntity[] entities)
{
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
{
var entity = entities[0];
var index = drawAddComponentMenu(entity);
if (index >= 0)
{
var componentType = entity.contextInfo.componentTypes[index];
foreach (var e in entities)
{
var component = e.CreateComponent(index, componentType);
e.AddComponent(index, component);
}
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
var bgColor = GUI.backgroundColor;
GUI.backgroundColor = Color.red;
if (GUILayout.Button("Destroy selected entities"))
foreach (var e in entities)
e.Destroy();
GUI.backgroundColor = bgColor;
EditorGUILayout.Space();
foreach (var e in entities)
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(e.ToString());
bgColor = GUI.backgroundColor;
GUI.backgroundColor = Color.red;
if (EditorLayout.MiniButton("Destroy Entity"))
e.Destroy();
GUI.backgroundColor = bgColor;
}
EditorGUILayout.EndHorizontal();
}
}
public static void DrawComponents(IEntity entity)
{
var unfoldedComponents = getUnfoldedComponents(entity);
var componentMemberSearch = getComponentMemberSearch(entity);
EditorLayout.BeginVerticalBox();
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField($"Components ({entity.GetComponents().Length})", EditorStyles.boldLabel);
if (EditorLayout.MiniButtonLeft("▸"))
for (var i = 0; i < unfoldedComponents.Length; i++)
unfoldedComponents[i] = false;
if (EditorLayout.MiniButtonRight("▾"))
for (var i = 0; i < unfoldedComponents.Length; i++)
unfoldedComponents[i] = true;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
var index = drawAddComponentMenu(entity);
if (index >= 0)
{
var componentType = entity.contextInfo.componentTypes[index];
var component = entity.CreateComponent(index, componentType);
entity.AddComponent(index, component);
}
EditorGUILayout.Space();
componentNameSearchString = EditorLayout.SearchTextField(componentNameSearchString);
EditorGUILayout.Space();
var indices = entity.GetComponentIndices();
var components = entity.GetComponents();
for (var i = 0; i < components.Length; i++)
DrawComponent(unfoldedComponents, componentMemberSearch, entity, indices[i], components[i]);
}
EditorLayout.EndVerticalBox();
}
public static void DrawComponent(bool[] unfoldedComponents, string[] componentMemberSearch, IEntity entity, int index, IComponent component)
{
var componentType = component.GetType();
var componentName = componentType.Name.RemoveComponentSuffix();
if (EditorLayout.MatchesSearchString(componentName.ToLower(), componentNameSearchString.ToLower()))
{
var boxStyle = getColoredBoxStyle(entity, index);
EditorGUILayout.BeginVertical(boxStyle);
{
if (!Attribute.IsDefined(componentType, typeof(DontDrawComponentAttribute)))
{
var memberInfos = componentType.GetPublicMemberInfos();
EditorGUILayout.BeginHorizontal();
{
if (memberInfos.Length == 0)
{
EditorGUILayout.LabelField(componentName, EditorStyles.boldLabel);
}
else
{
unfoldedComponents[index] = EditorLayout.Foldout(unfoldedComponents[index], componentName, foldoutStyle);
if (unfoldedComponents[index])
{
componentMemberSearch[index] = memberInfos.Length > 5
? EditorLayout.SearchTextField(componentMemberSearch[index])
: string.Empty;
}
}
if (EditorLayout.MiniButton("-"))
entity.RemoveComponent(index);
}
EditorGUILayout.EndHorizontal();
if (unfoldedComponents[index])
{
var newComponent = entity.CreateComponent(index, componentType);
component.CopyPublicMemberValues(newComponent);
var changed = false;
var componentDrawer = getComponentDrawer(componentType);
if (componentDrawer != null)
{
EditorGUI.BeginChangeCheck();
{
componentDrawer.DrawComponent(newComponent);
}
changed = EditorGUI.EndChangeCheck();
}
else
{
foreach (var info in memberInfos)
{
if (EditorLayout.MatchesSearchString(info.Name.ToLower(), componentMemberSearch[index].ToLower()))
{
var memberValue = info.GetValue(newComponent);
var memberType = memberValue == null ? info.Type : memberValue.GetType();
if (DrawObjectMember(memberType, info.Name, memberValue, newComponent, info.SetValue))
changed = true;
}
}
}
if (changed)
entity.ReplaceComponent(index, newComponent);
else
entity.GetComponentPool(index).Push(newComponent);
}
}
else
{
EditorGUILayout.LabelField(componentName, "[DontDrawComponent]", EditorStyles.boldLabel);
}
}
EditorLayout.EndVerticalBox();
}
}
public static bool DrawObjectMember(Type memberType, string memberName, object value, object target, Action<object, object> setValue)
{
if (value == null)
{
EditorGUI.BeginChangeCheck();
{
var isUnityObject = memberType == typeof(UnityEngine.Object) || memberType.IsSubclassOf(typeof(UnityEngine.Object));
EditorGUILayout.BeginHorizontal();
{
if (isUnityObject)
setValue(target, EditorGUILayout.ObjectField(memberName, (UnityEngine.Object)value, memberType, true));
else
EditorGUILayout.LabelField(memberName, "null");
if (EditorLayout.MiniButton($"new {memberType.ToCompilableString().ShortTypeName()}"))
{
if (CreateDefault(memberType, out var defaultValue))
setValue(target, defaultValue);
}
}
EditorGUILayout.EndHorizontal();
}
return EditorGUI.EndChangeCheck();
}
if (!memberType.IsValueType)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical();
}
EditorGUI.BeginChangeCheck();
{
var typeDrawer = getTypeDrawer(memberType);
if (typeDrawer != null)
{
var newValue = typeDrawer.DrawAndGetNewValue(memberType, memberName, value, target);
setValue(target, newValue);
}
else
{
var targetType = target.GetType();
var shouldDraw = !targetType.ImplementsInterface<IComponent>() || !Attribute.IsDefined(targetType, typeof(DontDrawComponentAttribute));
if (shouldDraw)
{
EditorGUILayout.LabelField(memberName, value.ToString());
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel += 1;
EditorGUILayout.BeginVertical();
{
foreach (var info in memberType.GetPublicMemberInfos())
{
var mValue = info.GetValue(value);
var mType = mValue == null ? info.Type : mValue.GetType();
DrawObjectMember(mType, info.Name, mValue, value, info.SetValue);
if (memberType.IsValueType)
setValue(target, value);
}
}
EditorGUILayout.EndVertical();
EditorGUI.indentLevel = indent;
}
else
{
drawUnsupportedType(memberType, memberName, value);
}
}
if (!memberType.IsValueType)
{
EditorGUILayout.EndVertical();
if (EditorLayout.MiniButton("×"))
setValue(target, null);
EditorGUILayout.EndHorizontal();
}
}
return EditorGUI.EndChangeCheck();
}
public static bool CreateDefault(Type type, out object defaultValue)
{
try
{
defaultValue = Activator.CreateInstance(type);
return true;
}
catch (Exception)
{
foreach (var creator in _defaultInstanceCreators)
{
if (creator.HandlesType(type))
{
defaultValue = creator.CreateDefault(type);
return true;
}
}
}
var typeName = type.ToCompilableString();
if (EditorUtility.DisplayDialog(
"No IDefaultInstanceCreator found",
"There's no IDefaultInstanceCreator implementation to handle the type '" + typeName + "'.\n" +
"Providing an IDefaultInstanceCreator enables you to create instances for that type.\n\n" +
"Do you want to generate an IDefaultInstanceCreator implementation for '" + typeName + "'?\n",
"Generate",
"Cancel"
))
{
GenerateIDefaultInstanceCreator(typeName);
}
defaultValue = null;
return false;
}
static int drawAddComponentMenu(IEntity entity)
{
var componentInfos = getComponentInfos(entity)
.Where(info => !entity.HasComponent(info.index))
.ToArray();
var componentNames = componentInfos
.Select(info => info.name)
.ToArray();
var index = EditorGUILayout.Popup("Add Component", -1, componentNames);
return index >= 0
? componentInfos[index].index
: -1;
}
static void drawUnsupportedType(Type memberType, string memberName, object value)
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(memberName, value.ToString());
if (EditorLayout.MiniButton("Missing ITypeDrawer"))
{
var typeName = memberType.ToCompilableString();
if (EditorUtility.DisplayDialog(
"No ITypeDrawer found",
"There's no ITypeDrawer implementation to handle the type '" + typeName + "'.\n" +
"Providing an ITypeDrawer enables you draw instances for that type.\n\n" +
"Do you want to generate an ITypeDrawer implementation for '" + typeName + "'?\n",
"Generate",
"Cancel"
))
{
GenerateITypeDrawer(typeName);
}
}
}
EditorGUILayout.EndHorizontal();
}
public static void GenerateIDefaultInstanceCreator(string typeName)
{
var preferences = new Preferences("Entitas.properties", $"{Environment.UserName}.userproperties");
var config = preferences.CreateAndConfigure<VisualDebuggingConfig>();
var folder = config.defaultInstanceCreatorFolderPath;
var filePath = folder + Path.DirectorySeparatorChar + "Default" + typeName.ShortTypeName() + "InstanceCreator.cs";
var template = DEFAULT_INSTANCE_CREATOR_TEMPLATE_FORMAT
.Replace("${Type}", typeName)
.Replace("${ShortType}", typeName.ShortTypeName());
generateTemplate(folder, filePath, template);
}
public static void GenerateITypeDrawer(string typeName)
{
var preferences = new Preferences("Entitas.properties", $"{Environment.UserName}.userproperties");
var config = preferences.CreateAndConfigure<VisualDebuggingConfig>();
var folder = config.typeDrawerFolderPath;
var filePath = folder + Path.DirectorySeparatorChar + typeName.ShortTypeName() + "TypeDrawer.cs";
var template = TYPE_DRAWER_TEMPLATE_FORMAT
.Replace("${Type}", typeName)
.Replace("${ShortType}", typeName.ShortTypeName());
generateTemplate(folder, filePath, template);
}
static void generateTemplate(string folder, string filePath, string template)
{
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
File.WriteAllText(filePath, template);
EditorApplication.isPlaying = false;
AssetDatabase.Refresh();
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(filePath);
}
const string DEFAULT_INSTANCE_CREATOR_TEMPLATE_FORMAT =
@"using System;
using Entitas.VisualDebugging.Unity.Editor;
public class Default${ShortType}InstanceCreator : IDefaultInstanceCreator {
public bool HandlesType(Type type) {
return type == typeof(${Type});
}
public object CreateDefault(Type type) {
// TODO return an instance of type ${Type}
throw new NotImplementedException();
}
}
";
const string TYPE_DRAWER_TEMPLATE_FORMAT =
@"using System;
using Entitas;
using Entitas.VisualDebugging.Unity.Editor;
public class ${ShortType}TypeDrawer : ITypeDrawer {
public bool HandlesType(Type type) {
return type == typeof(${Type});
}
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) {
// TODO draw the type ${Type}
throw new NotImplementedException();
}
}
";
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b8c341de02276434e984855d9db34f8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,176 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DesperateDevs.Reflection;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public static partial class EntityDrawer
{
static Dictionary<string, bool[]> _contextToUnfoldedComponents;
public static Dictionary<string, bool[]> contextToUnfoldedComponents =>
_contextToUnfoldedComponents ?? (_contextToUnfoldedComponents = new Dictionary<string, bool[]>());
static Dictionary<string, string[]> _contextToComponentMemberSearch;
public static Dictionary<string, string[]> contextToComponentMemberSearch =>
_contextToComponentMemberSearch ?? (_contextToComponentMemberSearch = new Dictionary<string, string[]>());
static Dictionary<string, GUIStyle[]> _contextToColoredBoxStyles;
public static Dictionary<string, GUIStyle[]> contextToColoredBoxStyles =>
_contextToColoredBoxStyles ?? (_contextToColoredBoxStyles = new Dictionary<string, GUIStyle[]>());
public struct ComponentInfo
{
public int index;
public string name;
public Type type;
}
static Dictionary<string, ComponentInfo[]> _contextToComponentInfos;
public static Dictionary<string, ComponentInfo[]> contextToComponentInfos =>
_contextToComponentInfos ?? (_contextToComponentInfos = new Dictionary<string, ComponentInfo[]>());
static GUIStyle _foldoutStyle;
public static GUIStyle foldoutStyle
{
get
{
if (_foldoutStyle == null)
{
_foldoutStyle = new GUIStyle(EditorStyles.foldout);
_foldoutStyle.fontStyle = FontStyle.Bold;
}
return _foldoutStyle;
}
}
static string _componentNameSearchString;
public static string componentNameSearchString
{
get => _componentNameSearchString ?? (_componentNameSearchString = string.Empty);
set => _componentNameSearchString = value;
}
public static readonly IDefaultInstanceCreator[] _defaultInstanceCreators;
public static readonly ITypeDrawer[] _typeDrawers;
public static readonly IComponentDrawer[] _componentDrawers;
static EntityDrawer()
{
_defaultInstanceCreators = AppDomain.CurrentDomain.GetInstancesOf<IDefaultInstanceCreator>().ToArray();
_typeDrawers = AppDomain.CurrentDomain.GetInstancesOf<ITypeDrawer>().ToArray();
_componentDrawers = AppDomain.CurrentDomain.GetInstancesOf<IComponentDrawer>().ToArray();
}
static bool[] getUnfoldedComponents(IEntity entity)
{
if (!contextToUnfoldedComponents.TryGetValue(entity.contextInfo.name, out var unfoldedComponents))
{
unfoldedComponents = new bool[entity.totalComponents];
for (var i = 0; i < unfoldedComponents.Length; i++)
unfoldedComponents[i] = true;
contextToUnfoldedComponents.Add(entity.contextInfo.name, unfoldedComponents);
}
return unfoldedComponents;
}
static string[] getComponentMemberSearch(IEntity entity)
{
if (!contextToComponentMemberSearch.TryGetValue(entity.contextInfo.name, out var componentMemberSearch))
{
componentMemberSearch = new string[entity.totalComponents];
for (var i = 0; i < componentMemberSearch.Length; i++)
componentMemberSearch[i] = string.Empty;
contextToComponentMemberSearch.Add(entity.contextInfo.name, componentMemberSearch);
}
return componentMemberSearch;
}
static ComponentInfo[] getComponentInfos(IEntity entity)
{
if (!contextToComponentInfos.TryGetValue(entity.contextInfo.name, out var infos))
{
var contextInfo = entity.contextInfo;
var infosList = new List<ComponentInfo>(contextInfo.componentTypes.Length);
for (var i = 0; i < contextInfo.componentTypes.Length; i++)
{
infosList.Add(new ComponentInfo
{
index = i,
name = contextInfo.componentNames[i],
type = contextInfo.componentTypes[i]
});
}
infos = infosList.ToArray();
contextToComponentInfos.Add(entity.contextInfo.name, infos);
}
return infos;
}
static GUIStyle getColoredBoxStyle(IEntity entity, int index)
{
if (!contextToColoredBoxStyles.TryGetValue(entity.contextInfo.name, out var styles))
{
styles = new GUIStyle[entity.totalComponents];
for (var i = 0; i < styles.Length; i++)
{
var hue = (float)i / (float)entity.totalComponents;
var componentColor = Color.HSVToRGB(hue, 0.7f, 1f);
componentColor.a = 0.15f;
var style = new GUIStyle(GUI.skin.box);
style.normal.background = createTexture(2, 2, componentColor);
styles[i] = style;
}
contextToColoredBoxStyles.Add(entity.contextInfo.name, styles);
}
return styles[index];
}
static Texture2D createTexture(int width, int height, Color color)
{
var pixels = new Color[width * height];
for (var i = 0; i < pixels.Length; ++i)
pixels[i] = color;
var result = new Texture2D(width, height);
result.SetPixels(pixels);
result.Apply();
return result;
}
static IComponentDrawer getComponentDrawer(Type type)
{
foreach (var drawer in _componentDrawers)
if (drawer.HandlesType(type))
return drawer;
return null;
}
static ITypeDrawer getTypeDrawer(Type type)
{
foreach (var drawer in _typeDrawers)
if (drawer.HandlesType(type))
return drawer;
return null;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f1e837164b267c44eaa35131c841fdb5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,28 +0,0 @@
using System.Linq;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
[CustomEditor(typeof(EntityBehaviour)), CanEditMultipleObjects]
public class EntityInspector : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
if (targets.Length == 1)
{
EntityDrawer.DrawEntity(((EntityBehaviour)target).entity);
}
else
{
var entities = targets
.Select(t => ((EntityBehaviour)t).entity)
.ToArray();
EntityDrawer.DrawMultipleEntities(entities);
}
if (target != null)
EditorUtility.SetDirty(target);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f23e43f40d885ab47b7cf8a57b9d25c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,11 +0,0 @@
using System;
namespace Entitas.VisualDebugging.Unity.Editor
{
public interface IComponentDrawer
{
bool HandlesType(Type type);
IComponent DrawComponent(IComponent component);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 767e084899e4ae441bfad7192b64be0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 3fd7bdd65e7d1054d8da306d48dce4a5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class AnimationCurveTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(AnimationCurve);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.CurveField(memberName, (AnimationCurve)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d0208986e746acb4586a5b49a7938a29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,203 +0,0 @@
using System;
using System.Collections;
using DesperateDevs.Extensions;
using DesperateDevs.Unity.Editor;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class ArrayTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type.IsArray;
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target)
{
var array = (Array)value;
var elementType = memberType.GetElementType();
var indent = EditorGUI.indentLevel;
if (array.Rank == 1)
array = drawRank1(array, memberName, elementType, indent, target);
else if (array.Rank == 2)
array = drawRank2(array, memberName, elementType, target);
else if (array.Rank == 3)
array = drawRank3(array, memberName, elementType, target);
EditorGUI.indentLevel = indent;
return array;
}
/*
*
* Rank 1
*
*/
Array drawRank1(Array array, string memberName, Type elementType, int indent, object target)
{
var length = array.GetLength(0);
if (length == 0)
array = drawAddElement(array, memberName, elementType);
else
EditorGUILayout.LabelField(memberName);
EditorGUI.indentLevel = indent + 1;
Func<Array> editAction = null;
for (var i = 0; i < length; i++)
{
var localIndex = i;
EditorGUILayout.BeginHorizontal();
{
EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex}]", array.GetValue(localIndex),
target, (newComponent, newValue) => array.SetValue(newValue, localIndex));
var action = drawEditActions(array, elementType, localIndex);
if (action != null)
editAction = action;
}
EditorGUILayout.EndHorizontal();
}
if (editAction != null)
array = editAction();
return array;
}
Array drawAddElement(Array array, string memberName, Type elementType)
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(memberName, "empty");
if (EditorLayout.MiniButton($"add {elementType.ToCompilableString().ShortTypeName()}"))
{
if (EntityDrawer.CreateDefault(elementType, out var defaultValue))
{
var newArray = Array.CreateInstance(elementType, 1);
newArray.SetValue(defaultValue, 0);
array = newArray;
}
}
}
EditorGUILayout.EndHorizontal();
return array;
}
/*
*
* Rank 2
*
*/
Array drawRank2(Array array, string memberName, Type elementType, object target)
{
EditorGUILayout.LabelField(memberName);
for (var i = 0; i < array.GetLength(0); i++)
{
var localIndex1 = i;
for (var j = 0; j < array.GetLength(1); j++)
{
var localIndex2 = j;
EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex1}, {localIndex2}]", array.GetValue(localIndex1, localIndex2),
target, (newComponent, newValue) => array.SetValue(newValue, localIndex1, localIndex2));
}
EditorGUILayout.Space();
}
return array;
}
/*
*
* Rank 3
*
*/
Array drawRank3(Array array, string memberName, Type elementType, object target)
{
EditorGUILayout.LabelField(memberName);
for (var i = 0; i < array.GetLength(0); i++)
{
var localIndex1 = i;
for (var j = 0; j < array.GetLength(1); j++)
{
var localIndex2 = j;
for (var k = 0; k < array.GetLength(2); k++)
{
var localIndex3 = k;
EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex1}, {localIndex2}, {localIndex3}]", array.GetValue(localIndex1, localIndex2, localIndex3),
target, (newComponent, newValue) => array.SetValue(newValue, localIndex1, localIndex2, localIndex3));
}
EditorGUILayout.Space();
}
EditorGUILayout.Space();
}
return array;
}
static Func<Array> drawEditActions(Array array, Type elementType, int index)
{
if (EditorLayout.MiniButtonLeft("↑"))
{
if (index > 0)
{
return () =>
{
var otherIndex = index - 1;
var other = array.GetValue(otherIndex);
array.SetValue(array.GetValue(index), otherIndex);
array.SetValue(other, index);
return array;
};
}
}
if (EditorLayout.MiniButtonMid("↓"))
{
if (index < array.Length - 1)
{
return () =>
{
var otherIndex = index + 1;
var other = array.GetValue(otherIndex);
array.SetValue(array.GetValue(index), otherIndex);
array.SetValue(other, index);
return array;
};
}
}
if (EditorLayout.MiniButtonMid("+"))
if (EntityDrawer.CreateDefault(elementType, out var defaultValue))
return () => arrayInsertAt(array, elementType, defaultValue, index + 1);
if (EditorLayout.MiniButtonRight("-"))
return () => arrayRemoveAt(array, elementType, index);
return null;
}
static Array arrayRemoveAt(Array array, Type elementType, int removeAt)
{
var arrayList = new ArrayList(array);
arrayList.RemoveAt(removeAt);
return arrayList.ToArray(elementType);
}
static Array arrayInsertAt(Array array, Type elementType, object value, int insertAt)
{
var arrayList = new ArrayList(array);
arrayList.Insert(insertAt, value);
return arrayList.ToArray(elementType);
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a8e055e8d366cf64d8b26ac71a3c5984
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class BoolTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(bool);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.Toggle(memberName, (bool)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fa5643f4fc78ff249b3cb9fe0edb2e0b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class BoundsTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(Bounds);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.BoundsField(memberName, (Bounds)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cf455b9a782c972438e19219c8f79f69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,18 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class CharTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(char);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target)
{
var str = EditorGUILayout.TextField(memberName, ((char)value).ToString());
return str.Length > 0
? str[0]
: default;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 186ed118a8a247e4da7133a5d65f3f7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class ColorTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(Color);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.ColorField(memberName, (Color)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: da13d69eac35dba4e9b9d2e95ce138e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,20 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class DateTimeTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(DateTime);
// Note: This is a very basic implementation. The ToString() method conversion will cut off milliseconds.
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target)
{
var dateString = value.ToString();
var newDateString = EditorGUILayout.TextField(memberName, dateString);
return newDateString != dateString
? DateTime.Parse(newDateString)
: value;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: db17b51b86835ea4e92bed92a2321b21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,89 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using DesperateDevs.Extensions;
using DesperateDevs.Unity.Editor;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class DictionaryTypeDrawer : ITypeDrawer
{
static readonly Dictionary<Type, string> _keySearchTexts = new Dictionary<Type, string>();
public bool HandlesType(Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target)
{
var dictionary = (IDictionary)value;
var keyType = memberType.GetGenericArguments()[0];
var valueType = memberType.GetGenericArguments()[1];
var targetType = target.GetType();
if (!_keySearchTexts.ContainsKey(targetType))
_keySearchTexts.Add(targetType, string.Empty);
EditorGUILayout.BeginHorizontal();
{
if (dictionary.Count == 0)
{
EditorGUILayout.LabelField(memberName, "empty");
_keySearchTexts[targetType] = string.Empty;
}
else
{
EditorGUILayout.LabelField(memberName);
}
var keyTypeName = keyType.ToCompilableString().ShortTypeName();
var valueTypeName = valueType.ToCompilableString().ShortTypeName();
if (EditorLayout.MiniButton($"new <{keyTypeName}, {valueTypeName}>"))
if (EntityDrawer.CreateDefault(keyType, out var defaultKey))
if (EntityDrawer.CreateDefault(valueType, out var defaultValue))
dictionary[defaultKey] = defaultValue;
}
EditorGUILayout.EndHorizontal();
if (dictionary.Count > 0)
{
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = indent + 1;
if (dictionary.Count > 5)
{
EditorGUILayout.Space();
_keySearchTexts[targetType] = EditorLayout.SearchTextField(_keySearchTexts[targetType]);
}
EditorGUILayout.Space();
var keys = new ArrayList(dictionary.Keys);
for (var i = 0; i < keys.Count; i++)
{
var key = keys[i];
if (EditorLayout.MatchesSearchString(key.ToString().ToLower(), _keySearchTexts[targetType].ToLower()))
{
EntityDrawer.DrawObjectMember(keyType, "key", key,
target, (newComponent, newValue) =>
{
var tmpValue = dictionary[key];
dictionary.Remove(key);
if (newValue != null)
{
dictionary[newValue] = tmpValue;
}
});
EntityDrawer.DrawObjectMember(valueType, "value", dictionary[key],
target, (newComponent, newValue) => dictionary[key] = newValue);
EditorGUILayout.Space();
}
}
EditorGUI.indentLevel = indent;
}
return dictionary;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 70c521c3acd0f87409f0fe461e956c08
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class DoubleTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(double);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.DoubleField(memberName, (double)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b52a30df69783134db3a0eaa46285ebd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,15 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class EnumTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type.IsEnum;
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
memberType.IsDefined(typeof(FlagsAttribute), false)
? EditorGUILayout.EnumFlagsField(memberName, (Enum)value)
: EditorGUILayout.EnumPopup(memberName, (Enum)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d4176a92d2d76cb44840f81b78088327
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class FloatTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(float);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.FloatField(memberName, (float)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 0672b246484ea094c9b32b1e7031fca8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,68 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using DesperateDevs.Extensions;
using DesperateDevs.Unity.Editor;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class HashSetTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target)
{
var elementType = memberType.GetGenericArguments()[0];
var itemsToRemove = new ArrayList();
var itemsToAdd = new ArrayList();
var isEmpty = !((IEnumerable)value).GetEnumerator().MoveNext();
EditorGUILayout.BeginHorizontal();
{
if (isEmpty)
EditorGUILayout.LabelField(memberName, "empty");
else
EditorGUILayout.LabelField(memberName);
if (EditorLayout.MiniButton($"new {elementType.ToCompilableString().ShortTypeName()}"))
if (EntityDrawer.CreateDefault(elementType, out var defaultValue))
itemsToAdd.Add(defaultValue);
}
EditorGUILayout.EndHorizontal();
if (!isEmpty)
{
EditorGUILayout.Space();
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = indent + 1;
foreach (var item in (IEnumerable)value)
{
EditorGUILayout.BeginHorizontal();
{
EntityDrawer.DrawObjectMember(elementType, string.Empty, item,
target, (newComponent, newValue) =>
{
itemsToRemove.Add(item);
itemsToAdd.Add(newValue);
});
if (EditorLayout.MiniButton("-"))
itemsToRemove.Add(item);
}
EditorGUILayout.EndHorizontal();
}
EditorGUI.indentLevel = indent;
}
foreach (var item in itemsToRemove)
memberType.GetMethod("Remove").Invoke(value, new[] {item});
foreach (var item in itemsToAdd)
memberType.GetMethod("Add").Invoke(value, new[] {item});
return value;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f401b7fcaf18a9445bed2117f9bdb2a2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,11 +0,0 @@
using System;
namespace Entitas.VisualDebugging.Unity.Editor
{
public interface ITypeDrawer
{
bool HandlesType(Type type);
object DrawAndGetNewValue(Type memberType, string memberName, object value, object target);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e085477379bb1a3469a551e7205b41a2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class IntTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(int);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.IntField(memberName, (int)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2344ecba39dc22047ba2dcd6fc92ba5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,115 +0,0 @@
using System;
using System.Collections;
using System.Linq;
using DesperateDevs.Extensions;
using DesperateDevs.Unity.Editor;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class ListTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type.GetInterfaces().Contains(typeof(IList));
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target)
{
var list = (IList)value;
var elementType = memberType.GetGenericArguments()[0];
if (list.Count == 0)
list = drawAddElement(list, memberName, elementType);
else
EditorGUILayout.LabelField(memberName);
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = indent + 1;
Func<IList> editAction = null;
for (var i = 0; i < list.Count; i++)
{
var localIndex = i;
EditorGUILayout.BeginHorizontal();
{
EntityDrawer.DrawObjectMember(elementType, $"{memberName}[{localIndex}]", list[localIndex],
target, (newComponent, newValue) => list[localIndex] = newValue);
var action = drawEditActions(list, elementType, localIndex);
if (action != null)
{
editAction = action;
}
}
EditorGUILayout.EndHorizontal();
}
if (editAction != null)
list = editAction();
EditorGUI.indentLevel = indent;
return list;
}
static Func<IList> drawEditActions(IList list, Type elementType, int index)
{
if (EditorLayout.MiniButtonLeft("↑"))
if (index > 0)
return () =>
{
var otherIndex = index - 1;
var other = list[otherIndex];
list[otherIndex] = list[index];
list[index] = other;
return list;
};
if (EditorLayout.MiniButtonMid("↓"))
if (index < list.Count - 1)
return () =>
{
var otherIndex = index + 1;
var other = list[otherIndex];
list[otherIndex] = list[index];
list[index] = other;
return list;
};
if (EditorLayout.MiniButtonMid("+"))
{
if (EntityDrawer.CreateDefault(elementType, out var defaultValue))
{
var insertAt = index + 1;
return () =>
{
list.Insert(insertAt, defaultValue);
return list;
};
}
}
if (EditorLayout.MiniButtonRight("-"))
{
var removeAt = index;
return () =>
{
list.RemoveAt(removeAt);
return list;
};
}
return null;
}
IList drawAddElement(IList list, string memberName, Type elementType)
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(memberName, "empty");
if (EditorLayout.MiniButton($"add {elementType.ToCompilableString().ShortTypeName()}"))
if (EntityDrawer.CreateDefault(elementType, out var defaultValue))
list.Add(defaultValue);
}
EditorGUILayout.EndHorizontal();
return list;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e09ccabab26c9d044be6bf7ceb1833a2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class RectTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(Rect);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.RectField(memberName, (Rect)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 466b350491d9cf4468948063648a9950
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class StringTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(string);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.DelayedTextField(memberName, (string)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fd396ae4f230fe141a65b09e50809a72
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,15 +0,0 @@
using System;
using UnityEditor;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class UnityObjectTypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) =>
type == typeof(UnityEngine.Object) ||
type.IsSubclassOf(typeof(UnityEngine.Object));
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.ObjectField(memberName, (UnityEngine.Object)value, memberType, true);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: aeb008cda984f8c459d142ce335f9697
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class Vector2TypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(Vector2);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.Vector2Field(memberName, (Vector2)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: caf2b76a2f61fe84c9c47e1b2724bb64
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class Vector3TypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(Vector3);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.Vector3Field(memberName, (Vector3)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: dcf34d5607065f947b6326dffbac494c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,14 +0,0 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
public class Vector4TypeDrawer : ITypeDrawer
{
public bool HandlesType(Type type) => type == typeof(Vector4);
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) =>
EditorGUILayout.Vector4Field(memberName, (Vector4)value);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cd4a8b28992d4a144b5417d077d608b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,39 +0,0 @@
using System.Linq;
using Entitas.Unity;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor
{
[CustomEditor(typeof(EntityLink))]
public class EntityLinkInspector : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
var link = (EntityLink)target;
if (link.entity != null)
if (GUILayout.Button("Unlink"))
link.Unlink();
if (link.entity != null)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField(link.entity.ToString());
if (GUILayout.Button("Show entity"))
Selection.activeGameObject = FindObjectsOfType<EntityBehaviour>()
.Single(e => e.entity == link.entity).gameObject;
EditorGUILayout.Space();
EntityDrawer.DrawEntity(link.entity);
}
else
{
EditorGUILayout.LabelField("Not linked to an entity");
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d537ffa36ad851f4ead175a077aad1ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 63182607bc2a385439536eda3628fb97
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More