Editor/RoadNetworkTool.cs

Editor tool root for Road Tool 2.0. It selects or creates the active RoadNetwork, exposes subtools, updates selection, and draws a gizmo overlay of the road graph (segments and nodes) each frame.

File Access
using System.Collections.Generic;
using System.Linq;
using Editor;
using Sandbox;

namespace RedSnail.RoadTool2.Editor;

/// <summary>
/// Root tool of Road Tool 2.0. Resolves the network being edited and draws the graph overlay; the actual
/// interaction lives in the sub tools.
/// </summary>
[EditorTool]
[Title("Road Tool 2.0")]
[Icon("add_road")]
[Alias("roadtool2")]
[Group("Tools")]
public class RoadNetworkTool : EditorTool
{
	/// <summary>
	/// The network edits go to. Null until the first road is drawn in a scene without one.
	/// </summary>
	public RoadNetwork Network { get; private set; }



	public override IEnumerable<EditorTool> GetSubtools()
	{
		yield return new RoadDrawTool();
		yield return new RoadSelectTool();
		yield return new RoadLaneTool();
		yield return new RoadLotTool();
		yield return new RoadTerrainTool();
	}



	public override void OnEnabled()
	{
		AllowGameObjectSelection = false;
		ResolveNetwork();
	}



	public override void OnSelectionChanged()
	{
		ResolveNetwork();
	}



	public override void OnUpdate()
	{
		if (!Network.IsValid())
			ResolveNetwork();

		DrawGraph();
	}



	/// <summary>
	/// Prefers a selected network (or a selected chunk's network), else the scene's own.
	/// </summary>
	public void ResolveNetwork()
	{
		var selected = Selection.OfType<GameObject>()
			.Select(gameObject => gameObject.Components.Get<RoadNetwork>() ?? gameObject.Parent?.Components.Get<RoadNetwork>())
			.FirstOrDefault(network => network.IsValid());

		Network = selected ?? Scene.Get<RoadNetwork>();
	}



	/// <summary>
	/// Creates a fresh network at the scene root. Call it inside an undo scope that records GameObject creations.
	/// </summary>
	public RoadNetwork CreateNetwork()
	{
		var gameObject = Scene.CreateObject();
		gameObject.Name = "Road Network";

		Network = gameObject.AddComponent<RoadNetwork>();

		return Network;
	}



	private void DrawGraph()
	{
		if (!Network.IsValid())
			return;

		var transform = Network.WorldTransform;

		using (Gizmo.Scope("roadtool2_graph"))
		{
			Gizmo.Draw.IgnoreDepth = true;
			Gizmo.Draw.LineThickness = 1.0f;
			Gizmo.Draw.Color = Color.White.WithAlpha(0.35f);

			foreach (var segment in Network.Segments)
			{
				if (Network.TryGetCurve(segment, out var curve))
					RoadGizmos.DrawCurve(curve, transform);
			}

			Gizmo.Draw.Color = Color.White.WithAlpha(0.6f);

			foreach (var node in Network.Nodes)
				RoadGizmos.DrawNode(transform.PointToWorld(node.Position), false);
		}
	}
}