sasalka/Code/Player/Dedugan.Interaction.cs
2025-06-08 23:43:22 +03:00

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;
}
}