RestaurantLayoutProbe.cs
using Sandbox;
using System;
namespace PaintballBaddies;
/// <summary>One-off layout dump for Last Orders: logs a coarse top-down map of
/// walkable navigation, doors, player spawns and kitchen entrances.</summary>
public sealed class RestaurantLayoutProbe : Component
{
[Property] public bool SurveyEnabled {get;set;}
private float wait;private bool done;
protected override void OnUpdate()
{
if(!Game.IsEditor || !SurveyEnabled || done || ArenaSelection.Current(Scene)!=ArenaSelection.Restaurant)return;
wait+=Time.Delta;
if(wait<4 || Scene.NavMesh.IsGenerating || Scene.GetAllComponents<MapInstance>().Any(m=>m.Active && !m.IsLoaded))return;
done=true;
const int step=40;int x0=-500,x1=1500,y0=500,y1=2100;
var doors=Scene.GetAllObjects(true).Where(g=>g.Name.Contains("door")).Select(g=>g.WorldPosition).ToArray();
var spawns=ArenaMap.Spawns(Scene).Select(s=>s.WorldPosition).ToArray();
var lines=new List<string>();
for(int y=y1;y>=y0;y-=step)
{
var row=new System.Text.StringBuilder();
for(int x=x0;x<=x1;x+=step)
{
var c=new Vector3(x,y,33);
char ch=' ';
var p=Scene.NavMesh.GetClosestPoint(c,step*.6f);
if(p.HasValue && MathF.Abs(p.Value.z-33)<60)ch='.';
if(MultiplayerSession.KitchenEntrances.Any(k=>(k.WithZ(0)-c.WithZ(0)).Length<step*.6f))ch='K';
if(doors.Any(d=>(d.WithZ(0)-c.WithZ(0)).Length<step*.6f))ch='D';
if(spawns.Any(s=>(s.WithZ(0)-c.WithZ(0)).Length<step*.6f))ch='P';
row.Append(ch);
}
lines.Add($"{y,5} |{row}");
}
Log.Info("RESTAURANT_LAYOUT x from "+x0+" to "+x1+" step "+step+" (left=low x); doors="+string.Join(";",doors.Select(d=>$"{d.x:0},{d.y:0}"))+" spawns="+string.Join(";",spawns.Select(s=>$"{s.x:0},{s.y:0}")));
foreach(var l in lines)Log.Info("RL "+l);
}
}