using HPJ.Simulation;
using HPJ.Simulation.Enums;
using HPJ.Simulation.Map;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace HPJ.Presentation.Obstacle
{
///
/// The Base class for all navigation obstacles
///
public abstract class NavigationObstacle : MonoBehaviour
{
#region Unity
// Start is called before the first frame update
public virtual void Start()
{
if (!NavigationManager.Instance.Initialized)
{
Invoke(nameof(Start), 01f);
return;
}
UpdatePosition(transform.position, true);
NavigationManager.Instance?.AddObstacle(this);
}
public virtual void OnDestroy()
{
NavigationManager.Instance?.RemoveObstacle(this);
}
#endregion
#region Obstacle
///
/// Does the obstacle update automatically through the built in systems
///
[SerializeField]
protected bool _automaticUpdate = true;
public bool AutomaticUpdate { get { return _automaticUpdate; } set { _automaticUpdate = value; } }
///
/// The Height difference from the map to count as being on top of the map
///
[SerializeField, Tooltip("The Height from the transform y position to the ground that this counts as an obstacle")]
protected float _checkMapHeight = 1f;
public float CheckMapHeight { get { return _checkMapHeight; } set { _checkMapHeight = value; } }
///
/// The tile type the obstacle changes the tiles beneath it too
///
[SerializeField]
protected TileTypes _obstacleTileType = TileTypes.Obstacle;
public TileTypes ObstacleTileType { get { return _obstacleTileType; } }
///
/// The Update cycle of the obstacle
///
public virtual void UpdateObstacle()
{
if (_automaticUpdate)
{
UpdatePosition(transform.position);
}
}
///
/// The tiles and map relationship data with this obstacle
///
public Dictionary MapTileRelationships { get; protected set; }
///
/// Checks to see if the new position changes and if so it changes the mesh to block out the new corresponding tiles
///
///
///
public abstract void UpdatePosition(Vector3 NewPosition, bool ForceCheck = false);
///
/// What happens the the obstacle mesh position changes
///
///
///
protected abstract bool PositionChanged(Vector3 NewPosition);
///
/// Rotates the obstacle based on the desired Rotation. Basic NavigationObstacle will only swap the object size x and y values. Inherit to ovverride this behaviour
///
///
public abstract void Rotate(Quaternion Rotation);
///
/// Revalidates the tiles of the obstacle in case another obstacle travels over top of this one
///
public abstract void RevalidateTiles();
#endregion
}
[Serializable]
public struct PositionSquareRect
{
public Vector3 Position;
public Vector2 Size;
public Vector3[] Corners;
public PositionSquareRect(Vector3 position, Vector2 size)
{
Position = position;
Size = size;
Corners = new Vector3[4];
Corners[0] = Position + new Vector3(Size.x / 2, 0, Size.y / 2);
Corners[1] = Position + new Vector3(Size.x / 2, 0, -Size.y / 2);
Corners[2] = Position + new Vector3(-Size.x / 2, 0, -Size.y / 2);
Corners[3] = Position + new Vector3(-Size.x / 2, 0, Size.y / 2);
}
public PositionSquareRect(Vector3 position, Vector3 LowerBounds, Vector3 HigherBounds)
{
Position = position;
Size = new Vector2(HigherBounds.x - LowerBounds.x, HigherBounds.z - LowerBounds.z);
Corners = new Vector3[4];
LowerBounds.y = 0;
HigherBounds.y = 0;
Corners[0] = HigherBounds;
Corners[1] = new Vector3(HigherBounds.x, 0, LowerBounds.z);
Corners[2] = LowerBounds;
Corners[3] = new Vector3(LowerBounds.x, 0, HigherBounds.z);
}
public void UpdatePosition(Vector3 position)
{
Position = position;
Corners[0] = Position + new Vector3(Size.x / 2, 0, Size.y / 2);
Corners[1] = Position + new Vector3(Size.x / 2, 0, -Size.y / 2);
Corners[2] = Position + new Vector3(-Size.x / 2, 0, -Size.y / 2);
Corners[3] = Position + new Vector3(-Size.x / 2, 0, Size.y / 2);
}
public void UpdateSize(Vector2 newSize)
{
Size = newSize;
Corners[0] = Position + new Vector3(Size.x / 2, 0, Size.y / 2);
Corners[1] = Position + new Vector3(Size.x / 2, 0, -Size.y / 2);
Corners[2] = Position + new Vector3(-Size.x / 2, 0, -Size.y / 2);
Corners[3] = Position + new Vector3(-Size.x / 2, 0, Size.y / 2);
}
public bool InBounds(Vector3 Point)
{
if (Point.x > Corners[0].x || Point.x < Corners[2].x || Point.z > Corners[0].z || Point.z < Corners[2].z)
{
return false;
}
return true;
}
}
[Serializable]
public class MapObstacleRelationshipData
{
public MapSet Map;
public NavigationObstacle Obstacle;
public Dictionary RelatedTilesData;
public HashSet ValidatedTiles;
public HashSet InvalidatedTiles;
public HashSet AddedTiles;
public TileTypes ObstacleTileType;
public MapObstacleRelationshipData(MapSet map, NavigationObstacle obstacle, TileTypes ObstacleType)
{
ValidatedTiles = new HashSet();
InvalidatedTiles = new HashSet();
AddedTiles = new HashSet();
RelatedTilesData = new Dictionary();
Map = map;
Obstacle = obstacle;
ObstacleTileType = ObstacleType;
}
public void UnvalidateTiles()
{
InvalidatedTiles.Clear();
ValidatedTiles.Clear();
AddedTiles.Clear();
foreach (ObstacleData Data in RelatedTilesData.Values)
{
InvalidatedTiles.Add(Data.TileIndexKey);
Data.UnValidate();
}
}
public void AddOrValidateTile(IntVector3 tileIndex)
{
if (RelatedTilesData.ContainsKey(tileIndex))
{
RelatedTilesData[tileIndex].Validate();
InvalidatedTiles.Remove(tileIndex);
ValidatedTiles.Add(tileIndex);
}
else
{
ObstacleData NewTile = new ObstacleData(tileIndex);
RelatedTilesData.Add(tileIndex, NewTile);
AddedTiles.Add(tileIndex);
}
}
public void SortRelatedTileData()
{
foreach(IntVector3 InvalidatedTile in InvalidatedTiles)
{
RelatedTilesData.Remove(InvalidatedTile);
}
}
public ChangeMapJob GenerateMapChangeJob()
{
if (AddedTiles.Count == 0 && InvalidatedTiles.Count == 0)
{
//Debug.Log("No Tiles Changed");
return null;
}
ChangeMapJob MapChange = new ChangeMapJob();
// Set to Obstacle type
foreach (IntVector3 Tile in AddedTiles)
{
MapChange.AddTileChange(Tile.Vector2(), Obstacle.ObstacleTileType);
}
// Set back to default
foreach (IntVector3 Tile in InvalidatedTiles)
{
MapChange.AddTileChange(Tile.Vector2(), (TileTypes)Map.SetSettings.MapSettings.MapInfo.SavedTiles[Tile.x, Tile.y]);
}
//Debug.Log($"Tiles To Change {MapChange.TilesToBeChanged.Count} -> Added {AddedTiles.Count} -> Removed {InvalidatedTiles.Count}");
return MapChange;
}
internal void Revalidate()
{
ChangeMapJob MapChange = new ChangeMapJob();
bool ChangedTiles = false;
foreach (IntVector3 Tile in ValidatedTiles)
{
if (Map.GetTileType(Tile.Vector2()) != ObstacleTileType)
{
ChangedTiles = true;
MapChange.AddTileChange(Tile.Vector2(), ObstacleTileType);
}
}
if (ChangedTiles)
{
Map.ChangeMap(MapChange);
}
}
}
}