217 lines
4.9 KiB
C#
217 lines
4.9 KiB
C#
using Sandbox;
|
|
using Sandbox.Utility;
|
|
using Sandbox.Diagnostics;
|
|
using System.Linq;
|
|
|
|
public sealed partial class Dedugan : Component
|
|
{
|
|
public Component Pressed { get; set; }
|
|
public bool EnablePressing { get; set; } = true;
|
|
public Component Hovered { get; set; }
|
|
|
|
[Sync( SyncFlags.Interpolate )] public Vector3 TracedHitPos { get; set; }
|
|
[Sync] public bool CameraTraceIsHit { get; set; }
|
|
public Vector3 TracedHitNormal { get; set; }
|
|
|
|
// private TimeSince HoldTime = 0;
|
|
// private bool Holding = false;
|
|
// private bool HoldingInteractionHappened = false;
|
|
|
|
void InteractionsUpdate()
|
|
{
|
|
if ( !EnablePressing )
|
|
{
|
|
// Holding = false;
|
|
// HoldingInteractionHappened = false;
|
|
return;
|
|
}
|
|
|
|
if ( Pressed.IsValid() )
|
|
{
|
|
UpdatePressed();
|
|
}
|
|
else
|
|
{
|
|
UpdateHovered();
|
|
}
|
|
|
|
if ( Input.Pressed( "Ragdoll" ) )
|
|
{
|
|
Health = 100;
|
|
}
|
|
}
|
|
|
|
private void UpdatePressed()
|
|
{
|
|
bool flag = Input.Down( "use" );
|
|
|
|
if ( flag && Pressed.Components.TryGet<IPressable>( out var pressable ) )
|
|
{
|
|
flag = pressable.Pressing( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
|
|
} );
|
|
}
|
|
|
|
if ( GetDistanceFromGameObject( Pressed.GameObject, Camera.WorldPosition ) > InteractDistance )
|
|
{
|
|
flag = false;
|
|
}
|
|
|
|
if ( !flag )
|
|
{
|
|
StopPressing();
|
|
}
|
|
}
|
|
|
|
private void UpdateHovered()
|
|
{
|
|
SwitchHovered( TryGetLookedAt() );
|
|
|
|
if ( Hovered is IPressable pressable )
|
|
{
|
|
pressable.Look( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
|
|
} );
|
|
}
|
|
|
|
if ( Input.Down( "use" ) )
|
|
{
|
|
StartPressing( Hovered );
|
|
}
|
|
}
|
|
|
|
public void StartPressing( Component obj )
|
|
{
|
|
StopPressing();
|
|
if ( !obj.IsValid() )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.FailPressing() );
|
|
return;
|
|
}
|
|
|
|
var component = obj.Components.Get<IPressable>( FindMode.EnabledInSelfAndDescendants );
|
|
if ( component != null )
|
|
{
|
|
var pressEvent = new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
|
|
};
|
|
|
|
if ( !component.CanPress( pressEvent ) )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.FailPressing() );
|
|
return;
|
|
}
|
|
|
|
component.Press( pressEvent );
|
|
}
|
|
|
|
Pressed = obj;
|
|
|
|
if ( Pressed.IsValid() )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.StartPressing( Pressed ) );
|
|
}
|
|
}
|
|
|
|
public void StopPressing()
|
|
{
|
|
if ( Pressed.IsValid() )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.StopPressing( Pressed ) );
|
|
|
|
if ( Pressed is IPressable pressable )
|
|
{
|
|
pressable.Release( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
|
|
} );
|
|
}
|
|
|
|
Pressed = null;
|
|
}
|
|
}
|
|
|
|
private void SwitchHovered( Component obj )
|
|
{
|
|
var e = new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
|
|
};
|
|
|
|
if ( Hovered == obj )
|
|
{
|
|
if ( Hovered is IPressable pressable )
|
|
pressable.Look( e );
|
|
return;
|
|
}
|
|
|
|
if ( Hovered is IPressable oldPressable )
|
|
oldPressable.Blur( e );
|
|
|
|
Hovered = obj;
|
|
|
|
if ( Hovered is IPressable newPressable )
|
|
{
|
|
newPressable.Hover( e );
|
|
newPressable.Look( e );
|
|
}
|
|
}
|
|
|
|
private Component TryGetLookedAt()
|
|
{
|
|
for ( float num = 0f; num <= 4f; num += 2f )
|
|
{
|
|
var from = Scene.Camera.WorldPosition + Scene.Camera.WorldRotation.Forward;
|
|
var to = from + Scene.Camera.WorldRotation.Forward * (InteractDistance - num);
|
|
var trace = Scene.Trace.Ray( from, to ).IgnoreGameObjectHierarchy( GameObject ).Radius( num ).Run();
|
|
|
|
TracedHitPos = trace.Hit ? trace.HitPosition : trace.EndPosition;
|
|
CameraTraceIsHit = trace.Hit;
|
|
TracedHitNormal = trace.Normal;
|
|
|
|
if ( !trace.Hit || !trace.GameObject.IsValid() ) continue;
|
|
|
|
Component foundComponent = null;
|
|
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x =>
|
|
{
|
|
foundComponent = x.GetUsableComponent( trace.GameObject ) ?? foundComponent;
|
|
} );
|
|
|
|
if ( foundComponent.IsValid() ) return foundComponent;
|
|
|
|
foreach ( var component in trace.GameObject.Components.GetAll<IPressable>() )
|
|
{
|
|
if ( component.CanPress( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
|
|
} ) )
|
|
{
|
|
return component as Component;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private float GetDistanceFromGameObject( GameObject obj, Vector3 point )
|
|
{
|
|
Vector3 closest = obj.WorldPosition;
|
|
float minDist = Vector3.DistanceBetween( closest, point );
|
|
|
|
foreach ( var col in Pressed.GetComponentsInChildren<Collider>() )
|
|
{
|
|
Vector3 cp = col.FindClosestPoint( point );
|
|
float dist = Vector3.DistanceBetween( cp, point );
|
|
if ( dist < minDist )
|
|
minDist = dist;
|
|
}
|
|
|
|
return minDist;
|
|
}
|
|
}
|