Weapons/ToolGun/Modes/TrailTool.cs
using Sandbox.UI;
[Icon( "✨" )]
[Title( "#tool.name.trail" )]
[ClassName( "trail" )]
[Group( "#tool.group.render" )]
public sealed class TrailTool : ToolMode
{
[Property, ResourceSelect( Extension = "ldef", AllowPackages = true ), Title( "Line" )]
public string Definition { get; set; } = "entities/trails/basic.ldef";
[Property, Sync]
public Color TrailColor { get; set; } = Color.White;
[Property, Sync, Range( 0.1f, 128.0f )]
public float StartWidth { get; set; } = 4.0f;
[Property, Sync, Range( 0.0f, 128.0f )]
public float EndWidth { get; set; } = 0.0f;
[Property, Sync, Range( 0.1f, 10.0f )]
public float Lifetime { get; set; } = 1.0f;
[Property, Sync]
public bool CastShadows { get; set; } = false;
public override string Description => "Add or remove trails from objects";
protected override void OnStart()
{
base.OnStart();
RegisterAction( ToolInput.Primary, () => "Add Trail", OnAddTrail );
RegisterAction( ToolInput.Secondary, () => "Remove Trail", OnRemoveTrail );
}
void OnAddTrail()
{
var select = TraceSelect();
IsValidState = select.IsValid() && !select.IsWorld && !select.IsPlayer;
if ( !IsValidState ) return;
var lineDef = ResourceLibrary.Get<LineDefinition>( Definition );
AddTrail( select.GameObject, TrailColor, StartWidth, EndWidth, Lifetime, CastShadows, lineDef );
ShootEffects( select );
}
void OnRemoveTrail()
{
var select = TraceSelect();
IsValidState = select.IsValid() && !select.IsWorld && !select.IsPlayer;
if ( !IsValidState ) return;
RemoveTrail( select.GameObject );
ShootEffects( select );
}
[Rpc.Broadcast]
private void AddTrail( GameObject go, Color color, float startWidth, float endWidth, float lifetime, bool castShadows, LineDefinition lineDef )
{
if ( !go.IsValid() ) return;
if ( go.IsProxy ) return;
var root = go.Network?.RootGameObject ?? go;
var existing = root.GetComponent<TrailRenderer>();
if ( existing.IsValid() )
{
existing.Destroy();
}
var trail = root.AddComponent<TrailRenderer>();
trail.Color = new Gradient( new Gradient.ColorFrame( 0, color ), new Gradient.ColorFrame( 1, color.WithAlpha( 0 ) ) );
trail.Width = new Curve( new Curve.Frame( 0, startWidth ), new Curve.Frame( 1, endWidth ) );
trail.LifeTime = lifetime;
trail.CastShadows = castShadows;
trail.Face = SceneLineObject.FaceMode.Camera;
trail.Opaque = lineDef.Opaque;
trail.BlendMode = lineDef.BlendMode;
if ( lineDef.IsValid() && lineDef.Material.IsValid() )
{
trail.Texturing = trail.Texturing with
{
Material = lineDef.Material,
WorldSpace = lineDef.WorldSpace,
UnitsPerTexture = lineDef.UnitsPerTexture
};
}
}
[Rpc.Broadcast]
private void RemoveTrail( GameObject go )
{
if ( !go.IsValid() ) return;
if ( go.IsProxy ) return;
var root = go.Network?.RootGameObject ?? go;
var trail = root.GetComponent<TrailRenderer>();
if ( trail.IsValid() )
{
trail.Destroy();
}
}
}