Editor/Walkway/ArchWalkwayConnectionService.cs

Editor-side service that helps resolve and connect walkway spans to buildings and rooms. It maps mouth geometry to endpoints, picks a host building for a connection based on opened rooms and a preferred host, and returns connection results.

NetworkingFile Access
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;

namespace Sunless.Architecture;


sealed class ArchWalkwayConnectionService
{
	readonly ArchConnectionService connections;
	readonly ArchBuilding preferredHost;
	readonly IReadOnlyList<(Vector2 From, Vector2 To)> mouths;
	readonly float clear;

	public ArchWalkwayConnectionService(
		ArchConnectionService connections,
		ArchBuilding preferredHost,
		IReadOnlyList<(Vector2 From, Vector2 To)> mouths,
		float clear )
	{
		this.connections = connections;
		this.preferredHost = preferredHost;
		this.mouths = mouths;
		this.clear = clear;
	}

	// The geometry already resolved which room each mouth cuts - the far one may be a storey up.
	public IReadOnlyList<ArchWalkwayEndpoint> ResolveEndpoints( ArchWalkwaySpan span )
	{
		return span.Mouths
			.Select( ( mouth, index ) =>
			{
				var point = (mouth.From + mouth.To) * 0.5f;
				var room = span.EndRooms[index];

				return new ArchWalkwayEndpoint
				{
					Point = point,
					Room = room,
					Building = room is null ? preferredHost : FindBuilding( room )
				};
			} )
			.ToList();
	}

	// Resolves WHERE the link lands, and cuts nothing. The mouths are an effect the link owns, so
	// ArchWalkwayConnection re-derives them on every commit - breaching here as well would bake a
	// hole the re-derive could not find again, and the link would drop its own group on the next one.
	public ArchWalkwayConnectionResult Connect( ArchRoom room, IReadOnlyList<ArchWalkwayEndpoint> endpoints )
	{
		var opened = endpoints
			.Select( endpoint => endpoint.Room )
			.Where( reached => reached is not null )
			.Distinct()
			.ToList();

		var host = opened.Select( reached => connections.Plan.OwnerOf( reached ) )
			.FirstOrDefault( owner => ReferenceEquals( owner, preferredHost ) )
			?? opened.Select( reached => connections.Plan.OwnerOf( reached ) ).FirstOrDefault( owner => owner is not null )
			?? preferredHost;

		return new ArchWalkwayConnectionResult { Host = host, Opened = opened, Endpoints = endpoints };
	}

	ArchBuilding FindBuilding( ArchRoom room ) => connections.Plan.OwnerOf( room );
}