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.
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 );
}