ConcreteCoverChecks.cs
using Sandbox;
using System.Linq;
namespace PaintballBaddies;
/// <summary>Opt-in checks against the actual placed arena barriers.</summary>
public sealed class ConcreteCoverChecks : Component
{
private PlayerController player;
private CoverController cover;
private CoverSurface[] barriers;
private int index;
private float elapsed;
private void Place()
{
var surface=barriers[index];
var collider=surface.Components.Get<ModelCollider>();
var depth=collider.Model.Bounds.Size.x*surface.WorldScale.x;
player.WorldPosition=surface.WorldPosition-surface.WorldRotation.Forward*(depth/2+30)+Vector3.Up*2;
player.EyeAngles=surface.WorldRotation.Angles();
player.Body.Velocity=Vector3.Zero;
elapsed=0;
}
protected override void OnStart()
{
player=Components.Get<PlayerController>();cover=Components.Get<CoverController>();
player.UseInputControls=player.UseLookControls=false;
Components.Get<PaintballMarker>().AcceptInput=false;cover.TestInput=true;
barriers=Scene.GetAllComponents<CoverSurface>().Where(c=>c.GameObject.Name.StartsWith("Concrete cover ")).ToArray();
if(barriers.Length==0) { Log.Error("CONCRETE_COVER FAIL no placed barriers");Destroy();return; }
Place();
}
protected override void OnUpdate()
{
elapsed+=Time.Delta;
if(elapsed<.6f)return;
var surface=barriers[index];
var trace=Scene.Trace.Ray(player.WorldPosition+Vector3.Up*28,player.WorldPosition+Vector3.Up*28+surface.WorldRotation.Forward*70).IgnoreGameObjectHierarchy(GameObject).Run();
bool attached=cover.TryEnter();
Log.Info($"CONCRETE_COVER {(attached ? "PASS" : "FAIL")} {surface.GameObject.Name} attachment; normal={trace.Normal}, airborne={player.IsAirborne}");
bool route=VaultPlanner.TryPlan(player,out var plan,out var reason);
bool expected=surface.Top-player.WorldPosition.z<=58;
Log.Info($"CONCRETE_COVER {(route==expected ? "PASS" : "FAIL")} {surface.GameObject.Name} vault route; expected={expected}, actual={route}, reason={reason}");
cover.Leave();index++;
if(index<barriers.Length) { Place();return; }
cover.TestInput=false;player.UseInputControls=player.UseLookControls=true;
Components.Get<PaintballMarker>().AcceptInput=true;
Log.Info($"CONCRETE_COVER COMPLETE barriers={barriers.Length}");Destroy();
}
}