using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HPJ.Simulation.Map;
using System.Threading;
using System.Threading.Tasks;
using HPJ.Simulation.Pathing;
using HPJ.Simulation.Enums;
using UnityEditor;
using System;
using HPJ.Simulation;
using System.IO;
//using Unity.Plastic.Newtonsoft.Json;
using UnityEngine.SceneManagement;
using HPJ.Presentation.Obstacle;
using HPJ.Presentation.Agents;
using HPJ.Presentation.NavigationManagerSettings;
using Newtonsoft.Json;
#if UNITY_EDITOR
using Unity.EditorCoroutines.Editor;
#endif
namespace HPJ.Presentation
{
///
/// The Manager used to manage the Map sets, Obstacles as Gameobjects, Navigation Agents as Gameobjects
///
public class NavigationManager : MonoBehaviour
{
#region Maps
[SerializeField]
protected List _mapSets = new List();
///
/// A List of the maps
///
public List MapSets { get { if (ApplicationPlaying) { return _activeSets; } return _mapSets; } }
[NonSerialized]
protected List _activeSets;
protected bool ApplicationPlaying { get; set; }
///
/// A List of all the bridges
///
[SerializeField]
protected List _bridges = new List();
public List Bridges { get { return _bridges; } }
///
/// A List of all the bridges
///
[SerializeField]
protected List _seams = new List();
public List Seams { get { return _seams; } }
///
/// The Navigation Manager Settings
///
public ManagerSetting ManagerSettings = new ManagerSetting();
///
/// Seam settings for the Navigation Manager
///
public SeamSettings MapSeamSettings = new SeamSettings();
///
/// Used to send a Navigation Job Request to the simulation
///
///
public void SetDestination(NavigationJob Job)
{
for (int i = 0; i < MapSets.Count; i++)
{
MapSet Set = MapSets[i];
if (Set.JobCompatible(Job))
{
Set.SetDestination(Job);
return;
}
}
if (Job.CurrentPath != null)
{
Job.CurrentPath.PreviousStatus = "Was not in bounds of a Map";
Job.CurrentPath.ValidPath = false;
Job.CurrentStep = PathfindingCalculationStep.Complete;
}
}
///
/// Adds a navigation order for the Navigation Agents
///
///
internal void AddNavigationOrder(NavigationOrder newOrder)
{
newOrder.StartingMap.SetDestination(newOrder.NavJob);
}
///
/// Initilaizes all the map bridges
///
public void SetMapBridges()
{
for (int i = 0; i < MapSets.Count; i++)
{
MapSet Map = MapSets[i];
Map.ClearMaps();
foreach (MapBridge Bridge in Bridges)
{
if (Bridge.Contains(Map))
{
Bridge.RefreshWithNew(Map);
Map.AddBridge(Bridge);
}
}
foreach (MapSeam Seam in Seams)
{
if (Seam.Contains(Map))
{
Seam.RefreshWithNew(Map);
Map.AddSeam(Seam);
}
}
}
}
///
/// Gets a desired bridge or seam for a position
///
///
///
///
///
///
///
public bool GetDesiredBridgeOrSeam(IntVector3 start, MapSet startingMap, MapSet endingMap, out MapBridge ClosestBridge, out MapSeam ClosestSeam, out int BridgeScore, out int SeamScore)
{
ClosestBridge = null;
ClosestSeam = null;
BridgeScore = int.MaxValue;
SeamScore = int.MaxValue;
// Make sure that these maps HAVE a way out of them
if ((endingMap.MapBridges.Count == 0 && endingMap.MapSeams.Count == 0) || (startingMap.MapBridges.Count == 0 && startingMap.MapSeams.Count == 0))
{
Debug.Log($"No Seam or Bridge for Starting or Ending Map {startingMap.SetSettings.Name}-> S#{startingMap.MapSeams.Count} - B#{startingMap.MapBridges.Count} / {endingMap.SetSettings.Name}-> S#{endingMap.MapSeams.Count} - B#{endingMap.MapBridges.Count}");
return false;
}
int ClosestScore = int.MaxValue;
// Check for direct bridges first
for (int i = 0; i < Bridges.Count; i++)
{
MapBridge Bridge = Bridges[i];
if (!Bridge.ValidBridge)
{
continue;
}
if (Bridge.CanWalkInDirection(startingMap, endingMap))
{
IntVector3 BridgePoint = Bridge.GetPoint(startingMap);
int Distance = IntVector3.DistanceSquared(BridgePoint, start);
if (Distance < ClosestScore)
{
ClosestBridge = Bridge;
ClosestScore = Distance;
}
}
}
ClosestScore = int.MaxValue;
// Check for direct bridges first
for (int i = 0; i < Seams.Count; i++)
{
MapSeam Seam = Seams[i];
if (!Seam.ValidSeam)
{
continue;
}
if (Seam.DirectConnects(startingMap, endingMap))
{
IntVector3 SeamPoint = Seam.GetPoint(startingMap, start);
int Distance = IntVector3.DistanceSquared(SeamPoint, start);
if (Distance < ClosestScore)
{
ClosestSeam = Seam;
ClosestScore = Distance;
}
}
}
// Ok adjacent map does not directly lead to the end map, so lets do node based pathfinding to try and get there
if (ClosestBridge == null && ClosestSeam == null)
{
ClosestBridge = AStarBridgeNode(startingMap, endingMap, start);
ClosestSeam = AStarSeamNode(startingMap, endingMap, start);
}
if (ClosestBridge != null)
{
IntVector3 BridgePoint = ClosestBridge.GetPoint(startingMap);
BridgeScore = IntVector3.DistanceSquared(BridgePoint, start);
}
if (ClosestSeam != null)
{
IntVector3 SeamPoint = ClosestSeam.GetPoint(startingMap, start);
SeamScore = IntVector3.DistanceSquared(SeamPoint, start);
}
return ClosestBridge != null || ClosestSeam != null;
}
///
/// Gets a desired bridge for a position
///
///
///
///
///
public MapBridge GetDesiredBridge(IntVector3 start, MapSet startingMap, MapSet endingMap)
{
if (endingMap.MapBridges.Count == 0 || startingMap.MapBridges.Count == 0)
{
return null;
}
MapBridge ClosestBridge = null;
int ClosestScore = int.MaxValue;
// Check for direct bridges first
foreach (MapBridge Bridge in Bridges)
{
if (!Bridge.ValidBridge)
{
continue;
}
if (Bridge.CanWalkInDirection(startingMap, endingMap))
{
IntVector3 BridgePoint = Bridge.GetPoint(startingMap);
int Distance = IntVector3.DistanceSquared(BridgePoint, start);
if (Distance < ClosestScore)
{
ClosestBridge = Bridge;
ClosestScore = Distance;
}
}
}
// Ok adjacent map does not directly lead to the end map, so lets do node based pathfinding to try and get there
if (ClosestBridge == null)
{
ClosestBridge = AStarBridgeNode(startingMap, endingMap, start);
//ClosestScore = int.MaxValue;
//List ClosedMaps = new List();
//foreach (MapBridge Bridge in startingMap.MapBridges)
//{
// if (!Bridge.ValidBridge)
// {
// continue;
// }
// IntVector3 BridgePoint = Bridge.GetPoint(startingMap);
// int Distance = IntVector3.DistanceSquared(BridgePoint, start);
// ClosedMaps.Add(startingMap);
// if (BridgeEventuallyLeadsToMap(Bridge, startingMap, endingMap, ClosedMaps))
// {
// if (Distance < ClosestScore)
// {
// ClosestBridge = Bridge;
// }
// }
// ClosedMaps.Clear();
//}
}
return ClosestBridge;
}
///
/// Gets a desired seam for a position
///
///
///
///
///
public MapSeam GetDesiredSeam(IntVector3 start, MapSet startingMap, MapSet endingMap)
{
if (endingMap.MapBridges.Count == 0 || startingMap.MapBridges.Count == 0)
{
return null;
}
MapSeam ClosestSeam = null;
int ClosestScore = int.MaxValue;
// Check for direct bridges first
foreach (MapSeam Seam in Seams)
{
if (!Seam.ValidSeam)
{
continue;
}
if (Seam.DirectConnects(startingMap, endingMap))
{
IntVector3 BridgePoint = Seam.GetPoint(startingMap, start);
int Distance = IntVector3.DistanceSquared(BridgePoint, start);
if (Distance < ClosestScore)
{
ClosestSeam = Seam;
ClosestScore = Distance;
}
}
}
// Ok adjacent map does not directly lead to the end map, so lets do node based pathfinding to try and get there
if (ClosestSeam == null)
{
ClosestSeam = AStarSeamNode(startingMap, endingMap, start);
//ClosestScore = int.MaxValue;
//List ClosedMaps = new List();
//foreach (MapBridge Bridge in startingMap.MapBridges)
//{
// if (!Bridge.ValidBridge)
// {
// continue;
// }
// IntVector3 BridgePoint = Bridge.GetPoint(startingMap);
// int Distance = IntVector3.DistanceSquared(BridgePoint, start);
// ClosedMaps.Add(startingMap);
// if (BridgeEventuallyLeadsToMap(Bridge, startingMap, endingMap, ClosedMaps))
// {
// if (Distance < ClosestScore)
// {
// ClosestBridge = Bridge;
// }
// }
// ClosedMaps.Clear();
//}
}
return ClosestSeam;
}
#region Bridge AStar Region
#region Map Bridges
///
/// Used A* Node Pathfinding to find a set of bridge to a ending map
///
///
///
///
///
public MapBridge AStarBridgeNode(MapSet StartMap, MapSet EndMap, IntVector3 Start)
{
List OpenList = new List();
List ClosedList = new List();
Dictionary SortedList = new Dictionary();
OpenList.Add(StartMap.InstanceID);
AStarBridgeData StartingTileData = new AStarBridgeData(-1, StartMap.InstanceID, GetMapDistance(StartMap, EndMap));
StartingTileData.GCost = 0;
StartingTileData.FCost = StartingTileData.GCost + StartingTileData.HCost;
SortedList.Add(StartMap.InstanceID, StartingTileData);
MapSet CurrentTile = StartMap;
int Iterations = 0;
bool MaxIterationsMade = false;
int MaxIterations = 3000;
while (OpenList.Count > 0)
{
// Give a safty range of 2 times the range in terms of iterations, if it cannot find a path by then, it's failed. can probably cannot be reached
if (Iterations > MaxIterations)
{
MaxIterationsMade = true;
break;
}
Iterations++;
int CurrentNodeIndex = GetLowestFCostMapInstanceID(OpenList, EndMap);
// Remove current
CurrentTile = MapSets[OpenList[CurrentNodeIndex]];
OpenList.RemoveAt(CurrentNodeIndex);
AStarBridgeData CurrentData = SortedList[CurrentTile.InstanceID];
CurrentTile = MapSets[CurrentData.ID];
ClosedList.Add(CurrentTile.InstanceID);
if (EndMap.InstanceID == CurrentTile.InstanceID)
{
// Reached the end
//Debug.Log("Found the End - Should be Path Complete");
break;
}
for (int j= 0; j < CurrentTile.MapBridges.Count; j++)
{
MapBridge Bridge = CurrentTile.MapBridges[j];
MapSet OtherMap = Bridge.Other(CurrentTile);
//Debug.Log($"Other Map {OtherMap.SetSettings.Name} ({OtherMap.InstanceID}) -> Bridges {OtherMap.MapBridges.Count}");
//if (OtherMap.InstanceID == EndMap.InstanceID)
//{
// Debug.Log("Found Last Map");
//}
if (OtherMap == null)
{
continue;
}
if (!Bridge.CanWalkInDirection(CurrentTile, OtherMap))
{
continue;
}
AStarBridgeData NeighbourData;
if (!SortedList.ContainsKey(OtherMap.InstanceID))
{
NeighbourData = new AStarBridgeData(CurrentData.ID, OtherMap.InstanceID, GetMapDistance(OtherMap, EndMap));
SortedList.Add(OtherMap.InstanceID, NeighbourData);
if (!ClosedList.Contains(OtherMap.InstanceID))
{
//Debug.Log($"Add Map {OtherMap.SetSettings.Name} for ({StartMap.SetSettings.Name} -> {EndMap.SetSettings.Name})");
OpenList.Add(OtherMap.InstanceID);
}
}
else
{
NeighbourData = SortedList[OtherMap.InstanceID];
}
int TentativeGCost = CurrentData.GCost + GetMapDistance(CurrentTile, OtherMap);
if (TentativeGCost < NeighbourData.GCost)
{
NeighbourData.FromMapInstanceID = CurrentData.ID;
NeighbourData.GCost = TentativeGCost;
NeighbourData.FCost = NeighbourData.GCost + NeighbourData.HCost;
SortedList[OtherMap.InstanceID] = NeighbourData;
}
}
for (int j = 0; j < CurrentTile.MapSeams.Count; j++)
{
MapSeam Seam = CurrentTile.MapSeams[j];
MapSet OtherMap = Seam.Other(CurrentTile);
//Debug.Log($"Other Map {OtherMap.SetSettings.Name} ({OtherMap.InstanceID}) -> Bridges {OtherMap.MapBridges.Count}");
//if (OtherMap.InstanceID == EndMap.InstanceID)
//{
// Debug.Log("Found Last Map");
//}
if (OtherMap == null)
{
continue;
}
AStarBridgeData NeighbourData;
if (!SortedList.ContainsKey(OtherMap.InstanceID))
{
NeighbourData = new AStarBridgeData(CurrentData.ID, OtherMap.InstanceID, GetMapDistance(OtherMap, EndMap));
SortedList.Add(OtherMap.InstanceID, NeighbourData);
if (!ClosedList.Contains(OtherMap.InstanceID))
{
//Debug.Log($"Add Map {OtherMap.SetSettings.Name} for ({StartMap.SetSettings.Name} -> {EndMap.SetSettings.Name})");
OpenList.Add(OtherMap.InstanceID);
}
}
else
{
NeighbourData = SortedList[OtherMap.InstanceID];
}
int TentativeGCost = CurrentData.GCost + GetMapDistance(CurrentTile, OtherMap);
if (TentativeGCost < NeighbourData.GCost)
{
NeighbourData.FromMapInstanceID = CurrentData.ID;
NeighbourData.GCost = TentativeGCost;
NeighbourData.FCost = NeighbourData.GCost + NeighbourData.HCost;
SortedList[OtherMap.InstanceID] = NeighbourData;
}
}
}
AStarBridgeData EndTileData;
if (MaxIterationsMade)
{
Debug.Log("Max Iterations Made");
return null;
}
else if (!SortedList.TryGetValue(EndMap.InstanceID, out EndTileData))
{
// No Valid Path Found
Debug.Log($"No Valid Path Found in sorted list ({ClosedList.Count} / {OpenList.Count} / {SortedList.Count})");
return null;
}
else if (EndTileData.FromMapInstanceID == -1)
{
// No Valid Path Found
Debug.Log("End does not have a from ID");
return null;
}
else
{
int NextMapIndex = GetNextMap(SortedList, EndMap, StartMap);
if (NextMapIndex != -1)
{
MapSet NextMap = MapSets[NextMapIndex];
MapBridge ClosestMap = StartMap.GetClosestBridge(NextMap, Start);
return ClosestMap;
}
Debug.Log("This should not hit");
}
return null;
}
private int GetNextMap(Dictionary sortedList, MapSet EndMap, MapSet StartMap)
{
AStarBridgeData CurrentTile = sortedList[EndMap.InstanceID];
// The Route From Index of the starting tile should be the only one with a (-1, -1) index
while (CurrentTile.FromMapInstanceID != -1)
{
if (CurrentTile.FromMapInstanceID == StartMap.InstanceID)
{
return CurrentTile.ID;
}
CurrentTile = sortedList[CurrentTile.FromMapInstanceID];
}
return -1;
}
private int GetLowestFCostMapInstanceID(List openList, MapSet endMap)
{
int LowestCostIndex = 0;
// Typical AStar pathfinding
int CurrentLowestCost = GetMapDistance(MapSets[openList[0]], endMap);
for (int i = 1; i < openList.Count; i++)
{
int testCost = GetMapDistance(MapSets[openList[i]], endMap);
if (testCost < CurrentLowestCost)
{
CurrentLowestCost = testCost;
LowestCostIndex = i;
}
}
return LowestCostIndex;
}
private int GetMapDistance(MapSet Map1, MapSet Map2)
{
if (Map1.InstanceID == Map2.InstanceID)
{
return 0;
}
int LowestDistance = int.MaxValue;
for (int i = 0; i < Map1.KeyBorderPositions.Count; i++)
{
IntVector3 KeyPosition = Map1.KeyBorderPositions[i];
for (int j = 0; j < Map2.KeyBorderPositions.Count; j++)
{
IntVector3 OtherMapKeyPosition = Map2.KeyBorderPositions[j];
int NewScore = IntVector3.Displacement(KeyPosition, OtherMapKeyPosition);
if (NewScore < LowestDistance)
{
LowestDistance = NewScore;
}
}
}
return LowestDistance;
}
private struct AStarBridgeData
{
public int ID;
public int FromMapInstanceID;
public int FCost;
public int GCost;
public int HCost;
public AStarBridgeData(int MapInstanceID, int ThisID, int EndCost)
{
ID = ThisID;
FromMapInstanceID = MapInstanceID;
FCost = int.MaxValue;
GCost = int.MaxValue;
HCost = EndCost;
}
}
public bool BridgeEventuallyLeadsToMap(MapBridge Bridge, MapSet CurrentMap, MapSet EndingMap, List ClosedList)
{
MapSet OtherMap = Bridge.Other(CurrentMap);
if (OtherMap == null)
{
return false;
}
if (OtherMap == EndingMap)
{
return true;
}
if (ClosedList.Contains(OtherMap))
{
return false;
}
ClosedList.Add(OtherMap);
for (int i = 0; i < OtherMap.MapBridges.Count; i++)
{
MapBridge OtherBridge = OtherMap.MapBridges[i];
MapSet NextOtherMap = OtherBridge.Other(OtherMap);
if (NextOtherMap == EndingMap)
{
return true;
}
if (NextOtherMap == null)
{
continue;
}
if (ClosedList.Contains(NextOtherMap))
{
continue;
}
if (BridgeEventuallyLeadsToMap(OtherBridge, OtherMap, EndingMap, ClosedList))
{
return true;
}
}
for (int i = 0; i < OtherMap.MapSeams.Count; i++)
{
MapSeam OtherSeam = OtherMap.MapSeams[i];
MapSet NextOtherMap = OtherSeam.Other(OtherMap);
if (NextOtherMap == EndingMap)
{
return true;
}
if (NextOtherMap == null)
{
continue;
}
if (ClosedList.Contains(NextOtherMap))
{
continue;
}
if (SeamEventuallyLeadsToMap(OtherSeam, OtherMap, EndingMap, ClosedList))
{
return true;
}
}
return false;
}
#endregion
#region Map Seams
///
/// Used A* Node Pathfinding to find a set of seams to a ending map
///
///
///
///
///
public MapSeam AStarSeamNode(MapSet StartMap, MapSet EndMap, IntVector3 Start)
{
List OpenList = new List();
List ClosedList = new List();
Dictionary SortedList = new Dictionary();
OpenList.Add(StartMap.InstanceID);
AStarBridgeData StartingTileData = new AStarBridgeData(-1, StartMap.InstanceID, GetMapDistance(StartMap, EndMap));
StartingTileData.GCost = 0;
StartingTileData.FCost = StartingTileData.GCost + StartingTileData.HCost;
SortedList.Add(StartMap.InstanceID, StartingTileData);
MapSet CurrentTile = StartMap;
int Iterations = 0;
bool MaxIterationsMade = false;
int MaxIterations = 3000;
while (OpenList.Count > 0)
{
// Give a safty range of 2 times the range in terms of iterations, if it cannot find a path by then, it's failed. can probably cannot be reached
if (Iterations > MaxIterations)
{
MaxIterationsMade = true;
break;
}
Iterations++;
int CurrentNodeIndex = GetLowestFCostMapInstanceID(OpenList, EndMap);
// Remove current
CurrentTile = MapSets[OpenList[CurrentNodeIndex]];
OpenList.RemoveAt(CurrentNodeIndex);
AStarBridgeData CurrentData = SortedList[CurrentTile.InstanceID];
CurrentTile = MapSets[CurrentData.ID];
ClosedList.Add(CurrentTile.InstanceID);
if (EndMap.InstanceID == CurrentTile.InstanceID)
{
// Reached the end
//Debug.Log("Found the End - Should be Path Complete");
break;
}
foreach (MapBridge Bridge in CurrentTile.MapBridges)
{
MapSet OtherMap = Bridge.Other(CurrentTile);
//Debug.Log($"Other Map {OtherMap.SetSettings.Name} ({OtherMap.InstanceID}) -> Bridges {OtherMap.MapBridges.Count}");
//if (OtherMap.InstanceID == EndMap.InstanceID)
//{
// Debug.Log("Found Last Map");
//}
if (OtherMap == null)
{
continue;
}
AStarBridgeData NeighbourData;
if (!SortedList.ContainsKey(OtherMap.InstanceID))
{
NeighbourData = new AStarBridgeData(CurrentData.ID, OtherMap.InstanceID, GetMapDistance(OtherMap, EndMap));
SortedList.Add(OtherMap.InstanceID, NeighbourData);
if (!ClosedList.Contains(OtherMap.InstanceID))
{
//Debug.Log($"Add Map {OtherMap.SetSettings.Name} for ({StartMap.SetSettings.Name} -> {EndMap.SetSettings.Name})");
OpenList.Add(OtherMap.InstanceID);
}
}
else
{
NeighbourData = SortedList[OtherMap.InstanceID];
}
int TentativeGCost = CurrentData.GCost + GetMapDistance(CurrentTile, OtherMap);
if (TentativeGCost < NeighbourData.GCost)
{
NeighbourData.FromMapInstanceID = CurrentData.ID;
NeighbourData.GCost = TentativeGCost;
NeighbourData.FCost = NeighbourData.GCost + NeighbourData.HCost;
SortedList[OtherMap.InstanceID] = NeighbourData;
}
}
foreach (MapSeam Seam in CurrentTile.MapSeams)
{
MapSet OtherMap = Seam.Other(CurrentTile);
//Debug.Log($"Other Map {OtherMap.SetSettings.Name} ({OtherMap.InstanceID}) -> Bridges {OtherMap.MapBridges.Count}");
//if (OtherMap.InstanceID == EndMap.InstanceID)
//{
// Debug.Log("Found Last Map");
//}
if (OtherMap == null)
{
continue;
}
AStarBridgeData NeighbourData;
if (!SortedList.ContainsKey(OtherMap.InstanceID))
{
NeighbourData = new AStarBridgeData(CurrentData.ID, OtherMap.InstanceID, GetMapDistance(OtherMap, EndMap));
SortedList.Add(OtherMap.InstanceID, NeighbourData);
if (!ClosedList.Contains(OtherMap.InstanceID))
{
//Debug.Log($"Add Map {OtherMap.SetSettings.Name} for ({StartMap.SetSettings.Name} -> {EndMap.SetSettings.Name})");
OpenList.Add(OtherMap.InstanceID);
}
}
else
{
NeighbourData = SortedList[OtherMap.InstanceID];
}
int TentativeGCost = CurrentData.GCost + GetMapDistance(CurrentTile, OtherMap);
if (TentativeGCost < NeighbourData.GCost)
{
NeighbourData.FromMapInstanceID = CurrentData.ID;
NeighbourData.GCost = TentativeGCost;
NeighbourData.FCost = NeighbourData.GCost + NeighbourData.HCost;
SortedList[OtherMap.InstanceID] = NeighbourData;
}
}
}
AStarBridgeData EndTileData;
if (MaxIterationsMade)
{
Debug.Log("Max Iterations Made");
return null;
}
else if (!SortedList.TryGetValue(EndMap.InstanceID, out EndTileData))
{
// No Valid Path Found
Debug.Log($"No Valid Path Found in sorted list ({ClosedList.Count} / {OpenList.Count} / {SortedList.Count})");
return null;
}
else if (EndTileData.FromMapInstanceID == -1)
{
// No Valid Path Found
Debug.Log("End does not have a from ID");
return null;
}
else
{
int NextMapIndex = GetNextMap(SortedList, EndMap, StartMap);
if (NextMapIndex != -1)
{
MapSet NextMap = MapSets[NextMapIndex];
MapSeam ClosestMap = StartMap.GetClosestSeam(NextMap, Start);
return ClosestMap;
}
Debug.Log("This should not hit");
}
return null;
}
public bool SeamEventuallyLeadsToMap(MapSeam Seam, MapSet CurrentMap, MapSet EndingMap, List ClosedList)
{
MapSet OtherMap = Seam.Other(CurrentMap);
if (OtherMap == null)
{
return false;
}
if (OtherMap == EndingMap)
{
return true;
}
if (ClosedList.Contains(OtherMap))
{
return false;
}
ClosedList.Add(OtherMap);
foreach (MapSeam OtherSeam in OtherMap.MapSeams)
{
MapSet NextOtherMap = OtherSeam.Other(OtherMap);
if (NextOtherMap == EndingMap)
{
return true;
}
if (NextOtherMap == null)
{
continue;
}
if (ClosedList.Contains(NextOtherMap))
{
continue;
}
if (SeamEventuallyLeadsToMap(OtherSeam, OtherMap, EndingMap, ClosedList))
{
return true;
}
}
foreach (MapBridge OtherBridge in OtherMap.MapBridges)
{
MapSet NextOtherMap = OtherBridge.Other(OtherMap);
if (NextOtherMap == EndingMap)
{
return true;
}
if (NextOtherMap == null)
{
continue;
}
if (ClosedList.Contains(NextOtherMap))
{
continue;
}
if (BridgeEventuallyLeadsToMap(OtherBridge, OtherMap, EndingMap, ClosedList))
{
return true;
}
}
return false;
}
#endregion
#endregion
///
/// Checks whether a specific bridge is valid
///
///
///
public bool ValidBridge(MapBridge Bridge)
{
if (Bridge == null || Bridge.MidPoints == null)
{
return false;
}
if (Bridge.MidPoints.Count <= 0)
{
return false;
}
Bridge.MapB = GetMapAtTileWorldPosition(Bridge.MidPoints[Bridge.MidPoints.Count - 1]);
Bridge.MapA = GetMapAtTileWorldPosition(Bridge.MidPoints[0]);
if (Bridge.MapB == Bridge.MapA)
{
return false;
}
if (Bridge.MapB == null || Bridge.MapA == null)
{
return false;
}
return true;
}
private void ValidateBridge(MapBridge bridge)
{
bridge.MapB = GetMapAtTileWorldPosition(bridge.MidPoints[bridge.MidPoints.Count - 1]);
bridge.MapA = GetMapAtTileWorldPosition(bridge.MidPoints[0]);
}
#endregion
#region Threads
///
/// Map Simulatin Threads
///
public Thread[] Threads;
///
/// Whether the map simulation threads are running
///
public bool Running { get; protected set; }
///
/// Extra Simulation Thrad
///
public Thread ExtraSimulatinThread;
///
/// Whether the map simulation helper thread is running
///
public bool HelperRunning { get; protected set; }
///
/// The options for parrellism in the map simulation threads
///
protected ParallelOptions _parallelOptions;
///
/// Log list for callback from the map simulation Threads
///
public List Logs { get; protected set; }
public List Warnings { get; protected set; }
public List Errors { get; protected set; }
///
/// Logs all the callbacks from the simulation
///
///
///
public void AddDebugLog(string Log, SimulationDebugLog LogType)
{
if (LogType == SimulationDebugLog.Error)
{
lock (Errors)
{
Errors.Add(Log);
}
}
else if (LogType == SimulationDebugLog.Warning)
{
lock (Warnings)
{
Warnings.Add(Log);
}
}
else
{
lock (Logs)
{
Logs.Add(Log);
}
}
}
#endregion
#region Painter
///
/// Painting Settings
///
public PainterSetting Painter = new PainterSetting();
///
/// Auto-Painter Settings
///
public AutoPainterSetting AutoPainter = new AutoPainterSetting();
///
/// Autopaints a givent map by the auto painter settings
///
public void AutoPaint()
{
if (AutoPainter.AutoPaintMapIndex < 0 || AutoPainter.AutoPaintMapIndex >= _mapSets.Count)
{
return;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
EditorCoroutineUtility.StartCoroutine(BakeTiles(), this);
}
else
{
StartCoroutine(BakeTiles());
}
#endif
}
///
/// Whether the Auto-Painter is baking in the tiles right now or not
///
public bool Baking { get; set; }
///
/// Bakes all the tiles from the Auto-Painter
///
///
protected virtual IEnumerator BakeTiles()
{
MapSet Map = _mapSets[AutoPainter.AutoPaintMapIndex];
Debug.Log($"Baking Map {Map.SetSettings.Name} (Index:{AutoPainter.AutoPaintMapIndex})");
ClearMap(AutoPainter.AutoPaintMapIndex);
RaycastHit ForRayHit;
RaycastHit AgainstRayHit;
Baking = true;
float RaycastDistance = AutoPainter.AutoPainterElavationIncrease + AutoPainter.AutoPainterElavationIDecrease + Map.SetSettings.MapSettings.Offset.y / 100f;
while (Baking)
{
for (int x = 0; x < Map.SetSettings.MapSettings.MapWidth; x++)
{
for (int y = 0; y < Map.SetSettings.MapSettings.MapHeight; y++)
{
// Raycast
Vector3 TileWorldPosition = GetTileWorldIndexCenter(x, y, Map);
// Water Check
if (Physics.Raycast(TileWorldPosition + Vector3.up * AutoPainter.AutoPainterElavationIncrease, Vector3.down * RaycastDistance, out ForRayHit, 800, AutoPainter.AutoPainterCheckForLayers))
{
if (Physics.Raycast(TileWorldPosition + Vector3.up * AutoPainter.AutoPainterElavationIncrease, Vector3.down * RaycastDistance, out AgainstRayHit, 800, AutoPainter.AutoPainterCheckAgainstLayers))
{
// If the for is closer then count it
if (ForRayHit.distance < AgainstRayHit.distance)
{
Map.ChangeDefaultTileType(x, y, AutoPainter.AutoPainterType);
}
else
{
// Distance Check
float HeightDifference = AgainstRayHit.point.y - Map.SetSettings.MapSettings.Offset.y / 100f;
if (HeightDifference > AutoPainter.AboveMapTypeChangeHeight)
{
Map.ChangeDefaultTileType(x, y, AutoPainter.AutoPainterAboveHeightType);
}
else if (HeightDifference < -AutoPainter.BelowMapTypeChangeHeight)
{
Map.ChangeDefaultTileType(x, y, AutoPainter.AutoPainterBelowHeightType);
}
}
}
else
{
Map.ChangeDefaultTileType(x, y, AutoPainter.AutoPainterType);
}
}
else
{
if (Physics.Raycast(TileWorldPosition + Vector3.up * AutoPainter.AutoPainterElavationIncrease, Vector3.down * RaycastDistance, out AgainstRayHit, 800, AutoPainter.AutoPainterCheckAgainstLayers))
{
// Distance Check
float HeightDifference = AgainstRayHit.point.y - Map.SetSettings.MapSettings.Offset.y / 100f;
if (HeightDifference > AutoPainter.AboveMapTypeChangeHeight)
{
Map.ChangeDefaultTileType(x, y, AutoPainter.AutoPainterAboveHeightType);
}
else if (HeightDifference < -AutoPainter.BelowMapTypeChangeHeight)
{
Map.ChangeDefaultTileType(x, y, AutoPainter.AutoPainterBelowHeightType);
}
}
}
if (!Baking)
{
break;
}
}
if (!Baking)
{
break;
}
yield return null;
}
Baking = false;
}
SaveMaps();
Debug.Log($"Bake Complete");
}
///
/// Creates a seam from the seam settings. Editor Only
///
public void CreateSeam()
{
if (Application.isPlaying)
{
return;
}
if (MapSeamSettings.MapAInsertSettings.MapIndex < 0 || MapSeamSettings.MapAInsertSettings.MapIndex >= MapSets.Count)
{
return;
}
if (MapSeamSettings.MapBInsertSettings.MapIndex < 0 || MapSeamSettings.MapBInsertSettings.MapIndex >= MapSets.Count)
{
return;
}
MapSet MapA = MapSets[MapSeamSettings.MapAInsertSettings.MapIndex];
MapSet MapB = MapSets[MapSeamSettings.MapBInsertSettings.MapIndex];
MapSeam NewSeam = new MapSeam(MapA, MapB, MapSeamSettings.MapAInsertSettings.ConnectionSide, MapSeamSettings.MapBInsertSettings.ConnectionSide);
}
///
/// Clears all maps of all the painted tiles
///
public void ClearMap()
{
if (Painter.CleanMapIndex < 0 || Painter.CleanMapIndex >= _mapSets.Count)
{
return;
}
MapSet Map = _mapSets[AutoPainter.AutoPaintMapIndex];
Map.CleanMapTiles();
SaveMaps();
}
///
/// Clears a map of all the painted tiles
///
public void ClearMap(int MapIndex)
{
if (MapIndex < 0 || MapIndex >= _mapSets.Count)
{
return;
}
MapSet Map = _mapSets[MapIndex];
Map.CleanMapTiles();
SaveMaps();
}
#endregion
#region Unity
public static NavigationManager Instance = null;
public bool Initialized { get; set; }
protected void Awake()
{
ApplicationPlaying = Application.IsPlaying(this);
if (Instance == null)
{
Instance = this;
}
else
{
Debug.Log($"Duplicate Navigation Manager in Scene. Destroying Navigation Manager {name}#{GetInstanceID()}");
Destroy(gameObject);
}
if (RandomValidPosition == null)
{
RandomValidPosition = new System.Random(33399927);
}
_activeSets = new List();
LoadMaps(_activeSets);
if (_activeSets.Count <= 0)
{
enabled = false;
return;
}
Logs = new List();
Warnings = new List();
Errors = new List();
SetMapBridges();
Running = true;
SimulationAgents = new Dictionary();
SimulationAgentList = new List();
Obstacles = new List();
Agents = new List();
_parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = ManagerSettings.PathfindingParrellism };
Threads = new Thread[ManagerSettings.MapRedundancy + 1];
bool CreateAgentMap = ManagerSettings.SimulationSettings.UseExtraSimulation && ManagerSettings.SimulationSettings.UseAgentAvoidance;
foreach (MapSet Set in _activeSets)
{
Set.Initialize(ManagerSettings.PathfindingParrellism, ManagerSettings.MapRedundancy, CreateAgentMap, AddDebugLog);
}
foreach(MapBridge Bridge in Bridges)
{
Bridge.Verify();
//Debug.Log($"{Bridge.MapA.SetSettings.Name} to {Bridge.MapB.SetSettings.Name} is Valid = {Bridge.ValidBridge}");
}
foreach (MapSeam Seam in Seams)
{
Seam.Verify();
//Debug.Log($"{Bridge.MapA.SetSettings.Name} to {Bridge.MapB.SetSettings.Name} is Valid = {Bridge.ValidBridge}");
}
if (ManagerSettings.SimulationSettings.UseExtraSimulation)
{
ExtraSimulatinThread = new Thread(SimulationHelperUpdate);
ExtraSimulatinThread.Start();
}
for (int i = 0; i < ManagerSettings.MapRedundancy + 1; i++)
{
if (i == 0)
{
Threads[i] = new Thread(UpdateThread0);
}
else if (i == 1)
{
Threads[i] = new Thread(UpdateThread1);
}
else if (i == 2)
{
Threads[i] = new Thread(UpdateThread2);
}
else if (i == 3)
{
Threads[i] = new Thread(UpdateThread3);
}
else if (i == 4)
{
Threads[i] = new Thread(UpdateThread4);
}
else if (i == 5)
{
Threads[i] = new Thread(UpdateThread5);
}
else if (i == 6)
{
Threads[i] = new Thread(UpdateThread6);
}
else if (i == 7)
{
Threads[i] = new Thread(UpdateThread7);
}
else if (i == 8)
{
Threads[i] = new Thread(UpdateThread8);
}
else if (i == 9)
{
Threads[i] = new Thread(UpdateThread9);
}
Threads[i].Start();
}
Initialized = true;
Debug.Log($"Navigation Manager Initialized");
}
///
/// List of all the obstacles that are currently active
///
public List Obstacles { get; protected set; }
///
/// List of all the agents that are currently active
///
public List Agents { get; protected set; }
private void Update()
{
for (int i = 0; i < Obstacles.Count; i++)
{
Obstacles[i].UpdateObstacle();
}
for (int i = 0; i < Agents.Count; i++)
{
Agents[i].AutoUpdateAgent();
}
}
public void FixedUpdate()
{
lock (Logs)
{
if (Logs.Count > 0)
{
for (int i = 0; i < Logs.Count; i++)
{
string log = Logs[i];
if (!string.IsNullOrEmpty(log))
{
Debug.Log(log);
}
}
Logs.Clear();
}
}
lock (Warnings)
{
if (Warnings.Count > 0)
{
for (int i = 0; i < Warnings.Count; i++)
{
string log = Warnings[i];
if (!string.IsNullOrEmpty(log))
{
Debug.LogWarning(log);
}
}
Warnings.Clear();
}
}
lock (Errors)
{
if (Errors.Count > 0)
{
for (int i = 0; i < Errors.Count; i++)
{
string log = Errors[i];
if (!string.IsNullOrEmpty(log))
{
Debug.LogError(log);
}
}
Errors.Clear();
}
}
}
private void OnDestroy()
{
foreach(MapSet Map in MapSets)
{
Map.OnDestroy();
}
if (Running)
{
Running = false;
foreach(Thread thread in Threads)
{
thread?.Abort();
}
}
if (HelperRunning)
{
HelperRunning = false;
ExtraSimulatinThread?.Abort();
}
Instance = null;
}
///
/// Navigation Manager Gizmos Settings
///
public GizmosSetting GizmosSettings;
///
/// Current Bridge that is being attempted
///
public MapBridge AttemptedBridge { get; set; }
private void OnDrawGizmosSelected()
{
#if UNITY_EDITOR
if (!Application.isEditor)
{
return;
}
if (!Application.IsPlaying(this))
{
for (int i = 0; i < MapSets.Count; i++)
{
if (MapSets[i].SetSettings.MapSettings.MapInfo.MakeSureSizeIsRight())
{
//Debug.Log($"Had to Correct Map {MapSets[i].SetSettings.Name}");
}
MapSets[i].InstanceID = i;
}
}
if (!GizmosSettings.DisplayGizmos)
{
return;
}
int Index = -1;
foreach(MapSet Map in MapSets)
{
Index++;
if (GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(Index))
{
continue;
}
Vector3 MapOffset = new Vector3(Map.SetSettings.MapSettings.Offset.x, Map.SetSettings.MapSettings.Offset.y, Map.SetSettings.MapSettings.Offset.z);
Vector3 MapSize = new Vector3();
MapSize.x = Map.SetSettings.MapSettings.TileSize * Map.SetSettings.MapSettings.MapWidth / 100f;
MapSize.y = 0.1f;
MapSize.z = Map.SetSettings.MapSettings.TileSize * Map.SetSettings.MapSettings.MapHeight / 100f;
Vector3 MapCenter = new Vector3();
MapCenter.x = MapSize.x / 2 + Map.SetSettings.MapSettings.Offset.x / 100f;
MapCenter.y = Map.SetSettings.MapSettings.Offset.y / 100f;
MapCenter.z = MapSize.z / 2 + Map.SetSettings.MapSettings.Offset.z / 100f;
if (GizmosSettings.DisplayMapBase)
{
if (GizmosSettings.DisplayMapEdge)
{
Color color = Color.black;
color.a = GizmosSettings.DisplayMapAlpha;
Gizmos.color = color;
Gizmos.DrawCube(MapCenter - Vector3.down * 0.4f, new Vector3(MapSize.x + 5, MapSize.y, MapSize.z + 5));
}
Color basecolor = Color.white;
basecolor.a = GizmosSettings.DisplayMapAlpha;
Gizmos.color = basecolor;
Gizmos.DrawCube(MapCenter, MapSize);
}
if (GizmosSettings.DisplayTiles)
{
Gizmos.color = Color.black;
MapOffset.y += 0.1f;
for (int x = 0; x <= Map.SetSettings.MapSettings.MapWidth; x++)
{
Vector3 Start = MapOffset + new Vector3(Map.SetSettings.MapSettings.TileSize, 0, 0) * x;
Start /= 100f;
Gizmos.DrawLine(Start, Start + Vector3.forward * MapSize.z);
}
for (int y = 0; y <= Map.SetSettings.MapSettings.MapHeight; y++)
{
Vector3 Start = MapOffset + new Vector3(0, 0, Map.SetSettings.MapSettings.TileSize) * y;
Start /= 100f;
Gizmos.DrawLine(Start, Start + Vector3.right * MapSize.x);
}
}
if (GizmosSettings.DisplayPaintedTilesMapIndex == -1 || GizmosSettings.DisplayPaintedTilesMapIndex == Index)
{
if (GizmosSettings.DisplayPaintedTiles)
{
if (Application.IsPlaying(this))
{
if (Map.Initialized)
{
for (int x = 0; x < Map.SetSettings.MapSettings.MapWidth; x++)
{
for (int y = 0; y < Map.SetSettings.MapSettings.MapHeight; y++)
{
try
{
TileTypes GetType = Map.BaseMap.GetTileType(x, y);
if (!GizmosSettings.OnlyPaintTheseTypes.Contains(GetType))
{
continue;
}
if (GetType == TileTypes.Standard || GetType == TileTypes.Free)
{
Gizmos.color = Color.green;
}
else if (GetType == TileTypes.Blocked || GetType == TileTypes.Void)
{
Gizmos.color = Color.black;
}
else if (GetType == TileTypes.Obstacle)
{
Gizmos.color = Color.red;
}
else if (GetType == TileTypes.Water)
{
Gizmos.color = Color.blue;
}
Vector3 TilePosition = GetTileWorldIndexCenter(x, y, Map);
TilePosition.y += 0.01f;
Vector3 Size = Vector3.one * Map.SetSettings.MapSettings.TileSize / 100f;
Size.y = 0.01f;
Gizmos.DrawCube(TilePosition, Size);
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
}
}
else
{
Map.SetSettings.MapSettings.MapInfo.MakeSureSizeIsRight();
if (Map.SetSettings.MapSettings.MapWidth != Map.SetSettings.MapSettings.MapInfo.SavedTiles.GetLength(0) || Map.SetSettings.MapSettings.MapHeight != Map.SetSettings.MapSettings.MapInfo.SavedTiles.GetLength(1))
{
continue;
}
for (int x = 0; x < Map.SetSettings.MapSettings.MapWidth; x++)
{
for (int y = 0; y < Map.SetSettings.MapSettings.MapHeight; y++)
{
try
{
TileTypes GetType = (TileTypes)Map.SetSettings.MapSettings.MapInfo.SavedTiles[x, y];
if (!GizmosSettings.OnlyPaintTheseTypes.Contains(GetType))
{
continue;
}
if (GetType == TileTypes.Standard || GetType == TileTypes.Free)
{
Gizmos.color = Color.green;
}
else if (GetType == TileTypes.Blocked || GetType == TileTypes.Void)
{
Gizmos.color = Color.black;
}
else if (GetType == TileTypes.Obstacle)
{
Gizmos.color = Color.red;
}
else if (GetType == TileTypes.Water)
{
Gizmos.color = Color.blue;
}
Vector3 TilePosition = GetTileWorldIndexCenter(x, y, Map);
TilePosition.y += 0.2f;
Vector3 Size = Vector3.one * Map.SetSettings.MapSettings.TileSize / 100f;
Size.y = 0.5f;
Gizmos.DrawCube(TilePosition, Size);
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
}
}
if (GizmosSettings.DisplayAgentOwnedTiles)
{
if (Application.IsPlaying(this))
{
if (Map.Initialized)
{
Gizmos.color = Color.cyan;
if (Map.BaseMap.AgentOwnershipMap != null)
{
for (int x = 0; x < Map.SetSettings.MapSettings.MapWidth; x++)
{
for (int y = 0; y < Map.SetSettings.MapSettings.MapHeight; y++)
{
try
{
if (Map.BaseMap.AgentOwnershipMap.Tiles[x,y] != 0)
{
Vector3 TilePosition = GetTileWorldIndexCenter(x, y, Map);
TilePosition.y += 0.01f;
Vector3 Size = Vector3.one * Map.SetSettings.MapSettings.TileSize / 100f;
Size.y = 0.01f;
Gizmos.DrawCube(TilePosition, Size);
}
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
}
}
}
}
}
}
}
if (GizmosSettings.DisplayBridges)
{
Gizmos.color = Color.blue;
for (int i = 0; i < Bridges.Count; i++)
{
if (ValidBridge(Bridges[i]))
{
Gizmos.color = Color.blue;
}
else
{
Gizmos.color = Color.red;
}
for (int j = 1; j < Bridges[i].MidPoints.Count; j++)
{
// Figure out positions
Vector3 MidPoint = new Vector3(Bridges[i].MidPoints[j].x, Bridges[i].MidPoints[j].y, Bridges[i].MidPoints[j].z) / 100f;
Vector3 PreviousMidPoint = new Vector3(Bridges[i].MidPoints[j - 1].x, Bridges[i].MidPoints[j - 1].y, Bridges[i].MidPoints[j - 1].z) / 100f;
// Draw Map Position
Gizmos.DrawLine(MidPoint, PreviousMidPoint);
}
}
if(GizmosSettings.DisplayBridgeDirections)
{
for (int i = 0; i < Bridges.Count; i++)
{
if (!ValidBridge(Bridges[i]))
{
continue;
}
if (Bridges[i].WalkableDirections == BridgeDirections.A_To_B)
{
Vector3 StartPoint = new Vector3(Bridges[i].MidPoints[0].x, Bridges[i].MidPoints[0].y, Bridges[i].MidPoints[0].z) / 100f;
Vector3 EndPoint = new Vector3(Bridges[i].MidPoints[Bridges[i].MidPoints.Count - 1].x, Bridges[i].MidPoints[Bridges[i].MidPoints.Count - 1].y, Bridges[i].MidPoints[Bridges[i].MidPoints.Count - 1].z) / 100f;
Gizmos.color = Color.red;
Gizmos.DrawSphere(StartPoint, 0.5f);
Gizmos.color = Color.blue;
Gizmos.DrawSphere(EndPoint, 0.5f);
}
else if (Bridges[i].WalkableDirections == BridgeDirections.B_To_A)
{
Vector3 StartPoint = new Vector3(Bridges[i].MidPoints[0].x, Bridges[i].MidPoints[0].y, Bridges[i].MidPoints[0].z) / 100f;
Vector3 EndPoint = new Vector3(Bridges[i].MidPoints[Bridges[i].MidPoints.Count - 1].x, Bridges[i].MidPoints[Bridges[i].MidPoints.Count - 1].y, Bridges[i].MidPoints[Bridges[i].MidPoints.Count - 1].z) / 100f;
Gizmos.color = Color.blue;
Gizmos.DrawSphere(StartPoint, 0.5f);
Gizmos.color = Color.red;
Gizmos.DrawSphere(EndPoint, 0.5f);
}
}
}
if (AttemptedBridge != null)
{
if (ValidBridge(AttemptedBridge))
{
Gizmos.color = Color.green;
}
else
{
Gizmos.color = Color.yellow;
}
for (int j = 1; j < AttemptedBridge.MidPoints.Count; j++)
{
// Figure out positions
Vector3 MidPoint = new Vector3(AttemptedBridge.MidPoints[j].x, AttemptedBridge.MidPoints[j].y, AttemptedBridge.MidPoints[j].z) / 100f;
Vector3 PreviousMidPoint = new Vector3(AttemptedBridge.MidPoints[j - 1].x, AttemptedBridge.MidPoints[j - 1].y, AttemptedBridge.MidPoints[j - 1].z) / 100f;
// Draw Map Position
Gizmos.DrawLine(MidPoint, PreviousMidPoint);
}
}
}
else
{
if (Application.IsPlaying(this))
{
return;
}
foreach (MapBridge Bridge in Bridges)
{
ValidateBridge(Bridge);
}
}
if (MapSeamSettings.DisplaySeams)
{
//Gizmos.color = Color.green;
foreach(MapSeam Seam in Seams)
{
Vector3 MapASize = new Vector3();
MapASize.y = 0.1f;
Vector3 MapAPosition = new Vector3();
MapAPosition.y = Seam.MapA.SetSettings.MapSettings.Offset.y / 100f;
if (Seam.MapA_ConectionSide == SeamConnectionSide.South || Seam.MapA_ConectionSide == SeamConnectionSide.North)
{
MapASize.z = Seam.MapA.SetSettings.MapSettings.TileSize / 100f;
MapASize.x = Seam.MapA.SetSettings.MapSettings.TileSize * Seam.MapA.SetSettings.MapSettings.MapWidth / 100f;
MapAPosition.x = MapASize.x / 2 + Seam.MapA.SetSettings.MapSettings.Offset.x / 100f;
MapAPosition.z = MapASize.z / 2 + Seam.MapA.SetSettings.MapSettings.Offset.z / 100f;
if (Seam.MapA_ConectionSide == SeamConnectionSide.North)
{
MapAPosition.z += Seam.MapA.SetSettings.MapSettings.TileSize * (Seam.MapB.SetSettings.MapSettings.MapHeight - 1) / 100f;
}
}
else
{
MapASize.x = Seam.MapA.SetSettings.MapSettings.TileSize / 100f;
MapASize.z = Seam.MapA.SetSettings.MapSettings.TileSize * Seam.MapA.SetSettings.MapSettings.MapHeight / 100f;
MapAPosition.x = MapASize.x / 2 + Seam.MapA.SetSettings.MapSettings.Offset.x / 100f;
MapAPosition.z = MapASize.z / 2 + Seam.MapA.SetSettings.MapSettings.Offset.z / 100f;
if (Seam.MapA_ConectionSide == SeamConnectionSide.East)
{
MapAPosition.x += Seam.MapA.SetSettings.MapSettings.TileSize * (Seam.MapA.SetSettings.MapSettings.MapWidth - 1) / 100f;
}
}
Vector3 MapBSize = new Vector3();
MapBSize.y = 0.1f;
Vector3 MapBPosition = new Vector3();
if (Seam.MapB_ConectionSide == SeamConnectionSide.South || Seam.MapB_ConectionSide == SeamConnectionSide.North)
{
MapBSize.z = Seam.MapB.SetSettings.MapSettings.TileSize / 100f;
MapBSize.x = Seam.MapB.SetSettings.MapSettings.TileSize * Seam.MapB.SetSettings.MapSettings.MapWidth / 100f;
MapBPosition.x = MapBSize.x / 2 + Seam.MapB.SetSettings.MapSettings.Offset.x / 100f;
MapBPosition.z = MapBSize.z / 2 + Seam.MapB.SetSettings.MapSettings.Offset.z / 100f;
if (Seam.MapB_ConectionSide == SeamConnectionSide.North)
{
MapBPosition.z += Seam.MapB.SetSettings.MapSettings.TileSize * (Seam.MapB.SetSettings.MapSettings.MapHeight - 1) / 100f;
}
}
else
{
MapBSize.x = Seam.MapB.SetSettings.MapSettings.TileSize / 100f;
MapBSize.z = Seam.MapB.SetSettings.MapSettings.TileSize * Seam.MapB.SetSettings.MapSettings.MapHeight / 100f;
MapBPosition.x = MapASize.x / 2 + Seam.MapB.SetSettings.MapSettings.Offset.x / 100f;
MapBPosition.z = MapASize.z / 2 + Seam.MapB.SetSettings.MapSettings.Offset.z / 100f;
if (Seam.MapB_ConectionSide == SeamConnectionSide.East)
{
MapBPosition.x += Seam.MapB.SetSettings.MapSettings.TileSize * (Seam.MapA.SetSettings.MapSettings.MapWidth - 1) / 100f;
}
}
Gizmos.color = Color.blue;
Gizmos.DrawCube(MapAPosition, MapASize);
Gizmos.color = Color.yellow;
Gizmos.DrawCube(MapBPosition, MapBSize);
Gizmos.color = Color.blue;
Gizmos.DrawLine(MapAPosition, MapBPosition);
}
}
if (Application.IsPlaying(this))
{
return;
}
if (GizmosSettings.DisplayPaintBrush)
{
Event e = Event.current;
Vector3 mousePos = e.mousePosition;
float ppp = EditorGUIUtility.pixelsPerPoint;
if (SceneView.currentDrawingSceneView == null || SceneView.currentDrawingSceneView.camera == null)
{
return;
}
mousePos.y = SceneView.currentDrawingSceneView.camera.pixelHeight - mousePos.y * ppp;
mousePos.x *= ppp;
//Debug.Log($"Try To Paint");
Ray ray = SceneView.currentDrawingSceneView.camera.ScreenPointToRay(mousePos);
MapSet ClosestMapSet = null;
float ClosestScore = float.MaxValue;
Vector3 ClosestPosition = new Vector3();
int NewIndex = 0;
foreach (MapSet Set in MapSets)
{
if (GizmosSettings.DisplayMapGizmos_ForMapIndecies.Count > 0 && !GizmosSettings.DisplayMapGizmos_ForMapIndecies.Contains(NewIndex))
{
continue;
}
NewIndex++;
Plane MapPlane = new Plane(Vector3.up, new Vector3(Set.SetSettings.MapSettings.Offset.x, Set.SetSettings.MapSettings.Offset.y, Set.SetSettings.MapSettings.Offset.z) / 100f);
if (MapPlane.Raycast(ray, out float Enter))
{
Vector3 HitPosition = ray.GetPoint(Enter);
if (ValidPoint(HitPosition, Set))
{
//Debug.Log($"Scored a Hit at Position {HitPosition} on map {Set.SetSettings.Name} - Score {Enter}");
if (Enter < ClosestScore)
{
ClosestMapSet = Set;
ClosestScore = Enter;
ClosestPosition = HitPosition;
}
}
}
}
if (ClosestMapSet != null)
{
//Debug.Log("Show Paint Brush");
Vector3 Size = (ClosestMapSet.SetSettings.MapSettings.TileSize + ClosestMapSet.SetSettings.MapSettings.TileSize * Painter.CurrentPainterRadius * 2) * Vector3.one;
Size /= 100f;
Size.y = 1;
Size.x -= 0.2f * ClosestMapSet.SetSettings.MapSettings.TileSize / 100f;
Size.z -= 0.2f * ClosestMapSet.SetSettings.MapSettings.TileSize / 100f;
Vector3 PainterPosition = ClosestPosition + Vector3.up;
PainterPosition = GetTileCenterWorldPosition(PainterPosition, ClosestMapSet);
Color BrushColor = Color.white;
if (Painter.CurrentPainterType == TileTypes.Standard || Painter.CurrentPainterType == TileTypes.Free)
{
BrushColor = Color.green;
}
else if (Painter.CurrentPainterType == TileTypes.Blocked || Painter.CurrentPainterType == TileTypes.Void)
{
BrushColor = Color.black;
}
else if (Painter.CurrentPainterType == TileTypes.Obstacle)
{
BrushColor = Color.red;
}
else if (Painter.CurrentPainterType == TileTypes.Water)
{
BrushColor = Color.blue;
}
BrushColor.a = 0.5f;
Gizmos.color = BrushColor;
if (GizmosSettings.DebugPaintBrushPosition)
{
IntVector3 WorldTileIndex = GetTileWorldPosition(PainterPosition);
IntVector2 TileIndex = ClosestMapSet.GetMapTileIndex(WorldTileIndex);
Debug.Log($"Brush Position Data: Tile Center({PainterPosition.x}, {PainterPosition.y}, {PainterPosition.z}), Tile Index({TileIndex.x}, {TileIndex.y})");
}
if (Painter.PainterType == PainterTypes.Square)
{
Gizmos.DrawCube(PainterPosition, Size);
//if (SquarePaintBrush == null)
//{
// GameObject PrimativeMeshObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
// SquarePaintBrush = PrimativeMeshObject.GetComponent();
// _squareFilter = PrimativeMeshObject.GetComponent();
// Collider collider = PrimativeMeshObject.GetComponent();
// collider.enabled = false;
// PrimativeMeshObject.layer = 5;
// SquarePaintBrush.transform.SetParent(transform);
// SquarePaintBrush.gameObject.name = "Square Brush";
// DestroyImmediate(collider);
// SquarePaintBrush.transform.position = Vector3.up * 1000000;
//}
//SquarePaintBrush.sharedMaterial.color = BrushColor;
//SquarePaintBrush.transform.position = PainterPosition;
//SquarePaintBrush.transform.localScale = Size;
//Gizmos.DrawMesh(_squareFilter.sharedMesh, SquarePaintBrush.subMeshStartIndex, PainterPosition, Quaternion.identity, Size);
}
else
{
if (Painter.CirclePaintBrush == null)
{
GameObject PrimativeMeshObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
Painter.CirclePaintBrush = PrimativeMeshObject.GetComponent();
Painter.CircleFilter = PrimativeMeshObject.GetComponent();
Collider collider = PrimativeMeshObject.GetComponent();
PrimativeMeshObject.layer = 5;
//CirclePaintBrush.transform.SetParent(transform);
Painter.CirclePaintBrush.gameObject.name = "Circle Brush";
DestroyImmediate(collider);
Painter.CirclePaintBrush.transform.position = Vector3.up * 1000000;
}
//CirclePaintBrush.sharedMaterial.color = BrushColor;
//CirclePaintBrush.transform.position = PainterPosition;
//CirclePaintBrush.transform.localScale = Size;
Gizmos.DrawMesh(Painter.CircleFilter.sharedMesh, Painter.CirclePaintBrush.subMeshStartIndex, PainterPosition, Quaternion.identity, Size);
}
}
}
#endif
}
///
/// Saves all the maps for the current scene
///
public void SaveMaps()
{
if (Application.isPlaying)
{
return;
}
JsonSerializerSettings setting = new JsonSerializerSettings
{
Formatting = Formatting.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string BasePath = Application.dataPath + ManagerSettings.MapSaveDataFolder;
if (string.IsNullOrEmpty(ManagerSettings.MapSaveDataFolder) || ManagerSettings.MapSaveDataFolder == "None" || !Directory.Exists(BasePath))
{
if (!Directory.Exists(BasePath) && ManagerSettings.MapSaveDataFolder != "None" && !string.IsNullOrEmpty(ManagerSettings.MapSaveDataFolder))
{
Debug.Log($"Save -> Base Path not Valid: FULL: '{BasePath}' -Partial: '{ManagerSettings.MapSaveDataFolder}'");
}
BasePath = Application.streamingAssetsPath + "/Saved Maps/";
if (!Directory.Exists(Application.streamingAssetsPath))
{
Directory.CreateDirectory(Application.streamingAssetsPath);
}
if (!Directory.Exists(Application.streamingAssetsPath + "/Saved Maps/"))
{
Directory.CreateDirectory(Application.streamingAssetsPath + "/Saved Maps/");
}
}
foreach (MapSet MapSet in _mapSets)
{
MapSet.SetSettings.MapSettings.MapInfo.MakeSureSizeIsRight();
string path = Path.Combine(BasePath, $"Scene_({SceneManager.GetActiveScene().name})-Map_({MapSet.SetSettings.Name}).json");
string json = JsonConvert.SerializeObject(MapSet, setting);
if (File.Exists(path))
{
File.Delete(path);
}
File.WriteAllText(path, json);
}
}
///
/// Load all the maps for the current scene
///
public void LoadMaps()
{
if (Application.isPlaying)
{
return;
}
//Debug.Log("Load Maps");
JsonSerializerSettings setting = new JsonSerializerSettings
{
Formatting = Formatting.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string BasePath = Application.dataPath + ManagerSettings.MapSaveDataFolder;
if (string.IsNullOrEmpty(ManagerSettings.MapSaveDataFolder) || ManagerSettings.MapSaveDataFolder == "None" || !Directory.Exists(BasePath))
{
if (!Directory.Exists(BasePath) && ManagerSettings.MapSaveDataFolder != "None" && !string.IsNullOrEmpty(ManagerSettings.MapSaveDataFolder))
{
Debug.Log($"Load -> Base Path not Valid: FULL: '{BasePath}' -Partial: '{ManagerSettings.MapSaveDataFolder}'");
}
BasePath = Application.streamingAssetsPath + "/Saved Maps/";
}
List NewMapSet = new List();
foreach (MapSet MapSet in _mapSets)
{
string path = Path.Combine(BasePath, $"Scene_({SceneManager.GetActiveScene().name})-Map_({MapSet.SetSettings.Name}).json");
if (File.Exists(path))
{
string fileContent = File.ReadAllText(path);
MapSet SavedMap = JsonConvert.DeserializeObject(fileContent);
NewMapSet.Add(SavedMap);
}
else
{
NewMapSet.Add(MapSet);
}
}
_mapSets.Clear();
_mapSets = NewMapSet;
}
///
/// Load all the maps for the current scene and puts them in the list
///
///
protected void LoadMaps(List NewList)
{
JsonSerializerSettings setting = new JsonSerializerSettings
{
Formatting = Formatting.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string BasePath = Application.dataPath + ManagerSettings.MapSaveDataFolder;
if (string.IsNullOrEmpty(ManagerSettings.MapSaveDataFolder) || ManagerSettings.MapSaveDataFolder == "None" || !Directory.Exists(BasePath))
{
if (!Directory.Exists(BasePath) && ManagerSettings.MapSaveDataFolder != "None" && !string.IsNullOrEmpty(ManagerSettings.MapSaveDataFolder))
{
Debug.Log($"Load -> Base Path not Valid: FULL: '{BasePath}' -Partial: '{ManagerSettings.MapSaveDataFolder}'");
}
BasePath = Application.streamingAssetsPath + "/Saved Maps/";
}
foreach (MapSet MapSet in _mapSets)
{
string path = Path.Combine(BasePath, $"Scene_({SceneManager.GetActiveScene().name})-Map_({MapSet.SetSettings.Name}).json");
if (File.Exists(path))
{
string fileContent = File.ReadAllText(path);
MapSet SavedMap = JsonConvert.DeserializeObject(fileContent);
NewList.Add(SavedMap);
}
else
{
NewList.Add(MapSet);
}
}
}
#endregion
#region Updates
public void UpdateThread0()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update0);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update0(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[0].Update();
}
}
public void UpdateThread1()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update1);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update1(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[1].Update();
}
}
public void UpdateThread2()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update2);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update2(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[2].Update();
}
}
public void UpdateThread3()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update3);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update3(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[3].Update();
}
}
public void UpdateThread4()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update4);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update4(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[4].Update();
}
}
public void UpdateThread5()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update5);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update5(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[5].Update();
}
}
public void UpdateThread6()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update6);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update6(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[6].Update();
}
}
public void UpdateThread7()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update7);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update7(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[7].Update();
}
}
public void UpdateThread8()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update8);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update8(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[8].Update();
}
}
public void UpdateThread9()
{
try
{
while (Running)
{
Thread.Sleep(1);
Parallel.ForEach(_activeSets, _parallelOptions, Update9);
}
}
catch (Exception e)
{
Debug.Log($"Error Caught {e}");
}
}
public void Update9(MapSet Map)
{
if (Map.Initialized)
{
Map.RedundantMaps[9].Update();
}
}
#endregion
#region Extra Simulation
///
/// Dictionary of all the simulation Agent
///
public Dictionary SimulationAgents { get; protected set; }
///
/// List of all the simulation agents
///
public List SimulationAgentList { get; protected set; }
///
/// Stopwatch to keep track of the helper update
///
protected System.Diagnostics.Stopwatch HelperStopwatch;
///
/// The Helper threads target period in ms
///
public long HelperTargetPeriod { get; set; }
///
/// The Helper threads target period in sec
///
public float HelperTargetDeltaTime { get; set; }
///
/// The Helper threads Delta Time of the last frame
///
public float HelperDeltaTime { get; protected set; }
///
/// This helper is used to run the simulation agents and the agent avoidence
///
public void SimulationHelperUpdate()
{
HelperRunning = true;
HelperStopwatch = new System.Diagnostics.Stopwatch();
HelperTargetPeriod = (int)MathF.Ceiling(1000f / ManagerSettings.SimulationSettings.DesiredHelperTickrate);
HelperTargetDeltaTime = HelperTargetPeriod / 1000f;
while (HelperRunning)
{
try
{
HelperStopwatch.Start();
// Update
HelperUpdate();
// Wait Section
HelperStopwatch.Stop();
HelperDeltaTime = HelperStopwatch.ElapsedMilliseconds / 1000f;
if (HelperStopwatch.ElapsedMilliseconds < HelperTargetPeriod)
{
HelperDeltaTime = HelperTargetDeltaTime;
int SleepPeriod = (int)(HelperTargetPeriod - HelperStopwatch.ElapsedMilliseconds);
Thread.Sleep(SleepPeriod);
}
else
{
HelperDeltaTime = HelperStopwatch.ElapsedMilliseconds / 1000f;
}
HelperStopwatch.Reset();
}
catch (Exception e)
{
lock (Errors)
{
Errors.Add($"{e.Message} \n --------------------------------- \n {e.StackTrace}");
}
}
}
}
///
/// The main update section of the simulation helper update. Removed this section for clarity and ease of use
///
protected virtual void HelperUpdate()
{
lock (SimulationAgents)
{
for (int i = 0; i < SimulationAgentList.Count; i++)
{
SimulationAgentList[i].Update();
}
}
for (int i = 0; i < MapSets.Count; i++)
{
MapSets[i].ClearClaims();
}
}
#endregion
#region Helpers
///
/// Gets the tile world index center for a specific map
///
///
///
///
///
private Vector3 GetTileWorldIndexCenter(int x, int y, MapSet map)
{
Vector3 NewPosition = new Vector3();
NewPosition.x = x * map.SetSettings.MapSettings.TileSize + map.SetSettings.MapSettings.TileSize / 2f + map.SetSettings.MapSettings.Offset.x;
NewPosition.y = map.SetSettings.MapSettings.Offset.y;
NewPosition.z = y * map.SetSettings.MapSettings.TileSize + map.SetSettings.MapSettings.TileSize / 2f + map.SetSettings.MapSettings.Offset.z;
NewPosition /= 100f;
return NewPosition;
}
///
/// Checks to see if any point of a circle is on a specific map
///
///
///
///
///
internal bool CircleOnMap(MapSet set, Vector3 newPosition, float radius)
{
IntVector3 WorldTileIndex = GetTileWorldPosition(newPosition);
IntVector2 TileIndex = set.GetMapTileIndex(WorldTileIndex);
int IntRadius = Mathf.FloorToInt(radius * 100 / set.SetSettings.MapSettings.TileSize);
IntVector2 RadiusVector = new IntVector2(IntRadius, IntRadius);
IntVector2 BottomLeftTileIndex = set.GetMapTileIndex(set.BottomLeftPosition) - RadiusVector;
IntVector2 TopRightTileIndex = set.GetMapTileIndex(set.TopRightPosition) + RadiusVector;
if (TileIndex.x >= BottomLeftTileIndex.x && TileIndex.x <= TopRightTileIndex.x && TileIndex.y >= BottomLeftTileIndex.y && TileIndex.y <= TopRightTileIndex.y)
{
return true;
}
return false;
}
///
/// Checks to see if any point of a rectangle is on a specific map
///
///
///
///
///
internal bool RectOnMap(MapSet set, PositionSquareRect newPositionRect, float HeightCheck)
{
if (newPositionRect.Corners[0].y * 100 < set.SetSettings.MapSettings.Offset.y || (newPositionRect.Corners[0].y - HeightCheck) * 100 > set.SetSettings.MapSettings.Offset.y)
{
return false;
}
foreach(Vector3 Corner in newPositionRect.Corners)
{
if (set.PointInMap(GetTileWorldPosition(Corner)))
{
return true;
}
}
return false;
}
///
/// Get the best map at a world tile index. Can be NULL
///
///
///
public MapSet GetMapAtTileWorldPosition(IntVector3 intVector3)
{
List PotentialMaps = new List();
foreach(MapSet set in MapSets)
{
if (set.PointInMap(intVector3))
{
PotentialMaps.Add(set);
}
}
if (PotentialMaps.Count == 0)
{
return null;
}
MapSet ClosestMap = PotentialMaps[0];
int ClosestMapScore = Mathf.Abs(ClosestMap.SetSettings.MapSettings.Offset.y - intVector3.y);
foreach (MapSet set in PotentialMaps)
{
int NewScore = Mathf.Abs(set.SetSettings.MapSettings.Offset.y - intVector3.y);
if (NewScore < ClosestMapScore)
{
ClosestMap = set;
ClosestMapScore = NewScore;
}
}
return ClosestMap;
}
///
/// Get the best map at a world position. Can be NULL
///
///
///
public MapSet GetMapAtWorldPosition(Vector3 position)
{
IntVector3 intWorldPosition = GetTileWorldPosition(position);
List PotentialMaps = new List();
foreach (MapSet set in MapSets)
{
if (set.PointInMap(intWorldPosition))
{
PotentialMaps.Add(set);
}
}
if (PotentialMaps.Count == 0)
{
return null;
}
MapSet ClosestMap = PotentialMaps[0];
int ClosestMapScore = Mathf.Abs(ClosestMap.SetSettings.MapSettings.Offset.y - intWorldPosition.y);
foreach (MapSet set in PotentialMaps)
{
int NewScore = Mathf.Abs(set.SetSettings.MapSettings.Offset.y - intWorldPosition.y);
if (NewScore < ClosestMapScore)
{
ClosestMap = set;
ClosestMapScore = NewScore;
}
}
return ClosestMap;
}
///
/// Adds the Obstacle to the Manager
///
///
public void AddObstacle(NavigationObstacle navigationObstacle)
{
if (!Obstacles.Contains(navigationObstacle))
{
Obstacles.Add(navigationObstacle);
}
}
///
/// Removes the Obstacle to the Manager
///
///
public void RemoveObstacle(NavigationObstacle navigationObstacle)
{
if (Obstacles.Contains(navigationObstacle))
{
Obstacles.Remove(navigationObstacle);
}
}
///
/// Adds the Agent to the Manager
///
///
public void AddAgent(NavigationAgent agent)
{
if (!Agents.Contains(agent))
{
Agents.Add(agent);
}
}
///
/// Adds the simulation Agent to the Manager
///
///
public void AddSimAgent(SimNavigationAgent agent)
{
if (!Agents.Contains(agent))
{
Agents.Add(agent);
lock(SimulationAgents)
{
SimulationAgents.Add(agent.SimulationAgent.SimID, agent.SimulationAgent);
lock (SimulationAgentList)
{
SimulationAgentList.Add(agent.SimulationAgent);
}
}
}
}
///
/// Removes the Agent to the Manager
///
///
public void RemoveAgent(NavigationAgent agent)
{
if (Agents.Contains(agent))
{
Agents.Remove(agent);
}
}
///
/// Removes the simulation Agent to the Manager
///
///
public void RemoveSimAgent(SimNavigationAgent agent)
{
if (!Running)
{
return;
}
if (Agents.Contains(agent))
{
Agents.Remove(agent);
lock (SimulationAgents)
{
SimulationAgents.Remove(agent.SimulationAgent.SimID);
lock (SimulationAgentList)
{
SimulationAgentList.Remove(agent.SimulationAgent);
}
}
}
}
///
/// Checks whether a point is valid on a map
///
///
///
///
public bool ValidPoint(Vector3 hitPosition, MapSet set)
{
if (set == null)
{
return false;
}
return set.PointInMap(new IntVector3(Mathf.FloorToInt(hitPosition.x * 100f), (int)(hitPosition.y * 100f), Mathf.FloorToInt(hitPosition.z * 100f)));
}
///
/// Checks whether a point is valid on a any map
///
///
///
///
public bool ValidPoint(Vector3 hitPosition, out MapSet HitMap)
{
HitMap = null;
foreach(MapSet Map in MapSets)
{
if (Map.PointInMap(new IntVector3(Mathf.FloorToInt(hitPosition.x * 100f), (int)(hitPosition.y * 100f), Mathf.FloorToInt(hitPosition.z * 100f))))
{
HitMap = Map;
}
}
if (HitMap == null)
{
return false;
}
return true;
}
///
/// Checks whether a point is valid on a map
///
///
///
///
public bool ValidPoint(IntVector3 hitWorldTilePosition, MapSet set)
{
return set.PointInMap(hitWorldTilePosition);
}
///
/// Get the world tile index from a position
///
///
///
public IntVector3 GetTileWorldPosition(Vector3 hitPosition)
{
return new IntVector3(Mathf.FloorToInt(hitPosition.x * 100), Mathf.FloorToInt(hitPosition.y * 100), Mathf.FloorToInt(hitPosition.z * 100));
}
///
/// Get the position world tile index from a world tile index
///
///
///
public Vector3 GetTileWorldPosition(IntVector3 tilePosition)
{
return new Vector3(tilePosition.x / 100f, tilePosition.y / 100f, tilePosition.z / 100f);
}
///
/// Gets the tile index center position from a position
///
///
///
///
public Vector3 GetTileCenterWorldPosition(Vector3 hitRoughPosition, MapSet Map)
{
IntVector3 GetTilePosition = GetTileWorldPosition(hitRoughPosition);
IntVector2 GetTileIndex = Map.GetMapTileIndex(GetTilePosition);
return GetTileCenterWorldPosition(GetTileIndex, Map);
}
///
/// Gets the tile index center position from a map tile index
///
///
///
///
public Vector3 GetTileCenterWorldPosition(IntVector2 mapTileIndex, MapSet Map)
{
return new Vector3(Map.SetSettings.MapSettings.Offset.x + mapTileIndex.x * Map.SetSettings.MapSettings.TileSize + Map.SetSettings.MapSettings.TileSize / 2f, Map.SetSettings.MapSettings.Offset.y, Map.SetSettings.MapSettings.Offset.z + mapTileIndex.y * Map.SetSettings.MapSettings.TileSize + Map.SetSettings.MapSettings.TileSize / 2f) / 100f;
}
///
/// Gets the tile index center position from a world tile index
///
///
///
///
public Vector3 GetTileCenterWorldPosition(IntVector3 worldTileIndex, MapSet Map)
{
IntVector3 FlattenedWorldTileIndex = Map.GetWorldTileIndex(Map.GetMapTileIndex(worldTileIndex), false); // Set it to the corner position
return new Vector3(FlattenedWorldTileIndex.x + Map.SetSettings.MapSettings.TileSize / 2f, (int)FlattenedWorldTileIndex.y, FlattenedWorldTileIndex.z + Map.SetSettings.MapSettings.TileSize / 2f) / 100f;
}
///
/// Gets the world tile index center position from a world tile index
///
///
///
///
public Vector3 GetTileCenterWorldPosition(IntVector3 worldTileIndex)
{
return new Vector3(Mathf.FloorToInt(worldTileIndex.x), (int)worldTileIndex.y, Mathf.FloorToInt(worldTileIndex.z)) / 100f;
}
///
/// Gets the tile index from a world tile index
///
///
///
///
public IntVector2 GetTileIndexForMap(IntVector3 TileWorldIndex, MapSet Map)
{
if (Map == null)
{
return new IntVector2();
}
return Map.GetMapTileIndex(TileWorldIndex);
}
///
/// Gets the tile index from a position
///
///
///
///
public IntVector2 GetTileIndexForMap(Vector3 WorldPosition, MapSet Map)
{
IntVector3 WorldTileIndex = GetTileWorldPosition(WorldPosition);
return Map.GetMapTileIndex(WorldTileIndex);
}
///
/// Gets the tile type from a position
///
///
///
///
public TileTypes GetTileTypeForMap(Vector3 WorldPosition, MapSet Map)
{
IntVector3 WorldTileIndex = GetTileWorldPosition(WorldPosition);
return Map.GetTileType(Map.GetMapTileIndex(WorldTileIndex));
}
///
/// Gets the tile type from a tile index
///
///
///
///
public TileTypes GetTileTypeForMap(IntVector2 MapIndex, MapSet Map)
{
if (Map == null)
{
return TileTypes.OutOfBounds;
}
return Map.GetTileType(MapIndex);
}
///
/// Gets the tile type from a tile index
///
///
///
///
///
public TileTypes GetTileTypeForMap(int x, int y, MapSet Map)
{
return Map.GetTileType(x, y);
}
///
/// Get the tile bounds of a map
///
///
///
///
///
public TileBounds GetTileBoundsForMap(int x, int y, MapSet Map)
{
Vector3 TilePosition = GetTileWorldPosition(Map.GetWorldTileIndex(x, y));
return new TileBounds(TilePosition, Map.SetSettings.MapSettings.TileSize / 100f);
}
///
/// Get the tile bounds of a map
///
///
///
///
public TileBounds GetTileBoundsForMap(IntVector2 TileIndex, MapSet Map)
{
Vector3 TilePosition = GetTileWorldPosition(Map.GetWorldTileIndex(TileIndex));
return new TileBounds(TilePosition, Map.SetSettings.MapSettings.TileSize / 100f);
}
///
/// Get a random valid position in the scene
///
///
///
///
public Vector3 GetRandomValidPosition(List ValidTypes, bool PlaceAtCenter = false)
{
if (MapSets.Count > 0)
{
MapSet RandomMap = MapSets[RandomValidPosition.Next(0, MapSets.Count)];
return GetRandomValidPosition(RandomMap, ValidTypes, PlaceAtCenter);
}
return new Vector3();
}
///
/// Get a random valid position oon this map
///
///
///
///
///
public Vector3 GetRandomValidPosition(List ValidTypes, MapSet Map, bool PlaceAtCenter = false)
{
return GetRandomValidPosition(Map, ValidTypes, PlaceAtCenter);
}
///
/// Get a random position in range of a position
///
///
///
///
///
///
public Vector3 GetRandomValidPositionAtPosition(List ValidTypes, IntVector2 Position, int Range = 30, bool PlaceAtCenter = false)
{
if (MapSets.Count > 0)
{
MapSet RandomMap = MapSets[RandomValidPosition.Next(0, MapSets.Count - 1)];
return GetRandomValidPositionAtPosition(RandomMap, ValidTypes, Position, Range, PlaceAtCenter);
}
return new Vector3();
}
protected System.Random RandomValidPosition = new System.Random(33399927);
///
/// get a random valid position for a map
///
///
///
///
///
public Vector3 GetRandomValidPosition(MapSet Map, List ValidTypes, bool PlaceAtCenter)
{
if (Map == null)
{
throw new Exception($"Map Is Null");
}
if (Map.SetSettings == null)
{
throw new Exception($"1. Map Settings Is Null");
}
if (Map.SetSettings.MapSettings == null)
{
throw new Exception($"2. Map Settings Is Null");
}
IntVector2 RandomIndex = new IntVector2(RandomValidPosition.Next(0, Map.SetSettings.MapSettings.MapWidth - 1), RandomValidPosition.Next(0, Map.SetSettings.MapSettings.MapHeight - 1));
IntVector3 WorldIndex;
if(!ValidTypes.Contains(Map.GetTileType(RandomIndex)))
{
int CurrentRadius = 0;
IntVector2 NewIndex;
while (!ValidTypes.Contains(Map.GetTileType(RandomIndex)) && CurrentRadius < 103)
{
CurrentRadius++;
NewIndex = RandomIndex;
NewIndex.x += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.y += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.y -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x += CurrentRadius;
NewIndex.y += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x -= CurrentRadius;
NewIndex.y += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x -= CurrentRadius;
NewIndex.y -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x += CurrentRadius;
NewIndex.y -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
}
}
WorldIndex = Map.GetWorldTileIndex(RandomIndex, false);
if (PlaceAtCenter)
{
Vector3 RandomPosition = new Vector3(WorldIndex.x + Map.SetSettings.MapSettings.TileSize / 2f, WorldIndex.y, WorldIndex.z + Map.SetSettings.MapSettings.TileSize / 2f) / 100f;
//Debug.Log($"Random Index ({RandomIndex.x}, {RandomIndex.y}) -> World Index ({WorldIndex.x}, {WorldIndex.y}, {WorldIndex.z}) -> World Position ({RandomPosition.x}, {RandomPosition.y}, {RandomPosition.z})");
return RandomPosition;
}
return new Vector3(WorldIndex.x, WorldIndex.y, WorldIndex.z) / 100f;
}
///
/// Get a random valid position at a position within a range
///
///
///
///
///
///
///
public Vector3 GetRandomValidPositionAtPosition(MapSet Map, List ValidTypes, IntVector2 Position, int Range = 30, bool PlaceAtCenter = false)
{
IntVector2 LowBound = Position - new IntVector2(Range, Range);
if (LowBound.x < 0)
{
LowBound.x = 0;
}
if (LowBound.y < 0)
{
LowBound.y = 0;
}
IntVector2 HighBound = Position + new IntVector2(Range, Range);
if (HighBound.x >= Map.SetSettings.MapSettings.MapWidth)
{
HighBound.x = Map.SetSettings.MapSettings.MapWidth - 1;
}
if (HighBound.y >= Map.SetSettings.MapSettings.MapHeight)
{
HighBound.y = Map.SetSettings.MapSettings.MapHeight - 1;
}
IntVector2 RandomIndex = new IntVector2(RandomValidPosition.Next(LowBound.x, HighBound.x), RandomValidPosition.Next(LowBound.y, HighBound.y));
IntVector3 WorldIndex;
if (!ValidTypes.Contains(Map.GetTileType(RandomIndex)))
{
int CurrentRadius = 0;
IntVector2 NewIndex;
while (!ValidTypes.Contains(Map.GetTileType(RandomIndex)) && CurrentRadius < 103)
{
CurrentRadius++;
NewIndex = RandomIndex;
NewIndex.x += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.y += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.y -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x += CurrentRadius;
NewIndex.y += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x -= CurrentRadius;
NewIndex.y += CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x -= CurrentRadius;
NewIndex.y -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
NewIndex = RandomIndex;
NewIndex.x += CurrentRadius;
NewIndex.y -= CurrentRadius;
if (ValidTypes.Contains(Map.GetTileType(NewIndex)))
{
RandomIndex = NewIndex;
break;
}
}
}
WorldIndex = Map.GetWorldTileIndex(RandomIndex, false);
if (PlaceAtCenter)
{
Vector3 RandomPosition = new Vector3(WorldIndex.x + Map.SetSettings.MapSettings.TileSize / 2f, WorldIndex.y, WorldIndex.z + Map.SetSettings.MapSettings.TileSize / 2f) / 100f;
//Debug.Log($"Random Index ({RandomIndex.x}, {RandomIndex.y}) -> World Index ({WorldIndex.x}, {WorldIndex.y}, {WorldIndex.z}) -> World Position ({RandomPosition.x}, {RandomPosition.y}, {RandomPosition.z})");
return RandomPosition;
}
return new Vector3(WorldIndex.x, WorldIndex.y, WorldIndex.z) / 100f;
}
public Vector3 GetRandomPosition()
{
if (MapSets.Count > 0)
{
MapSet RandomMap = MapSets[RandomValidPosition.Next(0, MapSets.Count)];
return GetRandomPosition(RandomMap);
}
return new Vector3();
}
///
/// Get a random position on a map
///
///
///
public Vector3 GetRandomPosition(MapSet Map)
{
IntVector2 RandomIndex = new IntVector2(RandomValidPosition.Next(0, Map.SetSettings.MapSettings.MapWidth - 1), RandomValidPosition.Next(0, Map.SetSettings.MapSettings.MapHeight - 1));
IntVector3 WorldIndex = Map.GetWorldTileIndex(RandomIndex);
return new Vector3(WorldIndex.x, WorldIndex.y, WorldIndex.z);
}
///
/// Gets the best map from a position
///
///
///
public MapSet GetCurrentMap(Vector3 WorldPosition)
{
if (MapSets.Count <= 0)
{
return null;
}
IntVector3 WorltIileIndex = GetTileWorldPosition(WorldPosition);
MapSet ClosestMap = null;
int ClosestScore = int.MaxValue;
foreach (MapSet map in MapSets)
{
if (map.PointInMap(WorltIileIndex))
{
int NewScore = WorltIileIndex.y - map.SetSettings.MapSettings.Offset.y;
if (NewScore >= 0)
{
if (NewScore < ClosestScore)
{
ClosestScore = NewScore;
ClosestMap = map;
}
}
}
}
return ClosestMap;
}
#endregion
}
[Serializable]
public struct TileBounds
{
public Vector3 Center;
public Vector3 BottomLeft;
public Vector3 TopLeft;
public Vector3 BottomRight;
public Vector3 TopRight;
public TileBounds(Vector3 TilePosition, float TileSize)
{
Center = TilePosition;
Center.x += TileSize / 2;
Center.z += TileSize / 2;
TopRight = TilePosition;
TopRight.x += TileSize;
TopRight.z += TileSize;
BottomLeft = TilePosition;
TopLeft = TilePosition;
TopLeft.z += TileSize;
BottomRight = TilePosition;
BottomRight.x += TileSize;
TopRight = TilePosition;
TopRight.x += TileSize;
TopRight.z += TileSize;
}
public bool InBounds(Vector3 Point)
{
if (Point.x > TopRight.x || Point.x < BottomLeft.x || Point.z > TopRight.z || Point.z < BottomLeft.z)
{
return false;
}
return true;
}
public bool IntersectsBounds(Vector3 PointA, Vector3 PointB)
{
if (InBounds(PointA) || InBounds(PointB))
{
return true;
}
if (LineLineCollision(PointA, PointB, BottomRight, BottomLeft) || LineLineCollision(PointA, PointB, BottomRight, TopRight) || LineLineCollision(PointA, PointB, BottomLeft, TopLeft) || LineLineCollision(PointA, PointB, TopRight, TopLeft))
{
return true;
}
return false;
}
public static bool LineLineCollision(Vector3 Position1Start, Vector3 Position1End, Vector3 Position2Start, Vector3 Position2End)
{
// Directions
float uA = ((Position2End.x - Position2Start.x) * (Position1Start.z - Position2Start.z) - (Position2End.z - Position2Start.z) * (Position1Start.x - Position2Start.x)) / ((Position2End.z - Position2Start.z) * (Position1End.x - Position1Start.x) - (Position2End.x - Position2Start.x) * (Position1End.z - Position1Start.z));
float uB = ((Position1End.x - Position1Start.x) * (Position1Start.z - Position2Start.z) - (Position1End.z - Position1Start.z) * (Position1Start.x - Position2Start.x)) / ((Position2End.z - Position2Start.z) * (Position1End.x - Position1Start.x) - (Position2End.x - Position2Start.x) * (Position1End.z - Position1Start.z));
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1)
{
return true;
}
return false;
}
}
}
namespace HPJ.Presentation.NavigationManagerSettings
{
///
/// The Manager settings of the Navigation Manager
///
[Serializable]
public class ManagerSetting
{
///
/// The amount of redundant maps generated - More Maps = Faster Pathfinding at cost of memory
///
[SerializeField]
[Range(0, 8)]
[Tooltip("The amount of redundant maps generated - More Maps = Faster Pathfinding at cost of memory")]
public int MapRedundancy = 4;
///
/// Setting used for parrellism for each maps pathfinding
///
[SerializeField]
[Range(2, 16)]
[Tooltip("Setting used for parrellism for each maps pathfinding")]
public int PathfindingParrellism = 4;
///
/// The size of the grid of maps you want to create
///
[Tooltip("The size of the grid of maps you want to create")]
public Vector2Int MapAutoCreationGridSize = new Vector2Int(1, 1);
///
/// The number of tiles in the x and z of the generated grid maps
///
[Tooltip("The number of tiles in the x and z of the generated grid maps")]
public Vector2Int MapAutoGridTileWidthAndHeight = new Vector2Int(1, 1);
///
/// The physical size of the autogenerated tiles on the generated maps
///
[Tooltip("The physical size of the autogenerated tiles on the generated maps")]
public int MapAutoGridTileSize = 100;
///
/// The physical offset of the bottom left map
///
[Tooltip("The physical offset of the bottom left map")]
public IntVector3 MapAutoGridOffset = new IntVector3();
///
/// Whether to create seams for each connected side of the autogrid
///
[Tooltip("Whether to create seams for each connected side of the autogrid")]
public bool MapAutoGridAutoSeam = true;
///
/// The filepath for the save data for this scene
///
[Tooltip("The filepath for the save data")]
public string MapSaveDataFolder = "None";
///
/// Extra Simulation Settings
///
public ExtraSimulationSettings SimulationSettings = new ExtraSimulationSettings();
}
///
/// The Painter settings, used to paint tiles on the Maps
///
[Serializable]
public class PainterSetting
{
///
/// The Paint Brush Size
///
[Range(0, 500)]
public int CurrentPainterRadius = 1;
///
/// The Tile Types we want to paint
///
public TileTypes CurrentPainterType = TileTypes.Blocked;
///
/// The Paint Brush Type
///
public PainterTypes PainterType = PainterTypes.Square;
///
/// Which Map do you want to clean (Change to Default Tile)
///
[Tooltip("Which Map do you want to clean (Change to Default Tile)")]
public int CleanMapIndex = 0;
[NonSerialized] public MeshRenderer SquarePaintBrush = null;
[NonSerialized] public MeshRenderer CirclePaintBrush = null;
[NonSerialized] public MeshFilter SquareFilter = null;
[NonSerialized] public MeshFilter CircleFilter = null;
}
///
/// The Auto-Painter settings, used to paint tiles on the Maps automatically
///
[Serializable]
public class AutoPainterSetting
{
///
/// What Tile Type the Auto painter turns the Tile Into
///
[Tooltip("What Tile Type the Auto painter turns the Tile Into")]
public TileTypes AutoPainterType = TileTypes.Water;
///
/// What Layers the Raycast must HIT to turn that tile
///
[Tooltip("What Layers the Raycast must HIT to turn that tile")]
public LayerMask AutoPainterCheckForLayers;
///
/// What Layers the Raycast must AVOID HITTING to turn that tile
///
[Tooltip("What Layers the Raycast must AVOID HITTING to turn that tile")]
public LayerMask AutoPainterCheckAgainstLayers;
///
/// "How much the Raycast will increase its starting position from the height of the Map (Offset Y)"
///
[Tooltip("How much the Raycast will increase its starting position from the height of the Map (Offset Y)")]
public float AutoPainterElavationIncrease = 20;
///
/// How much the Raycast will go below the height of the Map (Offset Y)
///
[Tooltip("How much the Raycast will go below the height of the Map (Offset Y)")]
public float AutoPainterElavationIDecrease = 100;
///
/// Which Map do you want to Auto Paint
///
[Tooltip("Which Map do you want to Auto Paint")]
public int AutoPaintMapIndex = 0;
///
/// How high above the map, where the tiles change type
///
[Tooltip("How high above the map, where the tiles change type")]
public float AboveMapTypeChangeHeight = 10;
///
/// What Tile Type the Auto painter turns the Tile Into on height check above
///
[Tooltip("What Tile Type the Auto painter turns the Tile Into on height check above")]
public TileTypes AutoPainterAboveHeightType = TileTypes.Blocked;
///
/// How far below the map, where the tiles change type
///
[Tooltip("How far below the map, where the tiles change type")]
public float BelowMapTypeChangeHeight = 10;
///
/// What Tile Type the Auto painter turns the Tile Into on height check below
///
[Tooltip("What Tile Type the Auto painter turns the Tile Into on height check below")]
public TileTypes AutoPainterBelowHeightType = TileTypes.Blocked;
}
///
/// The all seam settings
///
[Serializable]
public class SeamSettings
{
///
/// Whether to display seams
///
public bool DisplaySeams = false;
///
/// Map 1 or A Seam Insert Settings
///
public MapSeamInsertSettings MapAInsertSettings = new MapSeamInsertSettings();
///
/// Map 2 or B Seam Insert Settings
///
public MapSeamInsertSettings MapBInsertSettings = new MapSeamInsertSettings();
}
///
/// The map seam settings
///
[Serializable]
public class MapSeamInsertSettings
{
///
/// Map Index
///
public int MapIndex = -1;
///
/// Map Index
///
public SeamConnectionSide ConnectionSide = SeamConnectionSide.East;
}
///
/// Extra Simulation Settings
///
[Serializable]
public class ExtraSimulationSettings
{
///
/// Whether to use another thread for extra simulation. Used by Simulation Agents and Agent Avoidance
///
public bool UseExtraSimulation = false;
///
/// Whether to use agent avoidence for the simulation agents
///
public bool UseAgentAvoidance = false;
///
/// The Desired tickrate of the helper update
///
public int DesiredHelperTickrate = 60;
}
///
/// The Gizmos settings of the Navigation Manager
///
[Serializable]
public class GizmosSetting
{
///
/// Whether to show the Gizmos
///
[Header("GUI")]
public bool DisplayGizmos = true;
///
/// Whether to diplay the bridges
///
public bool DisplayBridges = false;
///
/// Shows the direction the bridge allows. Nothing for both ways, otherwise direction is from Red to Blue
///
public bool DisplayBridgeDirections = false;
///
/// The Bridge we want in inset a midpoint on
///
public int InsertBridgePointIndex = -1;
///
/// Whether to display tile grid
///
public bool DisplayTiles = false;
///
/// Whether to display transform handle for the map
///
public bool DisplayMapHandles = true;
///
/// Whether to display map nale label for the map
///
public bool DisplayMapLabels = true;
///
/// Whether to display the base of the Maps
///
public bool DisplayMapBase = true;
///
/// Whether to display the Map Edge
///
public bool DisplayMapEdge = true;
///
/// The Alpha of the Map Base and Edge
///
[Range(0, 1)]
public float DisplayMapAlpha = 1;
///
/// Whether to display the Map arrows on the Maps
///
public bool DisplayMapArrows = true;
///
/// Adjusts the Map Arrow Size
///
public float DisplayArrowSize = 12;
///
/// Whether to display the paint brush or not
///
public bool DisplayPaintBrush = false;
///
/// Whether to debug the paint brush position
///
public bool DebugPaintBrushPosition = false;
///
/// Whether to display the painted tiles. Painter and Auto-Painter
///
public bool DisplayPaintedTiles = false;
///
/// The Tiles we want to see
///
public List OnlyPaintTheseTypes = new List();
///
/// The Map index we want to show the painted tiles on. -1 for all
///
[Tooltip("Which Map do you want the tiles rendered, (-1 for All)")]
public int DisplayPaintedTilesMapIndex = -1;
///
/// limits the amount of gizmos on screen by the desired map indecies. a empty list means every map
///
public List DisplayMapGizmos_ForMapIndecies = new List();
///
/// Whetehr to display the tiles owned by agents
///
public bool DisplayAgentOwnedTiles = false;
}
}