Example/Complex/PlayerWalkControllerComplex.Using.cs
using Sandbox;
namespace XMovement;
public partial class PlayerWalkControllerComplex : Component
{
[Property, FeatureEnabled( "Using" )] public bool EnableUse { get; set; } = false;
/// <summary>
/// The Input Action that noclipping is triggered by.
/// </summary>
[Property, InputAction, Feature( "Using" )] public string UseAction { get; set; } = "Use";
[Property, Feature( "Using" )] public float UseDistance { get; set; } = 130;
public Component Hovering { get; set; }
public Component Using { get; set; }
public void DoUsing()
{
if ( !EnableUse ) return;
if ( IsProxy ) return;
var evnt = new IPressable.Event() { Ray = AimRay, Source = this };
UpdateHover( FindUsable() );
if ( Input.Pressed( UseAction ) && CanUse( Hovering ) )
{
Using = Hovering;
if ( Using is IPressable pressable ) pressable.Press( evnt );
}
if ( Input.Down( UseAction ) && CanUse( Using ) )
{
if ( Using is IPressable pressable ) pressable.Pressing( evnt );
}
if ( Using != null && (Input.Released( UseAction ) || !CanUse( Using )) )
{
if ( Using is IPressable pressable ) pressable.Release( evnt );
Using = null;
}
}
void UpdateHover( Component newhovering )
{
var evnt = new IPressable.Event() { Ray = AimRay, Source = this };
if ( Hovering == newhovering )
{
if ( Hovering is IPressable hoveringPressable )
{
hoveringPressable.Look( evnt );
}
return;
}
if ( Hovering is IPressable stoppedHoveringPressable )
{
stoppedHoveringPressable.Blur( evnt );
}
Hovering = newhovering;
if ( Hovering is IPressable startedHoveringPressable )
{
startedHoveringPressable.Hover( evnt );
startedHoveringPressable.Look( evnt );
}
}
public bool CanUse( Component component )
{
if ( !component.IsValid() ) return false;
if ( component.WorldPosition.Distance( AimRay.Position ) > UseDistance ) return false;
return true;
}
public Component FindUsable()
{
var tr = Scene.Trace.Ray( AimRay, UseDistance )
.IgnoreGameObjectHierarchy( GameObject )
.Run();
if ( !tr.GameObject.IsValid() ) return null;
// Walk up the hierarchy - the pressable component may be on a parent
// (e.g. DroppedWeapon is on the weapon root, but the trace hits the mesh child)
var pressable = tr.GameObject.Components.Get<Component.IPressable>( FindMode.EverythingInSelfAndParent );
if ( pressable != null && pressable.CanPress( new IPressable.Event() { Ray = AimRay, Source = this } ) )
return pressable as Component;
return null;
}
}