using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using UnityEngine;
using VOID.Generic.Dict;
namespace VOID.Generic.World
{
public class ComplexArea : SerializedMonoBehaviour
{
[SerializeField] [ReadOnly] public List areas;
[ReadOnly] [BoxGroup("variant", false)]
public bool isVariant;
[ReadOnly] [HideIf(nameof(isVariant))] [BoxGroup("variant", false)]
public List variants = new();
[ReadOnly] [ShowIf(nameof(isVariant))] [BoxGroup("variant", false)]
public ComplexArea original;
#if UNITY_EDITOR
private GameObject GetGameObjectForAreas()
{
const string areasGameObjectName = "_areas";
var areasGameObject = gameObject.transform.Find(areasGameObjectName)?.gameObject;
if (areasGameObject) return areasGameObject;
areasGameObject = new GameObject(areasGameObjectName);
areasGameObject.transform.position = Vector3.zero;
areasGameObject.transform.parent = gameObject.transform;
areasGameObject.transform.SetAsFirstSibling();
return areasGameObject;
}
[Title("Generate")]
[Button]
private void GenerateAreas()
{
areas.ForEach(area => DestroyImmediate(area.gameObject));
areas.Clear();
GenerateMissingAreas();
}
[Button]
private void GenerateMissingAreas()
{
// Bounds thats contains everything in this ComplexArea Prefab
var complexAreaBounds = new Bounds();
GetComponentsInChildren()
.ForEach(collider => complexAreaBounds.Encapsulate(collider.bounds));
GetComponentsInChildren()
.ForEach(meshRenderer => complexAreaBounds.Encapsulate(meshRenderer.bounds));
// To calculate position index we need only width (x) and length (z)
var startIndex = new Vector2Int(
Mathf.RoundToInt(complexAreaBounds.min.x / Area.Size),
Mathf.RoundToInt(complexAreaBounds.min.z / Area.Size)
);
var endIndex = new Vector2Int(
Mathf.RoundToInt(complexAreaBounds.max.x / Area.Size),
Mathf.RoundToInt(complexAreaBounds.max.z / Area.Size)
);
var areasGameObject = GetGameObjectForAreas();
// Create areas for everything inside bounds
for (var x = startIndex.x; x <= endIndex.x; x++)
{
for (var y = startIndex.y; y <= endIndex.y; y++)
{
if (areas.Any(area => area.position.x == x && area.position.y == y)) continue;
var areaGameObject = new GameObject();
areaGameObject.AddComponent();
areaGameObject.transform.parent = areasGameObject.transform;
areaGameObject.transform.position = new Vector3(x * Area.Size, 0, y * Area.Size);
}
}
UpdateAll();
}
[Button]
private void GenerateVariants()
{
Editor.EditorWindow.World.ComplexAreaRotateVariantGenerator.GenerateRotatedVariants(this);
}
[Title("Update")]
[Button(ButtonSizes.Large)]
public void UpdateAll()
{
UpdateAreaList();
UpdatePositionIndexes();
UpdateNames();
UpdateConnections();
}
[ResponsiveButtonGroup("Update")]
[Button]
private void UpdateAreaList()
{
areas = gameObject.GetComponentsInChildren().ToList();
areas.ForEach(area => area.complexArea = this);
}
[ResponsiveButtonGroup("Update")]
[Button]
private void UpdatePositionIndexes()
{
areas.ForEach(area =>
{
var position = area.transform.position;
area.position.x = Mathf.RoundToInt(position.x / Area.Size);
area.position.y = Mathf.RoundToInt(position.z / Area.Size);
});
}
[ResponsiveButtonGroup("Update")]
[Button]
private void UpdateNames()
{
UpdatePositionIndexes();
areas.ForEach(area => area.name = $"{nameof(Area)} ({area.position.x},{area.position.y})");
}
[ResponsiveButtonGroup("Update")]
[Button]
private void UpdateConnections()
{
UpdatePositionIndexes();
areas.ForEach(area =>
{
var forwardArea = areas.Find(subArea => (area.position + Vector2Int.up).Equals(subArea.position));
var rightArea = areas.Find(subArea => (area.position + Vector2Int.right).Equals(subArea.position));
var backArea = areas.Find(subArea => (area.position + Vector2Int.down).Equals(subArea.position));
var leftArea = areas.Find(subArea => (area.position + Vector2Int.left).Equals(subArea.position));
area.forwardConnection.direction = Direction2D.Forward;
area.rightConnection.direction = Direction2D.Right;
area.backConnection.direction = Direction2D.Back;
area.leftConnection.direction = Direction2D.Left;
if (forwardArea)
area.forwardConnection.type = AreaConnectionType.Inner;
else if (area.forwardConnection.type == AreaConnectionType.Inner)
area.forwardConnection.type = AreaConnectionType.None;
if (rightArea)
area.rightConnection.type = AreaConnectionType.Inner;
else if (area.rightConnection.type == AreaConnectionType.Inner)
area.rightConnection.type = AreaConnectionType.None;
if (backArea)
area.backConnection.type = AreaConnectionType.Inner;
else if (area.backConnection.type == AreaConnectionType.Inner)
area.backConnection.type = AreaConnectionType.None;
if (leftArea)
area.leftConnection.type = AreaConnectionType.Inner;
else if (area.leftConnection.type == AreaConnectionType.Inner)
area.leftConnection.type = AreaConnectionType.None;
});
}
[Title("Auto-Fix")]
[Button(ButtonSizes.Large)]
public void AutoFixAll()
{
AutoFixAreaTransforms();
AutoFixAreaHierarchy();
}
[ResponsiveButtonGroup("AutoFix")]
[Button]
private void AutoFixAreaTransforms()
{
areas.ForEach(area =>
{
var position = area.transform.localPosition;
position.x = Mathf.RoundToInt(position.x / Area.Size) * (int)Area.Size;
position.y = Mathf.RoundToInt(position.y / Area.Size) * (int)Area.Size;
position.z = Mathf.RoundToInt(position.z / Area.Size) * (int)Area.Size;
area.transform.localPosition = position;
});
}
[ResponsiveButtonGroup("AutoFix")]
[Button]
private void AutoFixAreaHierarchy()
{
var areasGameObject = GetGameObjectForAreas();
GetComponentsInChildren()
.ForEach(area => area.gameObject.transform.parent = areasGameObject.transform);
}
#endif
}
}