2024-11-19 11:48:21 +01:00

1616 lines
55 KiB
C#

#region "Imports"
using UnityEngine;
using System.Collections.Generic;
using RoadArchitect;
#endregion
namespace RoadArchitect
{
[ExecuteInEditMode]
public class Road : MonoBehaviour
{
public enum RoadMaterialDropdownEnum
{
Asphalt,
Dirt,
Brick,
Cobblestone
};
#region "Vars"
public GameObject MainMeshes;
public GameObject MeshRoad;
public GameObject MeshShoR;
public GameObject MeshShoL;
public GameObject MeshiLanes;
public GameObject MeshiLanes0;
public GameObject MeshiLanes1;
public GameObject MeshiLanes2;
public GameObject MeshiLanes3;
public GameObject MeshiMainPlates;
public GameObject MeshiMarkerPlates;
[System.NonSerialized]
public string editorTitleString = "";
public SplineC spline;
public int MostRecentNodeCount = -1;
public GameObject splineObject;
public RoadSystem roadSystem;
public SplineC[] PiggyBacks = null;
public bool isEditorProgressBar = false;
//Unique ID
public string UID;
[SerializeField]
public List<TerrainHistoryMaker> TerrainHistory;
public string TerrainHistoryByteSize = "";
[System.NonSerialized]
public bool isUpdatingSpline = false;
//Road editor options:
public float laneWidth = 5f;
public bool isShouldersEnabled = true;
public float shoulderWidth = 3f;
public int laneAmount = 2;
public float roadDefinition = 5f;
public bool roadCornerDefinition = false;
public bool isRoadCutsEnabled = true;
public bool isShoulderCutsEnabled = true;
public bool isDynamicCutsEnabled = false;
public bool isMaxGradeEnabled = true;
public float maxGrade = 0.08f;
public bool isUsingDefaultMaterials = true;
public bool isAutoUpdatingInEditor = true;
public float matchTerrainSubtraction = 0.1f;
public bool isRaisingRoad = false;
/// <summary> Defines the width of height modification in meters </summary>
public float matchHeightsDistance = 50f;
public float clearDetailsDistance = 30f;
public float clearDetailsDistanceHeight = 5f;
public float clearTreesDistance = 30f;
public float clearTreesDistanceHeight = 50f;
public bool isHeightModificationEnabled = true;
public bool isDetailModificationEnabled = true;
public bool isTreeModificationEnabled = true;
public bool isSavingTerrainHistoryOnDisk = true;
public float magnitudeThreshold = 300f;
public bool isGizmosEnabled = true;
public bool isUsingMultithreading = true;
public bool isSavingMeshes = false;
public bool isUsingMeshColliders = true;
public bool isStatic = false;
public bool isLightmapped = false;
public float desiredRampHeight = 0.35f;
public RoadMaterialDropdownEnum roadMaterialDropdown = RoadMaterialDropdownEnum.Asphalt;
public RoadMaterialDropdownEnum tRoadMaterialDropdownOLD = RoadMaterialDropdownEnum.Asphalt;
public Material RoadMaterial1;
public Material RoadMaterial2;
public Material RoadMaterial3;
public Material RoadMaterial4;
public Material RoadMaterialMarker1;
public Material RoadMaterialMarker2;
public Material RoadMaterialMarker3;
public Material RoadMaterialMarker4;
public Material ShoulderMaterial1;
public Material ShoulderMaterial2;
public Material ShoulderMaterial3;
public Material ShoulderMaterial4;
public Material ShoulderMaterialMarker1;
public Material ShoulderMaterialMarker2;
public Material ShoulderMaterialMarker3;
public Material ShoulderMaterialMarker4;
public PhysicMaterial RoadPhysicMaterial;
public PhysicMaterial ShoulderPhysicMaterial;
#endregion
#region "Road Construction"
#region "Vars"
[System.NonSerialized]
public Threading.TerrainCalcs TerrainCalcsJob;
[System.NonSerialized]
public Threading.RoadCalcs1 RoadCalcsJob1;
[System.NonSerialized]
public Threading.RoadCalcs2 RoadCalcsJob2;
[System.NonSerialized]
public RoadConstructorBufferMaker RCS;
public string roadName = "";
public bool isProfiling = false;
public bool isSkippingStore = true;
[System.NonSerialized]
public float EditorConstructionStartTime = 0f;
public bool isEditorError = false;
public System.Exception exceptionError = null;
private int editorTimer = 0;
private int editorTimerMax = 0;
private int editorTimerSpline = 0;
private const int editorTimerSplineMax = 2;
[System.NonSerialized]
public int editorProgress = 0;
private const int gizmoNodeTimerMax = 2;
public bool isUpdateRequired = false;
public bool isTriggeringGC = false;
private bool isTriggeredGCExecuting;
private float triggerGCEnd = 0f;
[System.NonSerialized]
public bool isEditorCameraMoving = false;
[System.NonSerialized]
public float EditorCameraPos = 0f;
private const float EditorCameraTimeUpdateInterval = 0.015f;
private float EditorCameraNextMove = 0f;
private bool isEditorCameraSetup = false;
private float EditorCameraStartPos = 0f;
private float EditorCameraEndPos = 1f;
private float EditorCameraIncrementDistance = 0f;
private float EditorCameraIncrementDistance_Full = 0f;
public float EditorCameraMetersPerSecond = 60f;
public bool isEditorCameraRotated = false;
private Vector3 EditorCameraV1 = default(Vector3);
private Vector3 EditorCameraV2 = default(Vector3);
[System.NonSerialized]
public Vector3 editorCameraOffset = new Vector3(0f, 5f, 0f);
[System.NonSerialized]
public Camera editorPlayCamera = null;
private Vector3 editorCameraBadVec = default(Vector3);
public List<Terraforming.TempTerrainData> EditorTTDList;
public bool isEditorConstructing = false;
public int editorConstructionID = 0;
public bool isEditorSelected = false;
public bool isEditorMouseHittingTerrain = false;
public Vector3 editorMousePos = new Vector3(0f, 0f, 0f);
public Color defaultNodeColor = new Color(0f, 1f, 1f, 0.75f);
/// <summary> Connection node color </summary>
public readonly Color Color_NodeConnColor = new Color(0f, 1f, 0f, 0.75f);
/// <summary> The color of the nodes when they are selected </summary>
public Color selectedColor = Color.yellow;
/// <summary> Color of the node preview when adding a new node </summary>
public Color newNodePreviewColor = Color.red;
#endregion
/// <summary> Make sure unused items are not using memory space in runtime </summary>
private void CleanRunTime()
{
TerrainHistory = null;
RCS = null;
}
private void OnEnable()
{
#if UNITY_EDITOR
isEditorConstructing = false;
UnityEditor.EditorApplication.update += delegate
{
EditorUpdate();
};
#if UNITY_2018_1_OR_NEWER
UnityEditor.EditorApplication.hierarchyChanged += delegate
{
HierarchyWindowChanged();
};
#else
UnityEditor.EditorApplication.hierarchyWindowChanged += delegate { HierarchyWindowChanged(); };
#endif
if (spline == null || spline.nodes == null)
{
MostRecentNodeCount = 0;
}
else
{
MostRecentNodeCount = spline.GetNodeCount();
}
tRoadMaterialDropdownOLD = roadMaterialDropdown;
CheckMats();
#endif
}
public void Awake()
{
if (spline == null || spline.nodes == null)
{
MostRecentNodeCount = 0;
}
else
{
MostRecentNodeCount = spline.GetNodeCount();
}
}
private void EditorUpdate()
{
#if UNITY_EDITOR
if (this == null)
{
UnityEditor.EditorApplication.update -= delegate
{
EditorUpdate();
};
isEditorConstructing = false;
EngineIntegration.ClearProgressBar();
return;
}
#endif
//Custom garbage collection demands for editor:
if (isTriggeringGC)
{
isTriggeringGC = false;
triggerGCEnd = Time.realtimeSinceStartup + 1f;
isTriggeredGCExecuting = true;
}
if (isTriggeredGCExecuting)
{
if (Time.realtimeSinceStartup > triggerGCEnd)
{
isTriggeredGCExecuting = false;
RootUtils.ForceCollection();
triggerGCEnd = 200000f;
}
}
if (isEditorConstructing)
{
if (isUsingMultithreading)
{
editorTimer += 1;
if (editorTimer > editorTimerMax)
{
if ((Time.realtimeSinceStartup - EditorConstructionStartTime) > 180f)
{
isEditorConstructing = false;
EngineIntegration.ClearProgressBar();
Debug.Log("Update shouldn't take longer than 180 seconds. Aborting update.");
}
editorTimer = 0;
if (isEditorError)
{
isEditorConstructing = false;
EngineIntegration.ClearProgressBar();
isEditorError = false;
if (exceptionError != null)
{
Debug.LogError(exceptionError.StackTrace);
throw exceptionError;
}
}
if (TerrainCalcsJob != null && TerrainCalcsJob.Update())
{
ConstructRoad2();
}
else if (RoadCalcsJob1 != null && RoadCalcsJob1.Update())
{
ConstructRoad3();
}
else if (RoadCalcsJob2 != null && RoadCalcsJob2.Update())
{
ConstructRoad4();
}
}
}
}
else
{
if (isUpdateRequired)
{
isUpdateRequired = false;
spline.TriggerSetup();
}
}
if (isEditorConstructing || isEditorProgressBar)
{
RoadUpdateProgressBar();
}
#if UNITY_EDITOR
if (!Application.isPlaying && isUpdatingSpline)
{
editorTimerSpline += 1;
if (editorTimerSpline > editorTimerSplineMax)
{
editorTimerSpline = 0;
isUpdatingSpline = false;
spline.TriggerSetup();
MostRecentNodeCount = spline.nodes.Count;
}
}
if (isEditorCameraMoving && EditorCameraNextMove < UnityEditor.EditorApplication.timeSinceStartup)
{
EditorCameraNextMove = (float)UnityEditor.EditorApplication.timeSinceStartup + EditorCameraTimeUpdateInterval;
DoEditorCameraLoop();
}
#endif
}
public void DoEditorCameraLoop()
{
if (!isEditorCameraSetup)
{
isEditorCameraSetup = true;
if (spline.isSpecialEndControlNode)
{
//If control node, start after the control node:
EditorCameraEndPos = spline.nodes[spline.GetNodeCount() - 2].time;
}
if (spline.isSpecialStartControlNode)
{
//If ends in control node, end construction before the control node:
EditorCameraStartPos = spline.nodes[1].time;
}
ChangeEditorCameraMetersPerSec();
}
#if UNITY_EDITOR
if (!UnityEditor.Selection.Contains(this.transform.gameObject))
{
QuitEditorCamera();
return;
}
#endif
//EditorCameraPos_Full+=EditorCameraIncrementDistance_Full;
//if(EditorCameraPos_Full > spline.distance)
//{
// EditorCameraPos = EditorCameraStartPos;
// isEditorCameraMoving = false;
// EditorCameraPos_Full = 0f;
// return;
// }
//EditorCameraPos = spline.TranslateDistBasedToParam(EditorCameraPos_Full);
EditorCameraPos += EditorCameraIncrementDistance;
if (EditorCameraPos > EditorCameraEndPos)
{
QuitEditorCamera();
return;
}
if (EditorCameraPos < EditorCameraStartPos)
{
EditorCameraPos = EditorCameraStartPos;
}
spline.GetSplineValueBoth(EditorCameraPos, out EditorCameraV1, out EditorCameraV2);
#if UNITY_EDITOR
if (Application.isPlaying)
{
if (editorPlayCamera != null)
{
editorPlayCamera.transform.position = EditorCameraV1;
if (isEditorCameraRotated)
{
editorPlayCamera.transform.position += editorCameraOffset;
if (EditorCameraV2 != editorCameraBadVec)
{
editorPlayCamera.transform.rotation = Quaternion.LookRotation(EditorCameraV2);
}
}
}
}
else
{
UnityEditor.SceneView.lastActiveSceneView.pivot = EditorCameraV1;
if (isEditorCameraRotated)
{
UnityEditor.SceneView.lastActiveSceneView.pivot += editorCameraOffset;
if (EditorCameraV2 != editorCameraBadVec)
{
UnityEditor.SceneView.lastActiveSceneView.rotation = Quaternion.LookRotation(EditorCameraV2);
}
}
UnityEditor.SceneView.lastActiveSceneView.Repaint();
}
#endif
}
public void EditorCameraSetSingle()
{
if (editorPlayCamera == null)
{
Camera[] editorCameras = GameObject.FindObjectsOfType<Camera>();
if (editorCameras != null && editorCameras.Length == 1)
{
editorPlayCamera = editorCameras[0];
}
}
}
public void QuitEditorCamera()
{
EditorCameraPos = EditorCameraStartPos;
isEditorCameraMoving = false;
isEditorCameraSetup = false;
}
public void ChangeEditorCameraMetersPerSec()
{
EditorCameraIncrementDistance_Full = (EditorCameraMetersPerSecond / 60);
EditorCameraIncrementDistance = (EditorCameraIncrementDistance_Full / spline.distance);
}
/// <summary> This is called when the hierarchy is changed in the editor </summary>
private void HierarchyWindowChanged()
{
#if UNITY_EDITOR
#if UNITY_2018_1_OR_NEWER
UnityEditor.EditorApplication.hierarchyChanged -= delegate { HierarchyWindowChanged(); };
#else
UnityEditor.EditorApplication.hierarchyWindowChanged -= delegate { HierarchyWindowChanged(); };
#endif
#endif
if (Application.isPlaying || !Application.isEditor)
{
return;
}
#if UNITY_EDITOR
if(UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
if(UnityEditor.EditorApplication.isPlaying)
{
return;
}
#endif
int count = 0;
if (spline != null && spline.nodes != null)
{
count = spline.GetNodeCountNonNull();
}
if (count != MostRecentNodeCount)
{
isUpdatingSpline = true;
}
}
/// <summary> Display the progress of the road update </summary>
private void RoadUpdateProgressBar()
{
#if UNITY_EDITOR
if (isEditorConstructing)
{
UnityEditor.EditorUtility.DisplayProgressBar(
"RoadArchitect: Road Update",
editorTitleString,
((float)editorProgress / 100f));
}
else if (isEditorProgressBar)
{
isEditorProgressBar = false;
EngineIntegration.ClearProgressBar();
}
#endif
}
/// <summary> Starts the road update </summary>
public void UpdateRoad(RoadUpdateTypeEnum _updateType = RoadUpdateTypeEnum.Full)
{
if (!roadSystem.isAllowingRoadUpdates)
{
spline.Setup();
isEditorConstructing = false;
return;
}
if (isEditorConstructing)
{
return;
}
RootUtils.SetupUniqueIdentifier(ref UID);
RootUtils.StartProfiling(this, "UpdateRoadPrelim");
roadDefinition = Mathf.Clamp(roadDefinition, 1f, 50f);
laneWidth = Mathf.Clamp(laneWidth, 0.2f, 500f);
EditorConstructionStartTime = Time.realtimeSinceStartup;
editorTitleString = "Updating " + transform.name + "...";
System.GC.Collect();
if (isSavingTerrainHistoryOnDisk)
{
LoadTerrainHistory();
}
CheckMats();
EngineIntegration.ClearProgressBar();
isProfiling = true;
if (isUsingMultithreading)
{
isProfiling = false;
}
//Set all terrains to height 0:
Terraforming.CheckAllTerrainsHeight0();
editorProgress = 20;
isEditorProgressBar = true;
if (isEditorConstructing)
{
AbortJobs();
isEditorConstructing = false;
}
//In here for intersection patching purposes:
int nodeCount = spline.GetNodeCount();
SplineN node = null;
SplineN node1 = null;
SplineN node2 = null;
if (spline.CheckInvalidNodeCount())
{
spline.Setup();
nodeCount = spline.GetNodeCount();
}
if (nodeCount > 1)
{
// Iterate over every node
for (int i = 0; i < nodeCount; i++)
{
//try
//{
node = spline.nodes[i];
//}
//catch
//{
// Editor_bIsConstructing = false;
// EditorUpdateMe = true;
// return;
//}
//If node is intersection with an invalid RoadIntersection, mark it as non-intersection. Just-in-case.
if (node.isIntersection && node.intersection == null)
{
node.isIntersection = false;
node.intersectionOtherNodeID = -1;
node.intersectionOtherNode = null;
}
//If node is intersection, re-setup:
if (node.isIntersection && node.intersection != null)
{
node1 = node.intersection.node1;
node2 = node.intersection.node2;
node.intersection.Setup(node1, node2);
node.intersection.DeleteRelevantChildren(node, node.spline.road.transform.name);
//If primary node on intersection, do more re-setup:
if (node.intersection.node1 == node)
{
node.intersection.lanesAmount = laneAmount;
node.intersection.name = node.intersection.transform.name;
}
//Setup construction objects:
node.intersection.node1.intersectionConstruction = new iConstructionMaker();
node.intersection.node2.intersectionConstruction = new iConstructionMaker();
}
//Store materials and physical materials for road and or shoulder cuts on each node, if necessary:
node.StoreCuts();
}
}
name = transform.name;
spline.RoadWidth = RoadWidth();
//RootUtils.StartProfiling(this, "SplineSetup");
spline.Setup();
//RootUtils.EndProfiling(this);
nodeCount = spline.GetNodeCount();
if (spline == null || spline.nodes == null)
{
MostRecentNodeCount = 0;
}
else
{
MostRecentNodeCount = spline.GetNodeCount();
}
if (isUsingDefaultMaterials)
{
SetDefaultMats();
if (DetectInvalidDefaultMatsForUndo())
{
SetAllCutsToCurrentMaterials();
}
}
//Hiding in hierarchy:
for (int i = 0; i < nodeCount; i++)
{
node = spline.nodes[i];
if (node != null)
{
if (node.isIntersection || node.isSpecialEndNode)
{
node.ToggleHideFlags(true);
}
else
{
node.ToggleHideFlags(false);
}
}
}
// Delete mainMeshes of this road
int childCount = transform.childCount;
GameObject mainMeshes = null;
for (int i = 0; i < childCount; i++)
{
if (transform.GetChild(i).transform.name.ToLower().Contains("mainmeshes"))
{
mainMeshes = transform.GetChild(i).transform.gameObject;
Object.DestroyImmediate(mainMeshes);
}
}
if (nodeCount < 2)
{
//Delete old objs and return:
Object.DestroyImmediate(MainMeshes);
Object.DestroyImmediate(MeshRoad);
Object.DestroyImmediate(MeshShoR);
Object.DestroyImmediate(MeshShoL);
Object.DestroyImmediate(MeshiLanes);
Object.DestroyImmediate(MeshiLanes0);
Object.DestroyImmediate(MeshiLanes1);
Object.DestroyImmediate(MeshiLanes2);
Object.DestroyImmediate(MeshiLanes3);
Object.DestroyImmediate(MeshiMainPlates);
Object.DestroyImmediate(MeshiMarkerPlates);
RootUtils.EndProfiling(this);
return;
}
spline.HeightHistory = new List<KeyValuePair<float, float>>();
if (roadSystem == null)
{
roadSystem = transform.parent.GetComponent<RoadSystem>();
}
//Compatibility update.
if (isUsingMultithreading)
{
isEditorConstructing = true;
}
else
{
isEditorConstructing = false;
}
editorConstructionID = 0;
//Check if road takes place on only 1 terrain:
Terrain terrain = RoadUtility.GetTerrain(spline.nodes[0].pos);
bool isSameTerrain = true;
for (int i = 1; i < nodeCount; i++)
{
if (terrain != RoadUtility.GetTerrain(spline.nodes[0].pos))
{
isSameTerrain = false;
break;
}
}
RCS = new RoadConstructorBufferMaker(this, _updateType);
if (isSameTerrain)
{
RCS.tTerrain = terrain;
}
else
{
RCS.tTerrain = null;
}
terrain = null;
RootUtils.EndProfiling(this);
if (isUsingMultithreading)
{
if (RCS.isTerrainOn || TerrainHistory == null)
{
Terraforming.ProcessRoadTerrainHook1(spline, this);
}
else
{
ConstructRoad2();
}
}
else
{
UpdateRoadNoMultiThreading();
}
}
#region "Terrain history"
public void StoreTerrainHistory(bool _isDiskOnly = false)
{
if (!_isDiskOnly)
{
Road road = this;
RoadUtility.ConstructRoadStoreTerrainHistory(ref road);
}
if (isSavingTerrainHistoryOnDisk && TerrainHistory != null && TerrainHistory.Count > 0)
{
RootUtils.StartProfiling(this, "TerrainHistory_Save");
TerrainHistoryUtility.SaveTerrainHistory(TerrainHistory, this);
RootUtils.EndProfiling(this);
TerrainHistory.Clear();
TerrainHistory = null;
}
else
{
if (TerrainHistory != null && TerrainHistory.Count > 0)
{
int terrainSize = 0;
for (int i = 0; i < TerrainHistory.Count; i++)
{
terrainSize += TerrainHistory[i].GetSize();
}
TerrainHistoryByteSize = (terrainSize * 0.001f).ToString("n0") + " kb";
}
else
{
TerrainHistoryByteSize = "0 bytes";
}
}
}
public void ResetTerrainHistory()
{
Road tRoad = this;
if (isSavingTerrainHistoryOnDisk && TerrainHistory != null)
{
TerrainHistoryUtility.DeleteTerrainHistory(this);
}
else
{
RoadUtility.ResetTerrainHistory(ref tRoad);
}
}
/// <summary> Loads terrain history from disk </summary>
public void LoadTerrainHistory(bool _isForced = false)
{
if (isSavingTerrainHistoryOnDisk || _isForced)
{
if (TerrainHistory != null)
{
TerrainHistory.Clear();
TerrainHistory = null;
}
TerrainHistory = TerrainHistoryUtility.LoadTerrainHistory(this);
}
if (_isForced)
{
TerrainHistoryUtility.DeleteTerrainHistory(this);
}
}
#endregion
#region "Construction process"
#region "No multithread"
private void UpdateRoadNoMultiThreading()
{
if (isHeightModificationEnabled || isDetailModificationEnabled || isTreeModificationEnabled)
{
RootUtils.StartProfiling(this, "RoadCon_Terrain");
if (RCS.isTerrainOn || TerrainHistory == null)
{
Terraforming.ProcessRoadTerrainHook1(spline, this, false);
Terraforming.ProcessRoadTerrainHook2(spline, ref EditorTTDList);
//Store history.
StoreTerrainHistory();
int editorTTDListCount = EditorTTDList.Count;
for (int i = 0; i < editorTTDListCount; i++)
{
EditorTTDList[i] = null;
}
EditorTTDList = null;
System.GC.Collect();
}
RootUtils.EndProfiling(this);
}
editorProgress = 50;
Road road = this;
RootUtils.StartProfiling(this, "RoadCon_RoadPrelim");
editorProgress = 80;
Threading.RoadCreationT.RoadJobPrelim(ref road);
RootUtils.EndStartProfiling(this, "RoadCon_Road1");
editorProgress = 90;
Threading.RoadCreationT.RoadJob1(ref RCS);
RootUtils.EndStartProfiling(this, "MeshSetup1");
editorProgress = 92;
RCS.MeshSetup1();
RootUtils.EndStartProfiling(this, "RoadCon_Road2");
editorProgress = 94;
Threading.RoadCreationT.RoadJob2(ref RCS);
RootUtils.EndStartProfiling(this, "MeshSetup2");
editorProgress = 96;
RCS.MeshSetup2();
RootUtils.EndProfiling(this);
ConstructionCleanup();
}
#endregion
/// <summary> Stores terrain history and nulls TerrainCalcsJob</summary>
private void ConstructRoad2()
{
editorProgress = 40;
if (RCS.isTerrainOn)
{
//Store history:
Terraforming.ProcessRoadTerrainHook2(spline, ref EditorTTDList);
StoreTerrainHistory();
EditorTTDList.Clear();
EditorTTDList = null;
System.GC.Collect();
}
editorProgress = 60;
if (TerrainCalcsJob != null)
{
TerrainCalcsJob.Abort();
TerrainCalcsJob = null;
}
Road road = this;
editorProgress = 72;
RoadCalcsJob1 = new Threading.RoadCalcs1();
RoadCalcsJob1.Setup(ref RCS, ref road);
RoadCalcsJob1.Start();
}
private void ConstructRoad3()
{
editorProgress = 84;
RCS.MeshSetup1();
editorProgress = 96;
if (RoadCalcsJob1 != null)
{
RoadCalcsJob1.Abort();
RoadCalcsJob1 = null;
}
RoadCalcsJob2 = new Threading.RoadCalcs2();
RoadCalcsJob2.Setup(ref RCS);
RoadCalcsJob2.Start();
editorProgress = 98;
}
private void ConstructRoad4()
{
RCS.MeshSetup2();
ConstructionCleanup();
}
#endregion
private void AbortJobs()
{
if (TerrainCalcsJob != null)
{
TerrainCalcsJob.Abort();
TerrainCalcsJob = null;
}
if (RoadCalcsJob1 != null)
{
RoadCalcsJob1.Abort();
RoadCalcsJob1 = null;
}
if (RoadCalcsJob2 != null)
{
RoadCalcsJob2.Abort();
RoadCalcsJob2 = null;
}
}
private void ConstructionCleanup()
{
FixDisplay();
AbortJobs();
isEditorConstructing = false;
int nodeCount = spline.GetNodeCount();
SplineN node;
for (int i = 0; i < nodeCount; i++)
{
node = spline.nodes[i];
if (node.isIntersection)
{
if (node.intersectionConstruction != null)
{
node.intersectionConstruction.Nullify();
node.intersectionConstruction = null;
}
}
node.SetupSplinationLimits();
node.SetupEdgeObjects(false);
node.SetupSplinatedMeshes(false);
}
if (spline.HeightHistory != null)
{
spline.HeightHistory.Clear();
spline.HeightHistory = null;
}
if (RCS != null)
{
RCS.Nullify();
RCS = null;
}
if (isSavingMeshes)
{
EngineIntegration.SaveAssets();
}
isEditorProgressBar = false;
EngineIntegration.ClearProgressBar();
//Make sure terrain history out of memory if necessary (redudant but keep):
if (isSavingTerrainHistoryOnDisk && TerrainHistory != null)
{
TerrainHistory.Clear();
TerrainHistory = null;
}
//Collect:
isTriggeringGC = true;
if (tRoadMaterialDropdownOLD != roadMaterialDropdown)
{
tRoadMaterialDropdownOLD = roadMaterialDropdown;
SetAllCutsToCurrentMaterials();
}
if (PiggyBacks != null && PiggyBacks.Length > 0)
{
for (int i = 0; i < PiggyBacks.Length; i++)
{
if (PiggyBacks[i] == null)
{
PiggyBacks = null;
break;
}
}
if (PiggyBacks != null)
{
SplineC tPiggy = PiggyBacks[0];
SplineC[] NewPiggys = null;
PiggyBacks[0] = null;
if (PiggyBacks.Length > 1)
{
NewPiggys = new SplineC[PiggyBacks.Length - 1];
for (int i = 1; i < PiggyBacks.Length; i++)
{
NewPiggys[i - 1] = PiggyBacks[i];
}
}
if (NewPiggys != null)
{
tPiggy.road.PiggyBacks = NewPiggys;
}
NewPiggys = null;
tPiggy.TriggerSetup();
}
}
}
public void SetEditorTerrainCalcs(ref List<Terraforming.TempTerrainData> _tddList)
{
EditorTTDList = _tddList;
}
#endregion
#region "Gizmos"
private void OnDrawGizmosSelected()
{
if (isEditorMouseHittingTerrain)
{
Gizmos.color = newNodePreviewColor;
Gizmos.DrawCube(editorMousePos, new Vector3(10f, 4f, 10f));
}
}
#endregion
/// <summary> Returns width of road </summary>
public float RoadWidth()
{
return (laneWidth * (float)laneAmount);
}
#if UNITY_EDITOR
public float EditorCameraTimer = 0f;
private void Update()
{
if (Application.isEditor && isEditorCameraMoving)
{
EditorCameraTimer += Time.deltaTime;
if (EditorCameraTimer > EditorCameraTimeUpdateInterval)
{
EditorCameraTimer = 0f;
DoEditorCameraLoop();
}
}
}
#endif
#region "Default materials retrieval"
public bool DetectInvalidDefaultMatsForUndo()
{
string lowerName = "";
int counter = 0;
if (!MeshRoad)
{
return false;
}
string basePath = RoadEditorUtility.GetBasePath();
MeshRenderer[] MRs = MeshRoad.GetComponentsInChildren<MeshRenderer>();
Material tMat2Lanes = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble.mat");
Material tMat4Lanes = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble-4L.mat");
Material tMat6Lanes = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble-6L.mat");
foreach (MeshRenderer MR in MRs)
{
lowerName = MR.transform.name.ToLower();
if (lowerName.Contains("marker"))
{
if (laneAmount == 2)
{
if (MR.sharedMaterials[0] == tMat4Lanes)
{
counter += 1;
}
else if (MR.sharedMaterials[0] == tMat6Lanes)
{
counter += 1;
}
}
else if (laneAmount == 4)
{
if (MR.sharedMaterials[0] == tMat2Lanes)
{
counter += 1;
}
else if (MR.sharedMaterials[0] == tMat6Lanes)
{
counter += 1;
}
}
else if (laneAmount == 6)
{
if (MR.sharedMaterials[0] == tMat2Lanes)
{
counter += 1;
}
else if (MR.sharedMaterials[0] == tMat4Lanes)
{
counter += 1;
}
}
}
if (counter > 1)
{
return true;
}
}
return false;
}
/// <summary> Assigns materials on all mesh renderers </summary>
public void SetAllCutsToCurrentMaterials()
{
if (!MeshRoad)
{
return;
}
MeshRenderer[] MRs = MeshRoad.GetComponentsInChildren<MeshRenderer>();
Material[] roadWorldMats = GetRoadWorldMaterials();
Material[] roadMarkerMats = GetRoadMarkerMaterials();
SetCutMaterials(MRs, roadWorldMats, roadMarkerMats);
if (isShouldersEnabled)
{
roadWorldMats = GetShoulderWorldMaterials();
roadMarkerMats = GetShoulderMarkerMaterials();
if (MeshShoL != null)
{
MRs = MeshShoL.GetComponentsInChildren<MeshRenderer>();
SetCutMaterials(MRs, roadWorldMats, roadMarkerMats);
}
if (MeshShoR != null)
{
MRs = MeshShoR.GetComponentsInChildren<MeshRenderer>();
SetCutMaterials(MRs, roadWorldMats, roadMarkerMats);
}
}
}
/// <summary> Sets materials of each MR in _MRs </summary>
private void SetCutMaterials(MeshRenderer[] _MRs, Material[] _roadWorldMats, Material[] _roadMarkerMats)
{
string lowerName;
foreach (MeshRenderer MR in _MRs)
{
lowerName = MR.transform.name.ToLower();
if (lowerName.Contains("marker"))
{
if (_roadMarkerMats != null)
{
MR.sharedMaterials = _roadMarkerMats;
}
}
else if (lowerName.Contains("cut"))
{
if (_roadWorldMats != null)
{
MR.sharedMaterials = _roadWorldMats;
}
}
}
}
public Material[] GetRoadWorldMaterials()
{
List<Material> roadMaterials = new List<Material>();
if (RoadMaterial1 != null)
{
roadMaterials.Add(RoadMaterial1);
if (RoadMaterial2 != null)
{
roadMaterials.Add(RoadMaterial2);
if (RoadMaterial3 != null)
{
roadMaterials.Add(RoadMaterial3);
if (RoadMaterial4 != null)
{
roadMaterials.Add(RoadMaterial4);
}
}
}
}
return roadMaterials.ToArray();
}
public Material[] GetRoadMarkerMaterials()
{
List<Material> roadMarkerMaterials = new List<Material>();
if (RoadMaterialMarker1 != null)
{
roadMarkerMaterials.Add(RoadMaterialMarker1);
if (RoadMaterialMarker2 != null)
{
roadMarkerMaterials.Add(RoadMaterialMarker2);
if (RoadMaterialMarker3 != null)
{
roadMarkerMaterials.Add(RoadMaterialMarker3);
if (RoadMaterialMarker4 != null)
{
roadMarkerMaterials.Add(RoadMaterialMarker4);
}
}
}
}
return roadMarkerMaterials.ToArray();
}
public Material[] GetShoulderWorldMaterials()
{
if (!isShouldersEnabled)
{
return null;
}
List<Material> shoulderMaterials = new List<Material>();
if (ShoulderMaterial1 != null)
{
shoulderMaterials.Add(ShoulderMaterial1);
if (ShoulderMaterial2 != null)
{
shoulderMaterials.Add(ShoulderMaterial2);
if (ShoulderMaterial3 != null)
{
shoulderMaterials.Add(ShoulderMaterial3);
if (ShoulderMaterial4 != null)
{
shoulderMaterials.Add(ShoulderMaterial4);
}
}
}
}
return shoulderMaterials.ToArray();
}
public Material[] GetShoulderMarkerMaterials()
{
if (!isShouldersEnabled)
{
return null;
}
List<Material> shoulderMarkerMaterials = new List<Material>();
if (ShoulderMaterialMarker1 != null)
{
shoulderMarkerMaterials.Add(ShoulderMaterialMarker1);
if (ShoulderMaterialMarker2 != null)
{
shoulderMarkerMaterials.Add(ShoulderMaterialMarker2);
if (ShoulderMaterialMarker3 != null)
{
shoulderMarkerMaterials.Add(ShoulderMaterialMarker3);
if (ShoulderMaterialMarker4 != null)
{
shoulderMarkerMaterials.Add(ShoulderMaterialMarker4);
}
}
}
}
return shoulderMarkerMaterials.ToArray();
}
#endregion
#region "Materials"
/// <summary> Loads the standard materials if the road uses default materials </summary>
private void CheckMats()
{
if (!isUsingDefaultMaterials)
{
return;
}
string basePath = RoadEditorUtility.GetBasePath();
if (!RoadMaterial1)
{
RoadMaterial1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Road1.mat");
RoadMaterial2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/RoadDetailOverlay1.mat");
}
if (!RoadMaterialMarker1)
{
if (laneAmount == 2)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks.mat");
}
else if (laneAmount == 4)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble-4L.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks-4L.mat");
}
else if (laneAmount == 6)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble-6L.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks-6L.mat");
}
else
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks.mat");
}
}
// Can be simplified
if (isShouldersEnabled && !ShoulderMaterial1)
{
ShoulderMaterial1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Shoulder1.mat");
ShoulderMaterial2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/RoadDetailOverlay1.mat");
}
if (isShouldersEnabled && !RoadPhysicMaterial)
{
RoadPhysicMaterial = RoadEditorUtility.LoadPhysicsMaterial(basePath + "/Physics/Pavement.physicMaterial");
}
if (isShouldersEnabled && !ShoulderPhysicMaterial)
{
ShoulderPhysicMaterial = RoadEditorUtility.LoadPhysicsMaterial(basePath + "/Physics/Dirt.physicMaterial");
}
}
public void SetDefaultMats()
{
string basePath = RoadEditorUtility.GetBasePath();
// Reset materials
RoadMaterial1 = null;
RoadMaterial2 = null;
RoadMaterial3 = null;
RoadMaterial4 = null;
RoadMaterialMarker2 = null;
RoadMaterialMarker3 = null;
RoadMaterialMarker4 = null;
if (roadMaterialDropdown == RoadMaterialDropdownEnum.Asphalt)
{
RoadMaterial1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Road1.mat");
RoadMaterial2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/RoadDetailOverlay1.mat");
if (laneAmount == 2)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks.mat");
}
else if (laneAmount == 4)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble-4L.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks-4L.mat");
}
else if (laneAmount == 6)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble-6L.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks-6L.mat");
}
else
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/WhiteYellowDouble.mat");
RoadMaterialMarker2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/TireMarks.mat");
}
ShoulderMaterial1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Shoulder1.mat");
ShoulderMaterial2 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/Markers/RoadDetailOverlay1.mat");
RoadPhysicMaterial = RoadEditorUtility.LoadPhysicsMaterial(basePath + "/Physics/Pavement.physicMaterial");
ShoulderPhysicMaterial = RoadEditorUtility.LoadPhysicsMaterial(basePath + "/Physics/Dirt.physicMaterial");
}
else if (roadMaterialDropdown == RoadMaterialDropdownEnum.Dirt)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/DirtRoad.mat");
RoadMaterial1 = RoadMaterialMarker1;
}
else if (roadMaterialDropdown == RoadMaterialDropdownEnum.Brick)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/BrickRoad.mat");
RoadMaterial1 = RoadMaterialMarker1;
}
else if (roadMaterialDropdown == RoadMaterialDropdownEnum.Cobblestone)
{
RoadMaterialMarker1 = RoadEditorUtility.LoadMaterial(basePath + "/Materials/CobblestoneRoad.mat");
RoadMaterial1 = RoadMaterialMarker1;
}
if (roadMaterialDropdown == RoadMaterialDropdownEnum.Brick
|| roadMaterialDropdown == RoadMaterialDropdownEnum.Cobblestone
|| roadMaterialDropdown == RoadMaterialDropdownEnum.Dirt)
{
if (laneAmount > 2)
{
RoadMaterialMarker1 = new Material(RoadMaterialMarker1);
RoadMaterialMarker1.mainTextureScale = Vector2.Scale(RoadMaterialMarker1.mainTextureScale, new Vector2(laneAmount / 2, 1f));
}
}
int nodeCount = spline.GetNodeCount();
for (int i = 0; i < nodeCount; i++)
{
if (spline.nodes[i] && spline.nodes[i].isIntersection && spline.nodes[i].intersection != null && spline.nodes[i].intersection.isUsingDefaultMaterials)
{
spline.nodes[i].intersection.ResetMaterialsAll();
}
}
}
#endregion
/// <summary> Toggles render state of every mesh of this road </summary>
public void ToggleWireframes()
{
ToggleWireframesHelper(transform);
if (spline != null)
{
ToggleWireframesHelper(spline.transform);
}
}
/// <summary> Toggles render state of each mesh in _MRs through isGizmosEnabled </summary>
private void ToggleWireframesHelper(Transform _transform)
{
MeshRenderer[] _MRs = _transform.GetComponentsInChildren<MeshRenderer>();
int meshRenderersCount = _MRs.Length;
for (int i = 0; i < meshRenderersCount; i++)
{
//UnityEditor.EditorUtility.SetSelectedWireframeHidden(_MRs[i], !isGizmosEnabled);
EngineIntegration.SetSelectedRenderState(_MRs[i], isGizmosEnabled);
}
}
/// <summary> Sets localPosition for meshes up to prevent z fighting </summary>
private void FixDisplay()
{
FixDisplayMobile();
}
/// <summary> Sets localPosition for meshes up to prevent z fighting </summary>
private void FixDisplayMobile()
{
//This road:
Object[] markerObjs = transform.GetComponentsInChildren<MeshRenderer>();
Vector3 vector;
foreach (MeshRenderer MR in markerObjs)
{
if (MR.transform.name.Contains("Marker"))
{
vector = new Vector3(0f, 0.02f, 0f);
MR.transform.localPosition = vector;
}
else if (MR.transform.name.Contains("SCut") || MR.transform.name.Contains("RoadCut")
|| MR.transform.name.Contains("ShoulderR")
|| MR.transform.name.Contains("ShoulderL"))
{
vector = MR.transform.position;
vector.y += 0.01f;
MR.transform.position = vector;
}
else if (MR.transform.name.Contains("RoadMesh"))
{
vector = MR.transform.position;
vector.y += 0.02f;
MR.transform.position = vector;
}
else if (MR.transform.name.Contains("Pavement"))
{
vector = MR.transform.position;
vector.y -= 0.01f;
MR.transform.position = vector;
}
}
//Intersections (all):
markerObjs = roadSystem.GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer MR in markerObjs)
{
if (MR.transform.name.Contains("CenterMarkers"))
{
vector = new Vector3(0f, 0.02f, 0f);
MR.transform.localPosition = vector;
}
else if (MR.transform.name.Contains("-Inter") && MR.transform.name.Contains("-Lane"))
{
vector = new Vector3(0f, 0.02f, 0f);
MR.transform.localPosition = vector;
}
else if (MR.transform.name.Contains("-Inter") && MR.transform.name.Contains("-Stretch"))
{
vector = new Vector3(0f, 0.03f, 0f);
MR.transform.localPosition = vector;
}
else if (MR.transform.name.Contains("-Inter") && MR.transform.name.Contains("-Tiled"))
{
vector = new Vector3(0f, 0.01f, 0f);
MR.transform.localPosition = vector;
}
}
}
/// <summary> Sets localPosition up by 0.01 </summary>
private void FixDisplayWin()
{
//This road:
Object[] markerObjs = transform.GetComponentsInChildren<MeshRenderer>();
Vector3 vector;
foreach (MeshRenderer MR in markerObjs)
{
if (MR.transform.name.Contains("Marker"))
{
vector = new Vector3(0f, 0.01f, 0f);
MR.transform.localPosition = vector;
}
}
//Intersections (all):
markerObjs = FindObjectsOfType<MeshRenderer>();
foreach (MeshRenderer MR in markerObjs)
{
if (MR.transform.name.Contains("-Inter") && MR.transform.name.Contains("-Lane"))
{
vector = new Vector3(0f, 0.01f, 0f);
MR.transform.localPosition = vector;
}
else if (MR.transform.name.Contains("-Inter") && MR.transform.name.Contains("-Stretch"))
{
vector = new Vector3(0f, 0.01f, 0f);
MR.transform.localPosition = vector;
}
}
}
}
}