LethalCompany/Lethal Company/ExportedProject/Assets/Scripts/Assembly-CSharp/DunGen/Adapters/UnityNavMeshAdapter.cs

199 lines
5.7 KiB
C#
Raw Permalink Normal View History

2023-12-22 22:51:17 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEngine.AI;
namespace DunGen.Adapters
{
[AddComponentMenu("DunGen/NavMesh/Unity NavMesh Adapter")]
public class UnityNavMeshAdapter : NavMeshAdapter
{
public enum RuntimeNavMeshBakeMode
{
PreBakedOnly = 0,
AddIfNoSurfaceExists = 1,
AlwaysRebake = 2,
FullDungeonBake = 3
}
[Serializable]
public sealed class NavMeshAgentLinkInfo
{
public int AgentTypeID;
public int AreaTypeID;
public bool DisableLinkWhenDoorIsClosed = true;
}
public RuntimeNavMeshBakeMode BakeMode = RuntimeNavMeshBakeMode.AddIfNoSurfaceExists;
public LayerMask LayerMask = -1;
public bool AddNavMeshLinksBetweenRooms = true;
public List<NavMeshAgentLinkInfo> NavMeshAgentTypes = new List<NavMeshAgentLinkInfo>
{
new NavMeshAgentLinkInfo()
};
public float NavMeshLinkDistanceFromDoorway = 2.5f;
public bool AutoGenerateFullRebakeSurfaces = true;
public List<NavMeshSurface> FullRebakeTargets = new List<NavMeshSurface>();
private List<NavMeshSurface> addedSurfaces = new List<NavMeshSurface>();
private List<NavMeshSurface> fullBakeSurfaces = new List<NavMeshSurface>();
public override void Generate(Dungeon dungeon)
{
if (BakeMode == RuntimeNavMeshBakeMode.FullDungeonBake)
{
BakeFullDungeon(dungeon);
return;
}
if (BakeMode != 0)
{
foreach (Tile allTile in dungeon.AllTiles)
{
NavMeshSurface[] componentsInChildren = allTile.gameObject.GetComponentsInChildren<NavMeshSurface>();
IEnumerable<NavMeshSurface> enumerable = AddMissingSurfaces(allTile, componentsInChildren);
if (BakeMode == RuntimeNavMeshBakeMode.AlwaysRebake)
{
enumerable = enumerable.Concat(componentsInChildren);
}
else if (BakeMode == RuntimeNavMeshBakeMode.AddIfNoSurfaceExists)
{
IEnumerable<NavMeshSurface> second = componentsInChildren.Where((NavMeshSurface x) => x.navMeshData == null);
enumerable = enumerable.Concat(second);
}
foreach (NavMeshSurface item in enumerable.Distinct())
{
item.BuildNavMesh();
}
}
}
if (AddNavMeshLinksBetweenRooms)
{
foreach (DoorwayConnection connection in dungeon.Connections)
{
foreach (NavMeshAgentLinkInfo navMeshAgentType in NavMeshAgentTypes)
{
AddNavMeshLink(connection, navMeshAgentType);
}
}
}
if (OnProgress != null)
{
OnProgress(new NavMeshGenerationProgress
{
Description = "Done",
Percentage = 1f
});
}
}
private void BakeFullDungeon(Dungeon dungeon)
{
if (AutoGenerateFullRebakeSurfaces)
{
foreach (NavMeshSurface fullBakeSurface in fullBakeSurfaces)
{
if (fullBakeSurface != null)
{
fullBakeSurface.RemoveData();
}
}
fullBakeSurfaces.Clear();
int settingsCount = NavMesh.GetSettingsCount();
for (int i = 0; i < settingsCount; i++)
{
NavMeshBuildSettings settings = NavMesh.GetSettingsByIndex(i);
NavMeshSurface navMeshSurface = (from s in dungeon.gameObject.GetComponents<NavMeshSurface>()
where s.agentTypeID == settings.agentTypeID
select s).FirstOrDefault();
if (navMeshSurface == null)
{
navMeshSurface = dungeon.gameObject.AddComponent<NavMeshSurface>();
navMeshSurface.agentTypeID = settings.agentTypeID;
navMeshSurface.collectObjects = CollectObjects.Children;
navMeshSurface.layerMask = LayerMask;
}
fullBakeSurfaces.Add(navMeshSurface);
navMeshSurface.BuildNavMesh();
}
}
else
{
foreach (NavMeshSurface fullRebakeTarget in FullRebakeTargets)
{
fullRebakeTarget.BuildNavMesh();
}
}
if (OnProgress != null)
{
OnProgress(new NavMeshGenerationProgress
{
Description = "Done",
Percentage = 1f
});
}
}
private NavMeshSurface[] AddMissingSurfaces(Tile tile, NavMeshSurface[] existingSurfaces)
{
addedSurfaces.Clear();
int settingsCount = NavMesh.GetSettingsCount();
for (int i = 0; i < settingsCount; i++)
{
NavMeshBuildSettings settings = NavMesh.GetSettingsByIndex(i);
if (!existingSurfaces.Where((NavMeshSurface x) => x.agentTypeID == settings.agentTypeID).Any())
{
NavMeshSurface navMeshSurface = tile.gameObject.AddComponent<NavMeshSurface>();
navMeshSurface.agentTypeID = settings.agentTypeID;
navMeshSurface.collectObjects = CollectObjects.Children;
navMeshSurface.layerMask = LayerMask;
addedSurfaces.Add(navMeshSurface);
}
}
return addedSurfaces.ToArray();
}
private void AddNavMeshLink(DoorwayConnection connection, NavMeshAgentLinkInfo agentLinkInfo)
{
GameObject gameObject = connection.A.gameObject;
NavMeshBuildSettings settingsByID = NavMesh.GetSettingsByID(agentLinkInfo.AgentTypeID);
float width = Mathf.Max(connection.A.Socket.Size.x - settingsByID.agentRadius * 2f, 0.01f);
NavMeshLink link = gameObject.AddComponent<NavMeshLink>();
link.agentTypeID = agentLinkInfo.AgentTypeID;
link.bidirectional = true;
link.area = agentLinkInfo.AreaTypeID;
link.startPoint = new Vector3(0f, 0f, 0f - NavMeshLinkDistanceFromDoorway);
link.endPoint = new Vector3(0f, 0f, NavMeshLinkDistanceFromDoorway);
link.width = width;
if (!agentLinkInfo.DisableLinkWhenDoorIsClosed)
{
return;
}
GameObject gameObject2 = ((connection.A.UsedDoorPrefabInstance != null) ? connection.A.UsedDoorPrefabInstance : ((connection.B.UsedDoorPrefabInstance != null) ? connection.B.UsedDoorPrefabInstance : null));
if (!(gameObject2 != null))
{
return;
}
Door component = gameObject2.GetComponent<Door>();
link.enabled = component.IsOpen;
if (component != null)
{
component.OnDoorStateChanged += delegate(Door d, bool o)
{
link.enabled = o;
};
}
}
}
}