diff --git a/Source/Editor/CustomEditors/Dedicated/NavAgentMaskEditor.cs b/Source/Editor/CustomEditors/Dedicated/NavAgentMaskEditor.cs
new file mode 100644
index 000000000..ab0151bb9
--- /dev/null
+++ b/Source/Editor/CustomEditors/Dedicated/NavAgentMaskEditor.cs
@@ -0,0 +1,92 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using System.Linq;
+using FlaxEditor.Content.Settings;
+using FlaxEngine;
+using FlaxEngine.GUI;
+
+namespace FlaxEditor.CustomEditors.Dedicated
+{
+ ///
+ /// Custom editor for .
+ ///
+ ///
+ [CustomEditor(typeof(NavAgentMask)), DefaultEditor]
+ internal class NavAgentMaskEditor : CustomEditor
+ {
+ private CheckBox[] _checkBoxes;
+
+ ///
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ var settings = GameSettings.Load();
+ if (settings.NavMeshes == null || settings.NavMeshes.Length == 0)
+ {
+ layout.Label("Missing navmesh settings");
+ return;
+ }
+
+ _checkBoxes = new CheckBox[settings.NavMeshes.Length];
+ for (int i = 0; i < settings.NavMeshes.Length; i++)
+ {
+ ref var navmesh = ref settings.NavMeshes[i];
+ var property = layout.AddPropertyItem(navmesh.Name, navmesh.Agent.ToString());
+ property.Labels.Last().TextColorHighlighted = navmesh.Color;
+ var checkbox = property.Checkbox().CheckBox;
+ UpdateCheckbox(checkbox, i);
+ checkbox.Tag = i;
+ checkbox.StateChanged += OnCheckboxStateChanged;
+ _checkBoxes[i] = checkbox;
+ }
+ }
+
+ ///
+ protected override void Deinitialize()
+ {
+ _checkBoxes = null;
+
+ base.Deinitialize();
+ }
+
+ ///
+ public override void Refresh()
+ {
+ if (_checkBoxes != null)
+ {
+ for (int i = 0; i < _checkBoxes.Length; i++)
+ {
+ UpdateCheckbox(_checkBoxes[i], i);
+ }
+ }
+
+ base.Refresh();
+ }
+
+ private void OnCheckboxStateChanged(CheckBox checkBox)
+ {
+ var i = (int)checkBox.Tag;
+ var value = (NavAgentMask)Values[0];
+ var mask = 1u << i;
+ value.Mask &= ~mask;
+ value.Mask |= checkBox.Checked ? mask : 0;
+ SetValue(value);
+ }
+
+ private void UpdateCheckbox(CheckBox checkbox, int i)
+ {
+ for (var j = 0; j < Values.Count; j++)
+ {
+ var value = (((NavAgentMask)Values[j]).Mask & (1 << i)) != 0;
+ if (j == 0)
+ {
+ checkbox.Checked = value;
+ }
+ else if (checkbox.State != CheckBoxState.Intermediate)
+ {
+ if (checkbox.Checked != value)
+ checkbox.State = CheckBoxState.Intermediate;
+ }
+ }
+ }
+ }
+}
diff --git a/Source/Engine/Navigation/Navigation.cpp b/Source/Engine/Navigation/Navigation.cpp
index 29b081150..5e73f40c7 100644
--- a/Source/Engine/Navigation/Navigation.cpp
+++ b/Source/Engine/Navigation/Navigation.cpp
@@ -97,6 +97,42 @@ bool NavAgentProperties::operator==(const NavAgentProperties& other) const
return Math::NearEqual(Radius, other.Radius) && Math::NearEqual(Height, other.Height) && Math::NearEqual(StepHeight, other.StepHeight) && Math::NearEqual(MaxSlopeAngle, other.MaxSlopeAngle);
}
+bool NavAgentMask::IsAgentSupported(int32 agentIndex) const
+{
+ return (Mask & (1 << agentIndex)) != 0;
+}
+
+bool NavAgentMask::IsAgentSupported(const NavAgentProperties& agentProperties) const
+{
+ auto settings = NavigationSettings::Get();
+ for (int32 agentIndex = 0; agentIndex < settings->NavMeshes.Count(); agentIndex++)
+ {
+ if (settings->NavMeshes[agentIndex].Agent == agentProperties)
+ {
+ return (Mask & (1 << agentIndex)) != 0;
+ }
+ }
+ return false;
+}
+
+bool NavAgentMask::IsNavMeshSupported(const NavMeshProperties& navMeshProperties) const
+{
+ auto settings = NavigationSettings::Get();
+ for (int32 agentIndex = 0; agentIndex < settings->NavMeshes.Count(); agentIndex++)
+ {
+ if (settings->NavMeshes[agentIndex] == navMeshProperties)
+ {
+ return (Mask & (1 << agentIndex)) != 0;
+ }
+ }
+ return false;
+}
+
+bool NavAgentMask::operator==(const NavAgentMask& other) const
+{
+ return Mask == other.Mask;
+}
+
bool NavMeshProperties::operator==(const NavMeshProperties& other) const
{
return Name == other.Name && Quaternion::NearEqual(Rotation, other.Rotation, 0.001f) && Agent == other.Agent;
diff --git a/Source/Engine/Navigation/NavigationSettings.cs b/Source/Engine/Navigation/NavigationSettings.cs
index da300b3f1..4127ebe6b 100644
--- a/Source/Engine/Navigation/NavigationSettings.cs
+++ b/Source/Engine/Navigation/NavigationSettings.cs
@@ -72,3 +72,15 @@ namespace FlaxEditor.Content.Settings
}
}
}
+
+namespace FlaxEngine
+{
+ partial struct NavAgentProperties
+ {
+ ///
+ public override string ToString()
+ {
+ return $"Radius: {Radius}, Height: {Height}, StepHeight: {StepHeight}, MaxSlopeAngle: {MaxSlopeAngle}";
+ }
+ }
+}
diff --git a/Source/Engine/Navigation/NavigationTypes.h b/Source/Engine/Navigation/NavigationTypes.h
index f00c1683e..d02b2acc4 100644
--- a/Source/Engine/Navigation/NavigationTypes.h
+++ b/Source/Engine/Navigation/NavigationTypes.h
@@ -91,6 +91,30 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(NavMeshProperties);
}
};
+///
+/// The navigation system agents selection mask (from navigation system settings). Uses 1 bit per agent type (up to 32 agents).
+///
+API_STRUCT() struct FLAXENGINE_API NavAgentMask
+{
+DECLARE_SCRIPTING_TYPE_MINIMAL(NavAgentMask);
+
+ ///
+ /// The agents selection mask.
+ ///
+ API_FIELD() uint32 Mask = MAX_uint32;
+
+ bool IsAgentSupported(int32 agentIndex) const;
+ bool IsAgentSupported(const NavAgentProperties& agentProperties) const;
+ bool IsNavMeshSupported(const NavMeshProperties& navMeshProperties) const;
+
+ bool operator==(const NavAgentMask& other) const;
+
+ bool operator!=(const NavAgentMask& other) const
+ {
+ return !operator==(other);
+ }
+};
+
///
/// The result information for navigation mesh queries.
///
diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs
index 231831442..535499442 100644
--- a/Source/Engine/Serialization/JsonSerializer.cs
+++ b/Source/Engine/Serialization/JsonSerializer.cs
@@ -120,6 +120,7 @@ namespace FlaxEngine.Json
}
}
*/
+
///
/// Objects serialization tool (json format).
///