ForwardAutoRunReview.cs
using Sandbox;
using System;
namespace PaintballBaddies;
/// <summary>Feeds mapped actions before the production auto-run/native movement hooks.</summary>
public sealed class ForwardAutoRunReview : Component
{
private PlayerController player;
private ForwardAutoRun runner;
private IDisposable updateHook,fixedHook;
private float elapsed;
private int phase;
private bool initialized,originalAutomatic;
protected override void OnUpdate()
{
if(initialized)return;
player=Scene.GetAllComponents<PlayerController>().FirstOrDefault();
runner=player?.Components.Get<ForwardAutoRun>();
if(!runner.IsValid())return;
initialized=true;originalAutomatic=runner.Automatic;
if(!runner.Automatic)runner.ToggleAutomatic();
player.WorldPosition=new Vector3(-900,1250,2);player.EyeAngles=Angles.Zero;player.UseLookControls=false;
player.Components.Get<PaintballMarker>().AcceptInput=false;
updateHook=Scene.AddHook(GameObjectSystem.Stage.StartUpdate,-95,Inputs,nameof(ForwardAutoRunReview),"Review actions");
fixedHook=Scene.AddHook(GameObjectSystem.Stage.StartFixedUpdate,-95,()=>{elapsed+=Time.Delta;Inputs();},nameof(ForwardAutoRunReview),"Review actions");
}
private void Inputs()
{
var forward=elapsed<2.2f || elapsed>=2.7f;
Input.SetAction("forward",forward);Input.SetAction("backward",false);
Input.SetAction("run",elapsed>=5.8f);
Input.SetAction("attack2",elapsed>=2 && elapsed<2.2f);
Input.SetAction("duck",elapsed>=4.4f && elapsed<4.7f);
Input.SetAction("walk",elapsed>=4.9f && elapsed<5.2f);
Input.AnalogMove=forward ? Vector3.Forward : Vector3.Zero;
}
private void Check(string name,bool pass)=>Log.Info($"AUTO_RUN_REVIEW {(pass ? "PASS" : "FAIL")} {name} speed={player.Body.Velocity.WithZ(0).Length:0.0} held={runner.HeldSeconds:0.00}");
protected override void OnFixedUpdate()
{
if(!initialized)return;
if(phase==0 && elapsed>.8f){Check("starts walking",!runner.Running && player.Body.Velocity.WithZ(0).Length>60 && player.Body.Velocity.WithZ(0).Length<105);phase++;}
if(phase==1 && elapsed>1.8f){Check("held forward reaches native run speed",runner.Running && Input.Down("run") && player.Body.Velocity.WithZ(0).Length>150);phase++;}
if(phase==2 && elapsed>2.1f){Check("aim resets automatic run",!runner.Running && runner.HeldSeconds==0 && !Input.Down("run"));phase++;}
if(phase==3 && elapsed>2.5f){Check("release clears timer",runner.HeldSeconds==0 && !Input.Down("run"));phase++;}
if(phase==4 && elapsed>3.2f){Check("new hold starts walking",!runner.Running && !Input.Down("run"));phase++;}
if(phase==5 && elapsed>4.2f){Check("new sustained hold runs again",runner.Running && Input.Down("run"));phase++;}
if(phase==6 && elapsed>4.5f){Check("crouch resets timer",runner.HeldSeconds==0 && !Input.Down("run"));phase++;}
if(phase==7 && elapsed>5){Check("walk override resets timer",runner.HeldSeconds==0 && !Input.Down("run"));phase++;}
if(phase==8 && elapsed>5.9f){Check("manual run remains immediate",Input.Down("run") && !runner.Running);phase++;}
}
protected override void OnDestroy()
{
updateHook?.Dispose();fixedHook?.Dispose();
if(runner.IsValid() && runner.Automatic!=originalAutomatic)runner.ToggleAutomatic();
if(player.IsValid()){player.UseLookControls=true;player.Components.Get<PaintballMarker>().AcceptInput=true;}
}
}