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