using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Deconstruction.Element;
using Deconstruction.Interface;
using Deconstruction.Manager;
using Deconstruction.Tool;
using Deconstruction.Type;
using Deconstruction.Type.DMToolSlot;
using Deconstruction.Type.Linkable;
using SerializerHelper.Type;
using UnityEngine;
using UnityEngine.Pool;
using XericLibrary.Runtime.MacroLibrary;
using XericLibrary.Runtime.Nav;
namespace SesothoLine
{
///
/// 线路绘制工具类
///
public class SesothoArrangementWiresTool : DecisionMakerToolBase
{
#region 事件委托
///
/// 工具中成员变更委托
///
public delegate void ToolMemberChange(PlacementBase obj);
///
/// 工具中成员添加事件
///
public event ToolMemberChange OnAdditional;
///
/// 工具中成员移除事件
///
public event ToolMemberChange OnDecreasing;
///
/// 当任意元素苏醒
///
public event ToolMemberChange OnAnyVivification;
///
/// 当任意元素休眠
///
public event ToolMemberChange OnAnyDormancy;
#endregion
#region 快捷键
/*
* 1 控制强制直线
* 2,3 控制圆弧的角度为90和180度
* R 反转圆弧
* shift+b 忽略对象吸附
* shift+n 忽略网格吸附
*/
///
/// 强制直线
///
public static KeyPack OpKey_ForceStr = new KeyPack(KeyCode.Alpha1);
///
/// 强制90度圆弧
///
public static KeyPack OpKey_90Arc = new KeyPack(KeyCode.Alpha2);
///
/// 强制180度圆弧
///
public static KeyPack OpKey_180Arc = new KeyPack(KeyCode.Alpha3);
///
/// 反转顺向,比如单圆弧的方向翻转。
/// 话说shift+alt+r是英伟达的一个快捷键呢,有点冲突
///
public static KeyPack OpKey_RevCisoid = new KeyPack(KeyCode.R);
///
/// 忽略吸附功能
///
public static KeyPack OpKey_IgnoreNeighborAdsorption = new KeyPack(KeyCode.LeftShift, KeyCode.B);
///
/// 忽略网格吸附
///
public static KeyPack OpKey_IgnoreGridAdsorption = new KeyPack(KeyCode.LeftShift, KeyCode.N);
#endregion
#region 字段属性
private ObjectPool _linePool;
private ObjectPool _pointPool;
#endregion
#region 获取转换
///
/// 获取光标下最近的对象为点
///
///
///
public static bool GetNearestObjectAsPoint(out TerminalPoint point)
{
if (SesothoPeManager.NearestObject is not null &&
SesothoPeManager.NearestObject is TerminalPoint terminalPoint)
{
point = terminalPoint;
return true;
}
point = null;
return false;
}
///
/// 获取光标下最近的对象为线
///
///
///
public static bool GetNearestObjectAsLine(out TerminalLine2T3 line)
{
if (SesothoPeManager.NearestObject is not null &&
SesothoPeManager.NearestObject is TerminalPoint terminalPoint &&
terminalPoint.LinkedData.GetOpposite(LinkType.Export) is TerminalLine2T3 terminalLine)
{
line = terminalLine;
return true;
}
line = null;
return false;
}
///
/// 获取以给定点上与最近的相切线相对
///
///
///
///
///
public static bool GetNearestObjectAsLine(TerminalPoint point, out TerminalLine2T3 line, out Vector3 normal)
{
if (point is null)
goto End;
// 检查最近线切线是否有效,是否相连
if (SesothoPeManager.NearestLineTangentObject is TerminalLine2T3 otherLine &&
point.TryGetLinkLineNormal(otherLine, out normal))
{
line = otherLine;
return true;
}
End:
line = null;
normal = default;
return false;
}
#endregion
#region 生命周期
protected override void Awake()
{
base.Awake();
_linePool = new ObjectPool(
createFunc: CreatElement,
actionOnGet: ElementActive,
actionOnRelease: ElementInactive,
actionOnDestroy: a =>
{ },
collectionCheck: true,
defaultCapacity: 10,
maxSize: 10000);
_pointPool = new ObjectPool(
createFunc: CreatElement,
actionOnGet: ElementActive,
actionOnRelease: ElementInactive,
actionOnDestroy: a =>
{ },
collectionCheck: true,
defaultCapacity: 10,
maxSize: 10000);
}
protected override void OnEnableTool()
{
// 启用时创建一个输入等待行为,随后进入绘制行为
var target = GenerateOperateSlot();
target.InitializeNextTodo(() => new DrawTerminalLine2T3_OpSlot());
Debug.Log("激活线路绘制工具");
}
protected override void OnDisableTool()
{
}
protected override void OnFinalEnd()
{
base.OnFinalEnd();
EnableTool = false;
}
#endregion
#region 序列化
public override SerializeUnion ToolSerializeDispost()
{
base.ToolSerializeDispost();
foreach (var element in PlaceElementManager.Inst.StructuralLinkedList)
{
var union = element.SerializedOccurs();
// 索引是后面用来标识类的
union.Index = TypeConsignMap.AddMapIndex(element.GetType());
union.RefreshSerializedContext();
SerializeTemp.Add(union);
}
SerializeTemp.RefreshSerializedContext();
return SerializeTemp;
}
public override bool ToolDiserializDispost(SerializeUnion context)
{
if (!base.ToolDiserializDispost(context))
return false;
var deserializeList = new List<(PlacementBase, SerializeUnion)>();
var safeCount = ushort.MaxValue;
Debug.Log("反序列化过程开始创建对象");
while (0 <-- safeCount && SerializeTemp.IndexMoveToNext(out var block))
{
var union = SerializeTemp.GetDeserializeObject();
var type = TypeConsignMap.GetMapType(union.Index);
if (GetElement(type, out var obj))
{
deserializeList.Add((obj, union));
union.RefreshDeserializeContext();
union.IndexMoveToStart();
obj.DeserializeOccurs(union);
// switch (obj)
// {
// case TerminalLine2T3 line:
// line.DeserializeOccurs(union);
// break;
// case TerminalPoint point:
// point.DeserializeOccurs(union);
// break;
// }
}
else
Debug.LogError($"无法创建序列化元素,原因是类型不支持{type}");
if (block) break;
}
Debug.Log("反序列化过程开始恢复链接关系");
foreach (var item in deserializeList)
item.Item1.DeserializeHysteresisOccurs(item.Item2);
return true;
}
#endregion
#region 方法
///
/// 创建元素
///
///
private T CreatElement()
where T : PlacementBase, ILinkconfidentPe
{
var obj = CreatPlacementObject();
obj.OnPlancementDestory += a =>
{
if (a is null)
{
Debug.LogError("元素已经被销毁,无法回收链表元素");
return;
}
if (a is T b &&
b.GetLinkedNode(out var node))
SesothoPeManager.Inst.RemoveLinkedTarget(node);
else
Debug.LogError("元素并非工具元素类型,或者其中的链表节点已丢失,导致无法回收链表元素");
};
return obj;
}
///
/// 池对象激活
///
///
///
private void ElementActive(T obj)
where T : PlacementBase, ILinkconfidentPe
{
obj.gameObject.SetActive(true);
OnAnyVivification?.Invoke(obj);
}
///
/// 池对象取消激活
///
///
///
private void ElementInactive(T obj)
where T : PlacementBase, ILinkconfidentPe
{
obj.gameObject.SetActive(false);
OnAnyDormancy?.Invoke(obj);
}
///
/// 获取元素
///
///
public bool GetElement(out T obj)
where T : PlacementBase, ILinkconfidentPe
{
var name = typeof(T).Name;
switch (name)
{
case nameof(TerminalLine2T3):
obj = _linePool.Get() as T;
return true;
case nameof(TerminalPoint):
obj = _pointPool.Get() as T;
return true;
default:
Debug.LogError($"给定的元素类型({name})并非预期,这将跳过对象池过程");
break;
}
obj = null;
return false;
}
///
/// 获取元素
///
///
///
///
public bool GetElement(Type type, out PlacementBase obj)
{
var name = type.Name;
switch (name)
{
case nameof(TerminalLine2T3):
obj = _linePool.Get();
return true;
case nameof(TerminalPoint):
obj = _pointPool.Get();
return true;
default:
Debug.LogError($"给定的元素类型({name})并非预期,这将跳过对象池过程");
break;
}
obj = null;
return false;
}
///
/// 删除元素
///
///
///
public void DeleteElement(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
var name = typeof(T).Name;
switch (name)
{
case nameof(TerminalLine2T3):
_linePool.Release(obj as TerminalLine2T3);
break;
case nameof(TerminalPoint):
_pointPool.Release(obj as TerminalPoint);
break;
default:
Debug.LogError($"给定的元素类型({name})并非预期,这将跳过对象池过程");
break;
}
}
///
/// 保存元素链,在创建并常态化元素后都需要执行的操作 (注意不是在创建后立刻保存)
///
/// 如果这是一个线,那么还应该调用 AddBulkLineToNeighborGrid;
/// 如果这是一个点,那么应该调用 AddPeToNeighborGrid。
///
///
public void PersistentElement(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
// 保存链表结构,反过来也持有这个节点,便于后续查找
var lineNode = SesothoPeManager.Inst.AddLinkedTarget(obj);
obj.SetLinkedNode(lineNode);
}
///
/// 移除元素链
///
///
///
public void ExcisionElement(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
if (obj.GetLinkedNode(out var node))
SesothoPeManager.Inst.RemoveLinkedTarget(node);
}
///
/// 添加小型元素到网格中
///
///
///
public void AddPeToNeighborGrid(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
if (obj.NeighborGridIndex != null)
{
Debug.LogError("无法重复插入元素:当前向管理器中插入的的元素,可能已经存在于其他管理器内,请先退出其他管理器后重试。");
return;
}
SesothoPeManager.Inst.InsertNeighbor(obj, out var index);
obj.NeighborGridIndex = index;
// 回调事件
OnAdditional?.Invoke(obj);
}
///
/// 添加大型元素到网格中
///
public void AddBulkPeToNeighborGrid(T obj)
where T : PlacementBase,
ILinkconfidentPe,
IPossessorTrajectory2
{
if (obj.NeighborGridIndex != null)
{
Debug.LogError("无法重复插入元素:当前向管理器中插入的的元素,可能已经存在于其他管理器内,请先退出其他管理器后重试。");
return;
}
SesothoPeManager.Inst.InsertGiantNeighbor(obj, out var index);
obj.NeighborGridIndex = index;
// 回调事件
OnAdditional?.Invoke(obj);
}
///
/// 移除这个小元素
///
///
///
public void RemovePeToNeighborGrid(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
if (obj.NeighborGridIndex != null &&
obj.NeighborGridIndex.GetAsIndex(out var index))
SesothoPeManager.Inst.RemoveNeighbor(index);
else
SesothoPeManager.Inst.RemoveNeighbor(obj);
ExcisionElement(obj);
// 回调事件
OnDecreasing?.Invoke(obj);
}
///
/// 移除这个大型元素
///
public void RemoveBulkPeFormNeighborGrid(T obj)
where T : PlacementBase,
ILinkconfidentPe,
IPossessorTrajectory2
{
if (obj.NeighborGridIndex != null &&
obj.NeighborGridIndex.GetAsMappingIndex(out var index))
SesothoPeManager.Inst.RemoveGiantNeighbor(index);
else
SesothoPeManager.Inst.RemoveGiantNeighbor(obj);
ExcisionElement(obj);
// 回调事件
OnDecreasing?.Invoke(obj);
}
#endregion
#region 绘制寻路
/*
* 没写完,如果不嫌麻烦可以看看Astart类,或者自己实现。
*
* 主要提供绘制线路时的多段线拟合,障碍物避让
*/
///
/// 获取一个可以通过的路径
///
/// 这是一个只在向上的二维平面上有效的路径。
/// 寻路的规则是仅避开建筑物,贪婪算法。
///
///
/// 起点
/// 终点
/// 避让半径,在遭遇碰撞时将沿法向退回这个距离
public DrawWayPoints GetPassThroughRouteShortcut(Vector3 startPoint, Vector3 endPoint, float avoidRadius)
{
var result = new DrawWayPoints();
Debug.LogError("此方法未完成");
return result;
}
///
/// 获取一个可以通过的路径的迭代器;
///
/// 起点
/// 终点
/// 避让半径,在遭遇障碍时将沿法向退回这个距离
/// 检查碰撞对象的层
///
protected IEnumerable GetPassThroughRoute(Vector3 startPoint, Vector3 endPoint, float avoidRadius, LayerMask layer)
{
yield return Vector3.zero;
}
///
/// 使用给定的路径创建一段工具拟合的路径
///
/// 一段路径
public void BuildPaths(DrawWayPoints wayPoints)
{
new AStart2();
}
#endregion
}
}