mod
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
public class NavMeshAssetManager : ScriptableSingleton<NavMeshAssetManager>
|
||||
{
|
||||
internal struct AsyncBakeOperation
|
||||
{
|
||||
public NavMeshSurface Surface;
|
||||
public NavMeshData BakeData;
|
||||
public AsyncOperation BakeOperation;
|
||||
}
|
||||
|
||||
List<AsyncBakeOperation> m_BakeOperations = new List<AsyncBakeOperation>();
|
||||
internal List<AsyncBakeOperation> GetBakeOperations() { return m_BakeOperations; }
|
||||
|
||||
struct SavedPrefabNavMeshData
|
||||
{
|
||||
public NavMeshSurface Surface;
|
||||
public NavMeshData NavMeshData;
|
||||
}
|
||||
|
||||
List<SavedPrefabNavMeshData> m_PrefabNavMeshDataAssets = new List<SavedPrefabNavMeshData>();
|
||||
|
||||
static string GetAndEnsureTargetPath(NavMeshSurface surface)
|
||||
{
|
||||
// Create directory for the asset if it does not exist yet.
|
||||
var activeScenePath = surface.gameObject.scene.path;
|
||||
|
||||
var targetPath = "Assets";
|
||||
if (!string.IsNullOrEmpty(activeScenePath))
|
||||
{
|
||||
targetPath = Path.Combine(Path.GetDirectoryName(activeScenePath), Path.GetFileNameWithoutExtension(activeScenePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(surface.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surface.gameObject);
|
||||
if (isPartOfPrefab && !string.IsNullOrEmpty(prefabStage.assetPath))
|
||||
{
|
||||
var prefabDirectoryName = Path.GetDirectoryName(prefabStage.assetPath);
|
||||
if (!string.IsNullOrEmpty(prefabDirectoryName))
|
||||
targetPath = prefabDirectoryName;
|
||||
}
|
||||
}
|
||||
if (!Directory.Exists(targetPath))
|
||||
Directory.CreateDirectory(targetPath);
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
static void CreateNavMeshAsset(NavMeshSurface surface)
|
||||
{
|
||||
var targetPath = GetAndEnsureTargetPath(surface);
|
||||
|
||||
var combinedAssetPath = Path.Combine(targetPath, "NavMesh-" + surface.name + ".asset");
|
||||
combinedAssetPath = AssetDatabase.GenerateUniqueAssetPath(combinedAssetPath);
|
||||
AssetDatabase.CreateAsset(surface.navMeshData, combinedAssetPath);
|
||||
}
|
||||
|
||||
NavMeshData GetNavMeshAssetToDelete(NavMeshSurface navSurface)
|
||||
{
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(navSurface) && !PrefabUtility.IsPartOfModelPrefab(navSurface))
|
||||
{
|
||||
// Don't allow deleting the asset belonging to the prefab parent
|
||||
var parentSurface = PrefabUtility.GetCorrespondingObjectFromSource(navSurface) as NavMeshSurface;
|
||||
if (parentSurface && navSurface.navMeshData == parentSurface.navMeshData)
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do not delete the NavMeshData asset referenced from a prefab until the prefab is saved
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(navSurface.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(navSurface.gameObject);
|
||||
if (isPartOfPrefab && IsCurrentPrefabNavMeshDataStored(navSurface))
|
||||
return null;
|
||||
|
||||
return navSurface.navMeshData;
|
||||
}
|
||||
|
||||
void ClearSurface(NavMeshSurface navSurface)
|
||||
{
|
||||
var hasNavMeshData = navSurface.navMeshData != null;
|
||||
StoreNavMeshDataIfInPrefab(navSurface);
|
||||
|
||||
var assetToDelete = GetNavMeshAssetToDelete(navSurface);
|
||||
navSurface.RemoveData();
|
||||
|
||||
if (hasNavMeshData)
|
||||
{
|
||||
SetNavMeshData(navSurface, null);
|
||||
EditorSceneManager.MarkSceneDirty(navSurface.gameObject.scene);
|
||||
}
|
||||
|
||||
if (assetToDelete)
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(assetToDelete));
|
||||
}
|
||||
|
||||
public void StartBakingSurfaces(UnityEngine.Object[] surfaces)
|
||||
{
|
||||
// Remove first to avoid double registration of the callback
|
||||
EditorApplication.update -= UpdateAsyncBuildOperations;
|
||||
EditorApplication.update += UpdateAsyncBuildOperations;
|
||||
|
||||
foreach (NavMeshSurface surf in surfaces)
|
||||
{
|
||||
StoreNavMeshDataIfInPrefab(surf);
|
||||
|
||||
var oper = new AsyncBakeOperation();
|
||||
|
||||
oper.BakeData = InitializeBakeData(surf);
|
||||
oper.BakeOperation = surf.UpdateNavMesh(oper.BakeData);
|
||||
oper.Surface = surf;
|
||||
|
||||
m_BakeOperations.Add(oper);
|
||||
}
|
||||
}
|
||||
|
||||
static NavMeshData InitializeBakeData(NavMeshSurface surface)
|
||||
{
|
||||
var emptySources = new List<NavMeshBuildSource>();
|
||||
var emptyBounds = new Bounds();
|
||||
return UnityEngine.AI.NavMeshBuilder.BuildNavMeshData(surface.GetBuildSettings(), emptySources, emptyBounds
|
||||
, surface.transform.position, surface.transform.rotation);
|
||||
}
|
||||
|
||||
void UpdateAsyncBuildOperations()
|
||||
{
|
||||
foreach (var oper in m_BakeOperations)
|
||||
{
|
||||
if (oper.Surface == null || oper.BakeOperation == null)
|
||||
continue;
|
||||
|
||||
if (oper.BakeOperation.isDone)
|
||||
{
|
||||
var surface = oper.Surface;
|
||||
var delete = GetNavMeshAssetToDelete(surface);
|
||||
if (delete != null)
|
||||
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(delete));
|
||||
|
||||
surface.RemoveData();
|
||||
SetNavMeshData(surface, oper.BakeData);
|
||||
|
||||
if (surface.isActiveAndEnabled)
|
||||
surface.AddData();
|
||||
CreateNavMeshAsset(surface);
|
||||
EditorSceneManager.MarkSceneDirty(surface.gameObject.scene);
|
||||
}
|
||||
}
|
||||
m_BakeOperations.RemoveAll(o => o.BakeOperation == null || o.BakeOperation.isDone);
|
||||
if (m_BakeOperations.Count == 0)
|
||||
EditorApplication.update -= UpdateAsyncBuildOperations;
|
||||
}
|
||||
|
||||
public bool IsSurfaceBaking(NavMeshSurface surface)
|
||||
{
|
||||
if (surface == null)
|
||||
return false;
|
||||
|
||||
foreach (var oper in m_BakeOperations)
|
||||
{
|
||||
if (oper.Surface == null || oper.BakeOperation == null)
|
||||
continue;
|
||||
|
||||
if (oper.Surface == surface)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ClearSurfaces(UnityEngine.Object[] surfaces)
|
||||
{
|
||||
foreach (NavMeshSurface s in surfaces)
|
||||
ClearSurface(s);
|
||||
}
|
||||
|
||||
static void SetNavMeshData(NavMeshSurface navSurface, NavMeshData navMeshData)
|
||||
{
|
||||
var so = new SerializedObject(navSurface);
|
||||
var navMeshDataProperty = so.FindProperty("m_NavMeshData");
|
||||
navMeshDataProperty.objectReferenceValue = navMeshData;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
void StoreNavMeshDataIfInPrefab(NavMeshSurface surfaceToStore)
|
||||
{
|
||||
var prefabStage = PrefabStageUtility.GetPrefabStage(surfaceToStore.gameObject);
|
||||
var isPartOfPrefab = prefabStage != null && prefabStage.IsPartOfPrefabContents(surfaceToStore.gameObject);
|
||||
if (!isPartOfPrefab)
|
||||
return;
|
||||
|
||||
// check if data has already been stored for this surface
|
||||
foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets)
|
||||
if (storedAssetInfo.Surface == surfaceToStore)
|
||||
return;
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabSaving += DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
PrefabStage.prefabStageClosing += ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
|
||||
var isDataOwner = true;
|
||||
if (PrefabUtility.IsPartOfPrefabInstance(surfaceToStore) && !PrefabUtility.IsPartOfModelPrefab(surfaceToStore))
|
||||
{
|
||||
var basePrefabSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceToStore) as NavMeshSurface;
|
||||
isDataOwner = basePrefabSurface == null || surfaceToStore.navMeshData != basePrefabSurface.navMeshData;
|
||||
}
|
||||
m_PrefabNavMeshDataAssets.Add(new SavedPrefabNavMeshData { Surface = surfaceToStore, NavMeshData = isDataOwner ? surfaceToStore.navMeshData : null });
|
||||
}
|
||||
|
||||
bool IsCurrentPrefabNavMeshDataStored(NavMeshSurface surface)
|
||||
{
|
||||
if (surface == null)
|
||||
return false;
|
||||
|
||||
foreach (var storedAssetInfo in m_PrefabNavMeshDataAssets)
|
||||
{
|
||||
if (storedAssetInfo.Surface == surface)
|
||||
return storedAssetInfo.NavMeshData == surface.navMeshData;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteStoredNavMeshDataAssetsForOwnedSurfaces(GameObject gameObjectInPrefab)
|
||||
{
|
||||
// Debug.LogFormat("DeleteStoredNavMeshDataAsset() when saving prefab {0}", gameObjectInPrefab.name);
|
||||
|
||||
var surfaces = gameObjectInPrefab.GetComponentsInChildren<NavMeshSurface>(true);
|
||||
foreach (var surface in surfaces)
|
||||
DeleteStoredPrefabNavMeshDataAsset(surface);
|
||||
}
|
||||
|
||||
void DeleteStoredPrefabNavMeshDataAsset(NavMeshSurface surface)
|
||||
{
|
||||
for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var storedAssetInfo = m_PrefabNavMeshDataAssets[i];
|
||||
if (storedAssetInfo.Surface == surface)
|
||||
{
|
||||
var storedNavMeshData = storedAssetInfo.NavMeshData;
|
||||
if (storedNavMeshData != null && storedNavMeshData != surface.navMeshData)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(storedNavMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
}
|
||||
|
||||
void ForgetUnsavedNavMeshDataChanges(PrefabStage prefabStage)
|
||||
{
|
||||
// Debug.Log("On prefab closing - forget about this object's surfaces and stop caring about prefab saving");
|
||||
|
||||
if (prefabStage == null)
|
||||
return;
|
||||
|
||||
var allSurfacesInPrefab = prefabStage.prefabContentsRoot.GetComponentsInChildren<NavMeshSurface>(true);
|
||||
NavMeshSurface surfaceInPrefab = null;
|
||||
var index = 0;
|
||||
do
|
||||
{
|
||||
if (allSurfacesInPrefab.Length > 0)
|
||||
surfaceInPrefab = allSurfacesInPrefab[index];
|
||||
|
||||
for (var i = m_PrefabNavMeshDataAssets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var storedPrefabInfo = m_PrefabNavMeshDataAssets[i];
|
||||
if (storedPrefabInfo.Surface == null)
|
||||
{
|
||||
// Debug.LogFormat("A surface from the prefab got deleted after it has baked a new NavMesh but it hasn't saved it. Now the unsaved asset gets deleted. ({0})", storedPrefabInfo.navMeshData);
|
||||
|
||||
// surface got deleted, thus delete its initial NavMeshData asset
|
||||
if (storedPrefabInfo.NavMeshData != null)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(storedPrefabInfo.NavMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
}
|
||||
else if (surfaceInPrefab != null && storedPrefabInfo.Surface == surfaceInPrefab)
|
||||
{
|
||||
//Debug.LogFormat("The surface {0} from the prefab was storing the original navmesh data and now will be forgotten", surfaceInPrefab);
|
||||
|
||||
var baseSurface = PrefabUtility.GetCorrespondingObjectFromSource(surfaceInPrefab) as NavMeshSurface;
|
||||
if (baseSurface == null || surfaceInPrefab.navMeshData != baseSurface.navMeshData)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(surfaceInPrefab.navMeshData);
|
||||
AssetDatabase.DeleteAsset(assetPath);
|
||||
|
||||
//Debug.LogFormat("The surface {0} from the prefab has baked new NavMeshData but did not save this change so the asset has been now deleted. ({1})",
|
||||
// surfaceInPrefab, assetPath);
|
||||
}
|
||||
|
||||
m_PrefabNavMeshDataAssets.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
} while (++index < allSurfacesInPrefab.Length);
|
||||
|
||||
if (m_PrefabNavMeshDataAssets.Count == 0)
|
||||
{
|
||||
PrefabStage.prefabSaving -= DeleteStoredNavMeshDataAssetsForOwnedSurfaces;
|
||||
PrefabStage.prefabStageClosing -= ForgetUnsavedNavMeshDataChanges;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7081cfb45d93f064db511881f87cb0b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "NavMeshComponentsEditor",
|
||||
"references": [
|
||||
"NavMeshComponents"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c7deb0338552a549a4a74d064f07701
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,258 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace UnityEditor.AI
|
||||
{
|
||||
public static class NavMeshComponentsGUIUtility
|
||||
{
|
||||
public static void AreaPopup(string labelName, SerializedProperty areaProperty)
|
||||
{
|
||||
var areaIndex = -1;
|
||||
var areaNames = NavMesh.GetAreaNames();
|
||||
for (var i = 0; i < areaNames.Length; i++)
|
||||
{
|
||||
var areaValue = NavMesh.GetAreaFromName(areaNames[i]);
|
||||
if (areaValue == areaProperty.intValue)
|
||||
areaIndex = i;
|
||||
}
|
||||
ArrayUtility.Add(ref areaNames, "");
|
||||
ArrayUtility.Add(ref areaNames, "Open Area Settings...");
|
||||
|
||||
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
|
||||
EditorGUI.BeginProperty(rect, GUIContent.none, areaProperty);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
areaIndex = EditorGUI.Popup(rect, labelName, areaIndex, areaNames);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (areaIndex >= 0 && areaIndex < areaNames.Length - 2)
|
||||
areaProperty.intValue = NavMesh.GetAreaFromName(areaNames[areaIndex]);
|
||||
else if (areaIndex == areaNames.Length - 1)
|
||||
NavMeshEditorHelpers.OpenAreaSettings();
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public static void AgentTypePopup(string labelName, SerializedProperty agentTypeID)
|
||||
{
|
||||
var index = -1;
|
||||
var count = NavMesh.GetSettingsCount();
|
||||
var agentTypeNames = new string[count + 2];
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
|
||||
var name = NavMesh.GetSettingsNameFromID(id);
|
||||
agentTypeNames[i] = name;
|
||||
if (id == agentTypeID.intValue)
|
||||
index = i;
|
||||
}
|
||||
agentTypeNames[count] = "";
|
||||
agentTypeNames[count + 1] = "Open Agent Settings...";
|
||||
|
||||
bool validAgentType = index != -1;
|
||||
if (!validAgentType)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Agent Type invalid.", MessageType.Warning);
|
||||
}
|
||||
|
||||
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
|
||||
EditorGUI.BeginProperty(rect, GUIContent.none, agentTypeID);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
index = EditorGUI.Popup(rect, labelName, index, agentTypeNames);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (index >= 0 && index < count)
|
||||
{
|
||||
var id = NavMesh.GetSettingsByIndex(index).agentTypeID;
|
||||
agentTypeID.intValue = id;
|
||||
}
|
||||
else if (index == count + 1)
|
||||
{
|
||||
NavMeshEditorHelpers.OpenAgentSettings(-1);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
// Agent mask is a set (internally array/list) of agentTypeIDs.
|
||||
// It is used to describe which agents modifiers apply to.
|
||||
// There is a special case of "None" which is an empty array.
|
||||
// There is a special case of "All" which is an array of length 1, and value of -1.
|
||||
public static void AgentMaskPopup(string labelName, SerializedProperty agentMask)
|
||||
{
|
||||
// Contents of the dropdown box.
|
||||
string popupContent = "";
|
||||
|
||||
if (agentMask.hasMultipleDifferentValues)
|
||||
popupContent = "\u2014";
|
||||
else
|
||||
popupContent = GetAgentMaskLabelName(agentMask);
|
||||
|
||||
var content = new GUIContent(popupContent);
|
||||
var popupRect = GUILayoutUtility.GetRect(content, EditorStyles.popup);
|
||||
|
||||
EditorGUI.BeginProperty(popupRect, GUIContent.none, agentMask);
|
||||
popupRect = EditorGUI.PrefixLabel(popupRect, 0, new GUIContent(labelName));
|
||||
bool pressed = GUI.Button(popupRect, content, EditorStyles.popup);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
var show = !agentMask.hasMultipleDifferentValues;
|
||||
var showNone = show && agentMask.arraySize == 0;
|
||||
var showAll = show && IsAll(agentMask);
|
||||
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("None"), showNone, SetAgentMaskNone, agentMask);
|
||||
menu.AddItem(new GUIContent("All"), showAll, SetAgentMaskAll, agentMask);
|
||||
menu.AddSeparator("");
|
||||
|
||||
var count = NavMesh.GetSettingsCount();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var id = NavMesh.GetSettingsByIndex(i).agentTypeID;
|
||||
var sname = NavMesh.GetSettingsNameFromID(id);
|
||||
|
||||
var showSelected = show && AgentMaskHasSelectedAgentTypeID(agentMask, id);
|
||||
var userData = new object[] { agentMask, id, !showSelected };
|
||||
menu.AddItem(new GUIContent(sname), showSelected, ToggleAgentMaskItem, userData);
|
||||
}
|
||||
|
||||
menu.DropDown(popupRect);
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public static GameObject CreateAndSelectGameObject(string suggestedName, GameObject parent)
|
||||
{
|
||||
var parentTransform = parent != null ? parent.transform : null;
|
||||
var uniqueName = GameObjectUtility.GetUniqueNameForSibling(parentTransform, suggestedName);
|
||||
var child = new GameObject(uniqueName);
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(child, "Create " + uniqueName);
|
||||
if (parentTransform != null)
|
||||
Undo.SetTransformParent(child.transform, parentTransform, "Parent " + uniqueName);
|
||||
|
||||
Selection.activeGameObject = child;
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
static bool IsAll(SerializedProperty agentMask)
|
||||
{
|
||||
return agentMask.arraySize == 1 && agentMask.GetArrayElementAtIndex(0).intValue == -1;
|
||||
}
|
||||
|
||||
static void ToggleAgentMaskItem(object userData)
|
||||
{
|
||||
var args = (object[])userData;
|
||||
var agentMask = (SerializedProperty)args[0];
|
||||
var agentTypeID = (int)args[1];
|
||||
var value = (bool)args[2];
|
||||
|
||||
ToggleAgentMaskItem(agentMask, agentTypeID, value);
|
||||
}
|
||||
|
||||
static void ToggleAgentMaskItem(SerializedProperty agentMask, int agentTypeID, bool value)
|
||||
{
|
||||
if (agentMask.hasMultipleDifferentValues)
|
||||
{
|
||||
agentMask.ClearArray();
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
// Find which index this agent type is in the agentMask array.
|
||||
int idx = -1;
|
||||
for (var j = 0; j < agentMask.arraySize; j++)
|
||||
{
|
||||
var elem = agentMask.GetArrayElementAtIndex(j);
|
||||
if (elem.intValue == agentTypeID)
|
||||
idx = j;
|
||||
}
|
||||
|
||||
// Handle "All" special case.
|
||||
if (IsAll(agentMask))
|
||||
{
|
||||
agentMask.DeleteArrayElementAtIndex(0);
|
||||
}
|
||||
|
||||
// Toggle value.
|
||||
if (value)
|
||||
{
|
||||
if (idx == -1)
|
||||
{
|
||||
agentMask.InsertArrayElementAtIndex(agentMask.arraySize);
|
||||
agentMask.GetArrayElementAtIndex(agentMask.arraySize - 1).intValue = agentTypeID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (idx != -1)
|
||||
{
|
||||
agentMask.DeleteArrayElementAtIndex(idx);
|
||||
}
|
||||
}
|
||||
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static void SetAgentMaskNone(object data)
|
||||
{
|
||||
var agentMask = (SerializedProperty)data;
|
||||
agentMask.ClearArray();
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static void SetAgentMaskAll(object data)
|
||||
{
|
||||
var agentMask = (SerializedProperty)data;
|
||||
agentMask.ClearArray();
|
||||
agentMask.InsertArrayElementAtIndex(0);
|
||||
agentMask.GetArrayElementAtIndex(0).intValue = -1;
|
||||
agentMask.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
static string GetAgentMaskLabelName(SerializedProperty agentMask)
|
||||
{
|
||||
if (agentMask.arraySize == 0)
|
||||
return "None";
|
||||
|
||||
if (IsAll(agentMask))
|
||||
return "All";
|
||||
|
||||
if (agentMask.arraySize <= 3)
|
||||
{
|
||||
var labelName = "";
|
||||
for (var j = 0; j < agentMask.arraySize; j++)
|
||||
{
|
||||
var elem = agentMask.GetArrayElementAtIndex(j);
|
||||
var settingsName = NavMesh.GetSettingsNameFromID(elem.intValue);
|
||||
if (string.IsNullOrEmpty(settingsName))
|
||||
continue;
|
||||
|
||||
if (labelName.Length > 0)
|
||||
labelName += ", ";
|
||||
labelName += settingsName;
|
||||
}
|
||||
return labelName;
|
||||
}
|
||||
|
||||
return "Mixed...";
|
||||
}
|
||||
|
||||
static bool AgentMaskHasSelectedAgentTypeID(SerializedProperty agentMask, int agentTypeID)
|
||||
{
|
||||
for (var j = 0; j < agentMask.arraySize; j++)
|
||||
{
|
||||
var elem = agentMask.GetArrayElementAtIndex(j);
|
||||
if (elem.intValue == agentTypeID)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd87d77a7e9dee24bbb6eaf7b8ac12da
|
||||
timeCreated: 1480524815
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user