ArenaVisualPolish.cs
using Sandbox;
using System;
namespace PaintballBaddies;
/// <summary>Restrained native post processing; objective effects stay below the aim line.</summary>
public sealed class ArenaVisualPolish : Component
{
protected override void OnStart()
{
if(MultiplayerSession.Find(Scene)?.IsPopRiot==true)_=RiotDroneAssets.LoadAsync();
if(!Scene.GetAllComponents<RiotRoofHatch>().Any())Components.Create<RiotRoofHatch>();
if(!Scene.GetAllComponents<Bloom>().Any())
{
var bloom=Components.Create<Bloom>();
bloom.Strength=.10f;bloom.Threshold=2;bloom.Tint=Color.White;
}
// Native SSR supplements each map's existing probes. Rough concrete does
// not need ray tracing; fresh paint, glass and metal receive reflections.
if(!Scene.GetAllComponents<ScreenSpaceReflections>().Any())
Components.Create<ScreenSpaceReflections>();
if(!Scene.GetAllComponents<ArenaSurfaceFinish>().Any())Components.Create<ArenaSurfaceFinish>();
if(!Scene.GetAllComponents<ArenaBrightness>().Any())Components.Create<ArenaBrightness>();
if(!Scene.GetAllComponents<MapAmbienceMute>().Any())Components.Create<MapAmbienceMute>();
if(!Scene.GetAllComponents<RestaurantLayoutProbe>().Any())Components.Create<RestaurantLayoutProbe>();
if(!Scene.GetAllComponents<OverdriveArenaWear>().Any())Components.Create<OverdriveArenaWear>();
if(!Scene.GetAllComponents<ConcreteDestruction>().Any())Components.Create<ConcreteDestruction>();
}
}
/// <summary>Shared, inexpensive native line geometry. No colliders, lights or shadows.</summary>
public static class ArenaGlow
{
public static readonly Color Gold=new(1,.64f,.10f);
public static readonly Color Teal=new(.12f,.95f,.78f);
public static LineRenderer Ring(GameObject parent,string name,float radius,float width,Color color,int segments=48)
{
var go=new GameObject(parent){Name=name,NetworkMode=NetworkMode.Never};go.Tags.Add("paintball_debris");
var line=go.Components.Create<LineRenderer>();
line.UseVectorPoints=true;line.VectorPoints=new();
for(int i=0;i<=segments;i++)
{
float angle=i*MathF.Tau/segments;
line.VectorPoints.Add(new Vector3(MathF.Cos(angle)*radius,MathF.Sin(angle)*radius,0));
}
line.Width=new Curve(new Curve.Frame(0,width),new Curve.Frame(1,width));
line.Color=Gradient.FromColors(color,color);
line.Face=SceneLineObject.FaceMode.Camera;
line.CastShadows=false;line.Lighting=false;line.Opaque=false;line.Additive=true;
var local=go.Components.Create<LocalGlowLine>();local.SetPoints(line.VectorPoints);
return line;
}
}
/// <summary>LineRenderer vector points are world-space; follow the cosmetic parent explicitly.</summary>
public sealed class LocalGlowLine : Component
{
private List<Vector3> points=new();
private Transform previous;
private bool ready;
public void SetPoints(List<Vector3> value){points=value.ToList();ready=false;Refresh();}
private void Refresh()
{
if(ready && WorldTransform.Equals(previous))return;
previous=WorldTransform;ready=true;
var line=Components.Get<LineRenderer>();
if(line.IsValid())line.VectorPoints=points.Select(p=>WorldTransform.PointToWorld(p)).ToList();
}
protected override void OnUpdate()=>Refresh();
}