sasalka/Code/Player/Dedugan.Interaction.cs
2025-06-10 23:24:50 +03:00

207 lines
4.4 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; }
void InteractionsUpdate()
{
if ( !EnablePressing ) 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()
{
if ( Pressed.IsValid() ) return;
SwitchHovered( TryGetLookedAt() );
if ( Hovered is IPressable pressable )
{
pressable.Look( new IPressable.Event
{
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
} );
}
if ( Input.Pressed( "use" ) )
{
StartPressing( Hovered );
}
}
public void StartPressing( Component obj )
{
if ( Pressed == obj ) return;
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()
{
var from = Scene.Camera.WorldPosition + Scene.Camera.WorldRotation.Forward;
var to = from + Scene.Camera.WorldRotation.Forward * InteractDistance;
var trace = Scene.Trace
.Ray( from, to )
.IgnoreGameObjectHierarchy( GameObject )
.Run();
TracedHitPos = trace.Hit ? trace.HitPosition : trace.EndPosition;
CameraTraceIsHit = trace.Hit;
TracedHitNormal = trace.Normal;
if ( !trace.Hit || !trace.GameObject.IsValid() ) return null;
var go = trace.GameObject;
var pressable = go.Components.Get<IPressable>( FindMode.EnabledInSelfAndDescendants );
if ( pressable != null && pressable.CanPress( new IPressable.Event
{
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), Source = this
} ) )
{
return pressable 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;
}
}