220 lines
5.9 KiB
C#
220 lines
5.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();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|