Files
XericLibrary-Publish/Runtime/HorizonLineOrbit/SesothoArrangementWiresTool.cs
2025-04-10 15:32:00 +08:00

559 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
/// <summary>
/// 线路绘制工具类
/// </summary>
public class SesothoArrangementWiresTool : DecisionMakerToolBase
{
#region
/// <summary>
/// 工具中成员变更委托
/// </summary>
public delegate void ToolMemberChange(PlacementBase obj);
/// <summary>
/// 工具中成员添加事件
/// </summary>
public event ToolMemberChange OnAdditional;
/// <summary>
/// 工具中成员移除事件
/// </summary>
public event ToolMemberChange OnDecreasing;
/// <summary>
/// 当任意元素苏醒
/// </summary>
public event ToolMemberChange OnAnyVivification;
/// <summary>
/// 当任意元素休眠
/// </summary>
public event ToolMemberChange OnAnyDormancy;
#endregion
#region
/*
* 1 控制强制直线
* 2,3 控制圆弧的角度为90和180度
* R 反转圆弧
* shift+b 忽略对象吸附
* shift+n 忽略网格吸附
*/
/// <summary>
/// 强制直线
/// </summary>
public static KeyPack OpKey_ForceStr = new KeyPack(KeyCode.Alpha1);
/// <summary>
/// 强制90度圆弧
/// </summary>
public static KeyPack OpKey_90Arc = new KeyPack(KeyCode.Alpha2);
/// <summary>
/// 强制180度圆弧
/// </summary>
public static KeyPack OpKey_180Arc = new KeyPack(KeyCode.Alpha3);
/// <summary>
/// 反转顺向,比如单圆弧的方向翻转。
/// 话说shift+alt+r是英伟达的一个快捷键呢有点冲突
/// </summary>
public static KeyPack OpKey_RevCisoid = new KeyPack(KeyCode.R);
/// <summary>
/// 忽略吸附功能
/// </summary>
public static KeyPack OpKey_IgnoreNeighborAdsorption = new KeyPack(KeyCode.LeftShift, KeyCode.B);
/// <summary>
/// 忽略网格吸附
/// </summary>
public static KeyPack OpKey_IgnoreGridAdsorption = new KeyPack(KeyCode.LeftShift, KeyCode.N);
#endregion
#region
private ObjectPool<TerminalLine2T3> _linePool;
private ObjectPool<TerminalPoint> _pointPool;
#endregion
#region
/// <summary>
/// 获取光标下最近的对象为点
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取光标下最近的对象为线
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取以给定点上与最近的相切线相对
/// </summary>
/// <param name="point"></param>
/// <param name="line"></param>
/// <param name="normal"></param>
/// <returns></returns>
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<TerminalLine2T3>(
createFunc: CreatElement<TerminalLine2T3>,
actionOnGet: ElementActive,
actionOnRelease: ElementInactive,
actionOnDestroy: a =>
{ },
collectionCheck: true,
defaultCapacity: 10,
maxSize: 10000);
_pointPool = new ObjectPool<TerminalPoint>(
createFunc: CreatElement<TerminalPoint>,
actionOnGet: ElementActive,
actionOnRelease: ElementInactive,
actionOnDestroy: a =>
{ },
collectionCheck: true,
defaultCapacity: 10,
maxSize: 10000);
}
protected override void OnEnableTool()
{
// 启用时创建一个输入等待行为,随后进入绘制行为
var target = GenerateOperateSlot<WaitForUserInput_OpSlot>();
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<SerializeUnion>();
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
/// <summary>
/// 创建元素
/// </summary>
/// <returns></returns>
private T CreatElement<T>()
where T : PlacementBase, ILinkconfidentPe
{
var obj = CreatPlacementObject<T>();
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;
}
/// <summary>
/// 池对象激活
/// </summary>
/// <param name="obj"></param>
/// <typeparam name="T"></typeparam>
private void ElementActive<T>(T obj)
where T : PlacementBase, ILinkconfidentPe
{
obj.gameObject.SetActive(true);
OnAnyVivification?.Invoke(obj);
}
/// <summary>
/// 池对象取消激活
/// </summary>
/// <param name="obj"></param>
/// <typeparam name="T"></typeparam>
private void ElementInactive<T>(T obj)
where T : PlacementBase, ILinkconfidentPe
{
obj.gameObject.SetActive(false);
OnAnyDormancy?.Invoke(obj);
}
/// <summary>
/// 获取元素
/// </summary>
/// <returns></returns>
public bool GetElement<T>(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;
}
/// <summary>
/// 获取元素
/// </summary>
/// <param name="type"></param>
/// <param name="obj"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 删除元素
/// </summary>
/// <param name="obj"></param>
/// <typeparam name="T"></typeparam>
public void DeleteElement<T>(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;
}
}
/// <summary>
/// 保存元素链,在创建并常态化元素后都需要执行的操作 (注意不是在创建后立刻保存)
/// <code>
/// 如果这是一个线,那么还应该调用 AddBulkLineToNeighborGrid;
/// 如果这是一个点,那么应该调用 AddPeToNeighborGrid。
/// </code>
/// </summary>
public void PersistentElement<T>(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
// 保存链表结构,反过来也持有这个节点,便于后续查找
var lineNode = SesothoPeManager.Inst.AddLinkedTarget(obj);
obj.SetLinkedNode(lineNode);
}
/// <summary>
/// 移除元素链
/// </summary>
/// <param name="obj"></param>
/// <typeparam name="T"></typeparam>
public void ExcisionElement<T>(T obj)
where T : PlacementBase,
ILinkconfidentPe
{
if (obj.GetLinkedNode(out var node))
SesothoPeManager.Inst.RemoveLinkedTarget(node);
}
/// <summary>
/// 添加小型元素到网格中
/// </summary>
/// <param name="obj"></param>
/// <typeparam name="T"></typeparam>
public void AddPeToNeighborGrid<T>(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);
}
/// <summary>
/// 添加大型元素到网格中
/// </summary>
public void AddBulkPeToNeighborGrid<T>(T obj)
where T : PlacementBase,
ILinkconfidentPe,
IPossessorTrajectory2
{
if (obj.NeighborGridIndex != null)
{
Debug.LogError("无法重复插入元素:当前向管理器中插入的的元素,可能已经存在于其他管理器内,请先退出其他管理器后重试。");
return;
}
SesothoPeManager.Inst.InsertGiantNeighbor<T>(obj, out var index);
obj.NeighborGridIndex = index;
// 回调事件
OnAdditional?.Invoke(obj);
}
/// <summary>
/// 移除这个小元素
/// </summary>
/// <param name="obj"></param>
/// <typeparam name="T"></typeparam>
public void RemovePeToNeighborGrid<T>(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);
}
/// <summary>
/// 移除这个大型元素
/// </summary>
public void RemoveBulkPeFormNeighborGrid<T>(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<T>(obj);
ExcisionElement(obj);
// 回调事件
OnDecreasing?.Invoke(obj);
}
#endregion
#region
/*
* 没写完如果不嫌麻烦可以看看Astart类或者自己实现。
*
* 主要提供绘制线路时的多段线拟合,障碍物避让
*/
/// <summary>
/// 获取一个可以通过的路径
/// <code>
/// 这是一个只在向上的二维平面上有效的路径。
/// 寻路的规则是仅避开建筑物,贪婪算法。
/// </code>
/// </summary>
/// <param name="startPoint">起点</param>
/// <param name="endPoint">终点</param>
/// <param name="avoidRadius">避让半径,在遭遇碰撞时将沿法向退回这个距离</param>
public DrawWayPoints GetPassThroughRouteShortcut(Vector3 startPoint, Vector3 endPoint, float avoidRadius)
{
var result = new DrawWayPoints();
Debug.LogError("此方法未完成");
return result;
}
/// <summary>
/// 获取一个可以通过的路径的迭代器;
/// </summary>
/// <param name="startPoint">起点</param>
/// <param name="endPoint">终点</param>
/// <param name="avoidRadius">避让半径,在遭遇障碍时将沿法向退回这个距离</param>
/// <param name="layer">检查碰撞对象的层</param>
/// <returns></returns>
protected IEnumerable<Vector3> GetPassThroughRoute(Vector3 startPoint, Vector3 endPoint, float avoidRadius, LayerMask layer)
{
yield return Vector3.zero;
}
/// <summary>
/// 使用给定的路径创建一段工具拟合的路径
/// </summary>
/// <param name="wayPoints">一段路径</param>
public void BuildPaths(DrawWayPoints wayPoints)
{
new AStart2();
}
#endregion
}
}