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( 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.PostToGameObject( GameObject, x => x.FailPressing() ); return; } var component = obj.Components.Get( 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.PostToGameObject( GameObject, x => x.FailPressing() ); return; } component.Press( pressEvent ); } Pressed = obj; if ( Pressed.IsValid() ) { ISceneEvent.PostToGameObject( GameObject, x => x.StartPressing( Pressed ) ); } } public void StopPressing() { if ( Pressed.IsValid() ) { ISceneEvent.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.PostToGameObject( GameObject, x => { foundComponent = x.GetUsableComponent( trace.GameObject ) ?? foundComponent; } ); if ( foundComponent.IsValid() ) return foundComponent; foreach ( var component in trace.GameObject.Components.GetAll() ) { 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() ) { Vector3 cp = col.FindClosestPoint( point ); float dist = Vector3.DistanceBetween( cp, point ); if ( dist < minDist ) minDist = dist; } return minDist; } }