plugins/AH64.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using AH64.Modules;
using AH64.Modules.Achievements;
using AH64.Modules.Characters;
using AH64.Survivors;
using AH64.Survivors.Components;
using AH64.Survivors.SkillStates;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.AI.Walker;
using EntityStates.Commando;
using EntityStates.Engi.EngiMissilePainter;
using EntityStates.Headstompers;
using HG;
using HG.BlendableTypes;
using HG.Reflection;
using KinematicCharacterController;
using On.EntityStates.Headstompers;
using On.RoR2;
using On.RoR2.Projectile;
using On.RoR2.UI;
using R2API;
using R2API.Utils;
using Rewired;
using RoR2;
using RoR2.Achievements;
using RoR2.Audio;
using RoR2.CharacterAI;
using RoR2.ConVar;
using RoR2.ContentManagement;
using RoR2.Networking;
using RoR2.Projectile;
using RoR2.Skills;
using RoR2.SurvivorMannequins;
using RoR2.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AH64")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c8488c53bca37208cfa1827eaa36caf89baedc29")]
[assembly: AssemblyProduct("AH64")]
[assembly: AssemblyTitle("AH64")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace AH64
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.JohnstonStu.AH64", "AH64", "1.3.3")]
	public class AH64Plugin : BaseUnityPlugin
	{
		public const string MODUID = "com.JohnstonStu.AH64";

		public const string MODNAME = "AH64";

		public const string MODVERSION = "1.3.3";

		public static AH64Plugin instance;

		private void Awake()
		{
			instance = this;
			Log.Init(((BaseUnityPlugin)this).Logger);
			AH64HellfireNetwork.Init();
			AH64BombingRunNetwork.Init();
			AH64PlaytestConfig.Init(((BaseUnityPlugin)this).Config);
			Language.Init();
			new AH64Survivor().Initialize();
			new ContentPacks().Initialize();
			DevAutopilot.TryStart();
		}

		private void OnDestroy()
		{
			AH64BombingRunNetwork.Shutdown();
			AH64HellfireNetwork.Shutdown();
		}
	}
	[DefaultExecutionOrder(10000)]
	internal sealed class DevAutopilot : MonoBehaviour
	{
		[Serializable]
		private sealed class BalanceResult
		{
			public int schema = 1;

			public int expectedChecks = 9;

			public string sourceSha;

			public string runId;

			public string dllSha256;

			public string status;

			public bool complete;

			public Check[] checks;

			public string limitation = "SOLO native request/stock/state/reload pipeline with isolated M230 override, no inventory grants. Cadence is fixed-tick scheduled. Physical controls, real target damage, alternate-primary gameplay and item scaling remain unverified by this delta test.";
		}

		[Serializable]
		private sealed class BombingResult
		{
			public int schema = 1;

			public int expectedChecks;

			public string runId;

			public string sourceSha;

			public string dllSha256;

			public string suite;

			public string status;

			public string limitation;

			public bool complete;

			public bool hooksReleased;

			public string[] expectedIds;

			public Check[] checks;
		}

		[Serializable]
		private sealed class BombingObservation : Record
		{
			public ulong castId;

			public uint ownerId;

			public uint targetId;

			public int dropIndex;

			public int projectileId;

			public int acceptedHits;

			public int icbmCount;

			public string kind;

			public string reason;

			public string bodyState;

			public string weapon2State;

			public float scheduledTime;

			public float actualTime;

			public float time;

			public float damage;

			public float procCoefficient;

			public float remainingBaseCoefficient;

			public float airtime;

			public float targetHeight;

			public Vector3 position;

			public Vector3 velocity;

			public Vector3 nativeCore;

			public Vector3 nativeVelocity;

			public bool crit;

			public bool jumpHeld;

			public bool ascending;
		}

		[Serializable]
		private sealed class BombingDamage : Record
		{
			public ulong castId;

			public uint ownerId;

			public uint targetId;

			public int projectileId;

			public int dropIndex;

			public float time;

			public float damageDealt;

			public float rawDamage;

			public float procCoefficient;

			public bool bomb;

			public bool crit;

			public bool rejected;

			public string dot;
		}

		[Serializable]
		private sealed class BombingFixture : Record
		{
			public uint targetId;

			public uint masterId;

			public float health;

			public float fullHealth;

			public float armor;

			public float pilotBleedChance;

			public Vector3 position;

			public bool godMode;

			public bool invulnerable;

			public string fixture;
		}

		[Serializable]
		private sealed class BombingCleanup : Record
		{
			public ulong castId;

			public float time;

			public int bombs;

			public int bleedBefore;

			public int bleedAfter;

			public int icbmBefore;

			public int icbmAfter;

			public int stockBefore;

			public int stockBeforeRestore;

			public bool targetAlive;

			public bool targetMasterAlive;

			public bool obstructionAlive;

			public bool noRefund;

			public bool originValid;

			public bool overrideReferencesReleased;

			public string weapon2State;
		}

		[Serializable]
		private sealed class BombingPayload
		{
			public ulong castId;

			public uint ownerId;

			public uint targetId;

			public string kind;

			public string reason;

			public int dropIndex;

			public int acceptedHits;

			public float scheduledTime;

			public float actualTime;

			public float remainingBaseCoefficient;

			public float damage;

			public float procCoefficient;

			public Vector3 position;

			public Vector3 velocity;

			public bool crit;
		}

		[Serializable]
		private sealed class BrakingResult
		{
			public int schema = 1;

			public int expectedChecks;

			public int renderSamples;

			public int renderViolations;

			public string runId;

			public string sourceSha;

			public string dllSha256;

			public string suite;

			public string status;

			public string limitation;

			public string utilityInterruptPriority;

			public bool complete;

			public string[] expectedIds;

			public Check[] checks;
		}

		[Serializable]
		private sealed class BrakingSample : Record
		{
			public int tick;

			public int appliedSteps;

			public float simulationTime;

			public float progress;

			public float appliedAge;

			public float targetHeight;

			public float airtime;

			public float groundDistance;

			public string capture;

			public string phase;

			public string yieldReason;

			public Vector3 commandedHeading;

			public Vector3 position;

			public Vector3 velocity;

			public Vector3 nativeAim;

			public Vector3 nativeVelocity;

			public Vector3 appliedVelocity;

			public Quaternion displayedBaseWorld;

			public bool ascending;

			public bool lease;

			public bool visualOwner;

			public bool visualRecovery;
		}

		[Serializable]
		private sealed class BrakingRender : Record
		{
			public int poseEpoch;

			public float renderedTime;

			public float renderDeltaTime;

			public float observedDelta;

			public float alarmBound;

			public Quaternion worldAttitude;

			public string bodyState;

			public bool visualActive;
		}

		[Serializable]
		private sealed class WindowCaptureStage
		{
			public string sourceSha;

			public string gameDirectory;

			public string owner;

			public string reservation;

			public string runtimeLockPath;
		}

		[Serializable]
		private sealed class WindowPhaseEvidence
		{
			public string runId;

			public string token;

			public string confirmedUtc;

			public string limitation;

			public bool phaseValid;

			public int phaseChecks;

			public int confirmedFrame;

			public float confirmedFixedTime;
		}

		[Serializable]
		private class StageIdentity
		{
			public string status = "";

			public string sourceSha = "";

			public string profile = "";

			public string dirtyWorkspaceFingerprint = "";
		}

		[Serializable]
		private class Record
		{
			public int schemaVersion = 1;

			public string recordType;

			public string runId;

			public string scenario;
		}

		[Serializable]
		private class Header : Record
		{
			public string sourceSha;

			public string dirtyWorkspaceFingerprint;

			public string pluginVersion;

			public string dllSha256;

			public string bundleSha256;

			public string bankSha256;

			public string configSha256;

			public string gameBuild;

			public string profile;

			public string role;

			public string identityFile;

			public int requestedAssertionCount;

			public int seed;
		}

		[Serializable]
		private class Sample : Record
		{
			public int tick;

			public int entityId;

			public int ownerId;

			public int poseEpoch;

			public float simulationTime;

			public Vector3 position;

			public Vector3 velocity;

			public Vector3 facing;

			public Vector3 nativeAim;

			public Quaternion modelAttitude;

			public bool authority;

			public string role;

			public string maneuverCapture;

			public string guidanceToken;

			public string attitudeSamplePhase;
		}

		[Serializable]
		private class ProjectileSample : Record
		{
			public int tick;

			public int projectileId;

			public int combo;

			public uint token;

			public Vector3 position;

			public Vector3 heading;

			public float lastTurnDegrees;

			public float remainingTurnDegrees;
		}

		[Serializable]
		private class EventRecord : Record
		{
			public int tick;

			public int entityId;

			public int ownerId;

			public float simulationTime;

			public string role;

			public string eventName;

			public string reason;
		}

		[Serializable]
		private class AssertionRecord : Record
		{
			public string assertionId;

			public string expected;

			public string actual;

			public float tolerance;

			public bool passed;
		}

		[Serializable]
		private class Check
		{
			public string id;

			public string expected;

			public string actual;

			public string scenario;

			public float tolerance;

			public bool passed;
		}

		[Serializable]
		private class Summary : Record
		{
			public int schema = 1;

			public int expectedAssertions;

			public int assertions;

			public int failedAssertions;

			public int executed;

			public int passed;

			public int failed;

			public int skipped;

			public int captures;

			public int samples;

			public int errors;

			public int warnings;

			public int visualFlags;

			public string suite;

			public string status;

			public string reason;

			public string warningClassification;

			public string errorClassification;

			public string limitation;

			public Check[] checks;

			public string[] artifactPaths;
		}

		[Serializable]
		private sealed class PrototypeResult
		{
			public int schema = 1;

			public int expectedChecks;

			public string runId;

			public string sourceSha;

			public string dllSha256;

			public string status;

			public string limitation;

			public bool complete;

			public Check[] checks;
		}

		private readonly List<Check> balanceChecks = new List<Check>();

		private bool balanceStarted;

		private bool balanceComplete;

		private const string BombingSuite = "bombing-solo-v1";

		private static readonly string[] BombingNames = new string[5] { "stationary", "bleed", "curve", "interrupt", "invalid" };

		private static readonly string[] BombingChecks = new string[5] { "activation", "opportunities", "motion", "payload", "cleanup" };

		private readonly List<Check> bombingChecks = new List<Check>();

		private readonly List<BombingObservation> bombingObservations = new List<BombingObservation>();

		private readonly HashSet<int> bombingProjectileIds = new HashSet<int>();

		private readonly Dictionary<int, int> bombingDropByProjectile = new Dictionary<int, int>();

		private readonly Dictionary<int, ulong> bombingCastByProjectile = new Dictionary<int, ulong>();

		private readonly List<BombingDamage> bombingReports = new List<BombingDamage>();

		private readonly HashSet<DamageInfo> bombingAcceptedNativeInfo = new HashSet<DamageInfo>();

		private bool bombingStarted;

		private bool bombingComplete;

		private bool bombingHooks;

		private bool bombingCaseActive;

		private bool bombingAddedBleed;

		private bool bombingAddedIcbm;

		private int bombingOnEnemy;

		private int bombingOnAll;

		private ulong bombingCastId;

		private CharacterMaster bombingTargetMaster;

		private CharacterBody bombingTarget;

		private uint bombingTargetId;

		private uint bombingTargetMasterId;

		private GameObject bombingObstruction;

		private SkillDef bombingSpecialOverride;

		private SkillDef bombingUtilityOverride;

		private NetworkUser startedNetworkUser;

		private BodyIndex expectedBody = (BodyIndex)(-1);

		private readonly List<Check> brakingChecks = new List<Check>();

		private bool brakingStarted;

		private bool brakingComplete;

		private bool brakingCollective;

		private bool brakingHasRender;

		private bool brakingPreviousVisualActive;

		private Quaternion brakingPreviousRender;

		private int brakingRenderEpoch;

		private int brakingRenderViolations;

		private int brakingRenderSamples;

		private static readonly string[] BrakingCaseNames = new string[6] { "stationary", "small", "fast", "spare", "collective", "interrupt" };

		private static readonly string[] BrakingCaseChecks = new string[5] { "activation-capture", "midflight", "motion", "exit", "cleanup" };

		private WindowCaptureRequest pendingCapture;

		private bool capturePhaseInvalid;

		private int capturePhaseChecks;

		internal const string Suite = "baseline-v1";

		internal const int ExpectedAssertions = 12;

		private string output;

		private string segment = "startup";

		private CharacterBody pilot;

		private Vector3 mark;

		private Vector3 facing = Vector3.forward;

		private Vector3 move;

		private float started;

		private float quitAt;

		private bool gameLoaded;

		private bool scripting;

		private bool finished;

		private int tick;

		private int samples;

		private int errors;

		private int warnings;

		private int visualFlags;

		private int launches;

		private int captures;

		private readonly List<Check> checks = new List<Check>();

		private bool prototypeHeld;

		private Vector3 prototypeAim;

		private StreamWriter jsonl;

		private StreamWriter csv;

		private StreamWriter trace;

		private StreamWriter runtimeLog;

		private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;

		private readonly Dictionary<string, EntityState> previousStates = new Dictionary<string, EntityState>();

		private readonly HashSet<int> observedProjectiles = new HashSet<int>();

		private readonly HashSet<int> liveProjectiles = new HashSet<int>();

		private Quaternion previousAttitude;

		private bool hasAttitude;

		private int poseEpoch;

		private int terminalExit;

		private readonly List<Check> prototypeChecks = new List<Check>();

		private bool prototypeStarted;

		private bool prototypeComplete;

		private void BalanceCheck(string id, bool passed, string actual)
		{
			balanceChecks.Add(new Check
			{
				id = id,
				passed = passed,
				actual = actual,
				scenario = segment
			});
			Event("balance-check", id + " " + (passed ? "PASS" : "FAIL") + " " + actual);
		}

		private IEnumerator M230BalanceCase()
		{
			balanceStarted = true;
			yield return ResetCase("m230-balance");
			Event("balance-scope", "SOLO native GenericSkill.ExecuteIfReady requests at fixed cadence with explicit M230 override; no physical hold, target-hit/damage or item-scaling acceptance");
			GenericSkill slot = pilot.skillLocator.primary;
			SkillDef original = slot.skillDef;
			SkillDef skill = Variant(slot, typeof(FireChaingun));
			slot.SetSkillOverride((object)this, skill, (SkillOverridePriority)4);
			try
			{
				yield return Until(() => slot.stock == slot.maxStock && slot.CanExecute(), 10f, "M230 full native drum");
				float attackSpeed = pilot.attackSpeed;
				BalanceCheck("m230.defaults", FireChaingun.baseDuration == 0.11f && Mathf.Abs(attackSpeed - 1f) < 0.001f, "nominal interval=" + FireChaingun.baseDuration + " attackSpeed=" + attackSpeed + " damage=" + AH64PlaytestConfig.ChaingunDamage + " HE=" + AH64PlaytestConfig.ChaingunSplashDamage + " proc=" + 0.5f);
				BalanceCheck("m230.native-magazine", skill.baseMaxStock == 20 && slot.maxStock == 20 && slot.stock == 20, "SkillDef=" + skill.baseMaxStock + " native max=" + slot.maxStock + " stock=" + slot.stock);
				List<float> nativeEntries = new List<float>();
				EntityState last = null;
				Action observe = delegate
				{
					EntityState state = Machine("Weapon").state;
					if (last != state)
					{
						last = state;
						if (state is FireChaingun)
						{
							nativeEntries.Add(Time.fixedTime);
							Event("m230-native-fire-entry", "entry=" + nativeEntries.Count + " stock=" + slot.stock + " fixedTime=" + Time.fixedTime.ToString("R", Invariant));
						}
					}
				};
				int accepted = 0;
				bool singleStock = true;
				float lastRequest = 0f;
				float deadline = Time.realtimeSinceStartup + 15f;
				while (slot.stock > 0 && Time.realtimeSinceStartup < deadline)
				{
					observe();
					int stock = slot.stock;
					if (slot.ExecuteIfReady())
					{
						accepted++;
						lastRequest = Time.fixedTime;
						singleStock &= slot.stock == stock - 1;
						Event("m230-accepted-request", "request=" + accepted + " stock=" + stock + "->" + slot.stock + " fixedTime=" + lastRequest.ToString("R", Invariant));
					}
					yield return (object)new WaitForFixedUpdate();
				}
				yield return (object)new WaitForFixedUpdate();
				observe();
				yield return (object)new WaitForFixedUpdate();
				observe();
				BalanceCheck("m230.stock-cost", accepted == 20 && singleStock && slot.stock == 0, "accepted=" + accepted + " one-stock-each=" + singleStock + " stock=" + slot.stock);
				BalanceCheck("m230.native-fire-entries", nativeEntries.Count == 20, "actual FireChaingun state entries=" + nativeEntries.Count);
				float[] array = nativeEntries.Skip(1).Select((float time, int index) => time - nativeEntries[index]).ToArray();
				float nominal = FireChaingun.baseDuration / attackSpeed;
				bool passed = array.Length == 19 && array.All((float dt) => dt >= nominal - 0.001f && dt <= nominal + Time.fixedDeltaTime * 3f + 0.001f);
				BalanceCheck("m230.native-cadence", passed, "nominal=" + nominal + " observed min=" + ((array.Length != 0) ? array.Min().ToString("R", Invariant) : "none") + " max=" + ((array.Length != 0) ? array.Max().ToString("R", Invariant) : "none") + " intervals=" + array.Length + "; fixed-tick request/state scheduling, not nominal RPM measurement");
				bool flag = slot.ExecuteIfReady();
				BalanceCheck("m230.empty-blocked", !flag && slot.stock == 0, "empty ExecuteIfReady=" + flag + " stock=" + slot.stock);
				float reload = skill.GetRechargeInterval(slot);
				yield return Until(() => slot.stock > 0, 10f, "M230 native full reload");
				float num = Time.fixedTime - lastRequest;
				BalanceCheck("m230.whole-reload", slot.stock == 20 && slot.maxStock == 20, "native stock=" + slot.stock + " max=" + slot.maxStock);
				BalanceCheck("m230.reload-timing", Mathf.Abs(num - reload) <= Time.fixedDeltaTime * 3f + 0.001f, "native elapsed from last request=" + num.ToString("R", Invariant) + " expected=" + reload.ToString("R", Invariant));
				yield return Until(() => !(Machine("Weapon").state is FireChaingun), 5f, "M230 firing state exit");
			}
			finally
			{
				slot.UnsetSkillOverride((object)this, skill, (SkillOverridePriority)4);
			}
			BalanceCheck("m230.override-cleanup", (Object)(object)slot.skillDef == (Object)(object)original && !(Machine("Weapon").state is FireChaingun), "original primary restored; no live FireChaingun state");
			balanceComplete = true;
		}

		private bool FinishBalanceEvidence()
		{
			if (Environment.GetEnvironmentVariable("AH64_AUTOPILOT_BALANCE_CHECKS") != "m230-v1")
			{
				return true;
			}
			bool flag = balanceStarted && balanceComplete && balanceChecks.Count == 9 && balanceChecks.All((Check c) => c.passed);
			File.WriteAllText(Path.Combine(output, "balance-result.json"), JsonUtility.ToJson((object)new BalanceResult
			{
				sourceSha = JsonUtility.FromJson<StageIdentity>(File.ReadAllText(Path.Combine(output, "identity.json"))).sourceSha,
				runId = Path.GetFileName(output),
				dllSha256 = Hash(typeof(AH64Plugin).Assembly.Location),
				status = (flag ? "passed" : "failed"),
				complete = balanceComplete,
				checks = balanceChecks.ToArray()
			}, true));
			return flag;
		}

		private void InstallBombingProbeHooks()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			if (!(Environment.GetEnvironmentVariable("AH64_AUTOPILOT_BOMBING_CHECKS") != "bombing-solo-v1") && !bombingHooks)
			{
				bombingHooks = true;
				AH64BombingRunTrace.Emitted += ObserveBombingTrace;
				GlobalEventManager.onServerDamageDealt += ObserveBombingDamage;
				GlobalEventManager.OnHitEnemy += new hook_OnHitEnemy(ObserveBombingOnHitEnemy);
				GlobalEventManager.OnHitAll += new hook_OnHitAll(ObserveBombingOnHitAll);
			}
		}

		private void CleanupBombingProbe()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			if (bombingHooks)
			{
				AH64BombingRunTrace.Emitted -= ObserveBombingTrace;
				GlobalEventManager.onServerDamageDealt -= ObserveBombingDamage;
				GlobalEventManager.OnHitEnemy -= new hook_OnHitEnemy(ObserveBombingOnHitEnemy);
				GlobalEventManager.OnHitAll -= new hook_OnHitAll(ObserveBombingOnHitAll);
				bombingHooks = false;
			}
			CleanupBombingFixture();
		}

		private void CleanupBombingFixture()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			bombingCaseActive = false;
			brakingCollective = false;
			prototypeHeld = false;
			prototypeAim = Vector3.zero;
			move = Vector3.zero;
			if (Object.op_Implicit((Object)(object)pilot))
			{
				pilot.inputBank.jump.down = (pilot.inputBank.skill4.down = false);
				if (Object.op_Implicit((Object)(object)bombingSpecialOverride))
				{
					pilot.skillLocator.special.UnsetSkillOverride((object)this, bombingSpecialOverride, (SkillOverridePriority)4);
				}
				if (Object.op_Implicit((Object)(object)bombingUtilityOverride))
				{
					pilot.skillLocator.utility.UnsetSkillOverride((object)this, bombingUtilityOverride, (SkillOverridePriority)4);
				}
				if (Object.op_Implicit((Object)(object)pilot.inventory))
				{
					if (bombingAddedBleed)
					{
						pilot.inventory.RemoveItem(Items.BleedOnHit.itemIndex, 20);
					}
					if (bombingAddedIcbm)
					{
						pilot.inventory.RemoveItem(Items.MoreMissile.itemIndex, 1);
					}
				}
			}
			bombingSpecialOverride = (bombingUtilityOverride = null);
			bombingAddedBleed = (bombingAddedIcbm = false);
			if (Object.op_Implicit((Object)(object)bombingObstruction))
			{
				bombingObstruction.SetActive(false);
				Object.Destroy((Object)(object)bombingObstruction);
			}
			bombingObstruction = null;
			if (NetworkServer.active)
			{
				if (Object.op_Implicit((Object)(object)bombingTarget))
				{
					NetworkServer.Destroy(((Component)bombingTarget).gameObject);
				}
				if (Object.op_Implicit((Object)(object)bombingTargetMaster))
				{
					NetworkServer.Destroy(((Component)bombingTargetMaster).gameObject);
				}
			}
			bombingTarget = null;
			bombingTargetMaster = null;
		}

		private void BombingCheck(string id, bool passed, string actual)
		{
			bombingChecks.Add(new Check
			{
				id = id,
				passed = passed,
				actual = actual,
				scenario = segment
			});
			Event("bombing-check", id + " " + (passed ? "PASS" : "FAIL") + " " + actual);
		}

		private IEnumerator BombingCases()
		{
			bombingStarted = true;
			Event("bombing-scope", "SOLO actual GenericSkill, native World/HealthComponent/DamageReport and downstream Bleed; scripted inputs and owned disposable fixtures. No physical feel, media, peer or complete terrain matrix acceptance.");
			GenericSkill special = pilot.skillLocator.special;
			Variant[] variants = special.skillFamily.variants;
			SkillDef val = Variant(special, typeof(BombingRun));
			BombingCheck("catalog.order", variants.Length == 3 && ((SerializableEntityStateType)(ref variants[0].skillDef.activationState)).stateType == typeof(PaintLongbow) && ((SerializableEntityStateType)(ref variants[1].skillDef.activationState)).stateType == typeof(FireHellfire) && (Object)(object)variants[2].skillDef == (Object)(object)val, string.Join(",", variants.Select((Variant v) => ((SerializableEntityStateType)(ref v.skillDef.activationState)).stateType.Name)));
			BombingCheck("catalog.definition", val.activationStateMachineName == "Weapon2" && val.baseMaxStock == 1 && val.stockToConsume == 1 && val.baseRechargeInterval == 10f && val.mustKeyPress && (int)val.interruptPriority == 1, "machine=" + val.activationStateMachineName + " priority=" + ((object)Unsafe.As<InterruptPriority, InterruptPriority>(ref val.interruptPriority)/*cast due to .constrained prefix*/).ToString() + " stock=" + val.baseMaxStock);
			try
			{
				string[] bombingNames = BombingNames;
				foreach (string name in bombingNames)
				{
					yield return BombingCase(name);
				}
				bombingComplete = true;
			}
			finally
			{
				CleanupBombingProbe();
			}
		}

		private IEnumerator SpawnBombingTarget()
		{
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(mark + facing * 3f + Vector3.up * 6f, Vector3.down, ref val, 20f, LayerMask.op_Implicit(((LayerIndex)(ref LayerIndex.world)).mask), (QueryTriggerInteraction)1))
			{
				throw new InvalidOperationException("Bombing target fixture lacks native terrain.");
			}
			GameObject val2 = MasterCatalog.FindMasterPrefab("GolemMaster");
			if (!Object.op_Implicit((Object)(object)val2))
			{
				throw new InvalidOperationException("Native GolemMaster unavailable.");
			}
			bombingTargetMaster = new MasterSummon
			{
				masterPrefab = val2,
				position = ((RaycastHit)(ref val)).point + Vector3.up,
				rotation = Quaternion.LookRotation(-facing),
				summonerBodyObject = null,
				teamIndexOverride = (TeamIndex)2,
				ignoreTeamMemberLimit = true,
				preSpawnSetupCallback = delegate(CharacterMaster master)
				{
					BaseAI[] components2 = ((Component)master).GetComponents<BaseAI>();
					for (int i = 0; i < components2.Length; i++)
					{
						((Behaviour)components2[i]).enabled = false;
					}
				}
			}.Perform();
			if (!Object.op_Implicit((Object)(object)bombingTargetMaster))
			{
				throw new InvalidOperationException("Native target summon failed.");
			}
			BaseAI[] components = ((Component)bombingTargetMaster).GetComponents<BaseAI>();
			for (int num = 0; num < components.Length; num++)
			{
				((Behaviour)components[num]).enabled = false;
			}
			yield return Until(() => Object.op_Implicit((Object)(object)bombingTargetMaster) && Object.op_Implicit((Object)(object)bombingTargetMaster.GetBody()), 5f, "damageable native Golem body");
			bombingTarget = bombingTargetMaster.GetBody();
			DevAutopilot devAutopilot = this;
			NetworkInstanceId netId = ((NetworkBehaviour)bombingTarget.healthComponent).netId;
			devAutopilot.bombingTargetId = ((NetworkInstanceId)(ref netId)).Value;
			DevAutopilot devAutopilot2 = this;
			netId = ((NetworkBehaviour)bombingTargetMaster).netId;
			devAutopilot2.bombingTargetMasterId = ((NetworkInstanceId)(ref netId)).Value;
			yield return FixedSeconds(0.5f);
			if (bombingTarget.healthComponent.godMode || !bombingTarget.healthComponent.alive || bombingTarget.HasBuff(Buffs.HiddenInvincibility))
			{
				throw new InvalidOperationException("Positive damage fixture is protected or dead.");
			}
			DevAutopilot devAutopilot3 = this;
			BombingFixture obj = new BombingFixture
			{
				recordType = "bombing-fixture",
				runId = Path.GetFileName(output),
				scenario = segment,
				targetId = bombingTargetId
			};
			netId = ((NetworkBehaviour)bombingTargetMaster).netId;
			obj.masterId = ((NetworkInstanceId)(ref netId)).Value;
			obj.health = bombingTarget.healthComponent.health;
			obj.fullHealth = bombingTarget.healthComponent.fullHealth;
			obj.armor = bombingTarget.armor;
			obj.position = bombingTarget.corePosition;
			obj.godMode = bombingTarget.healthComponent.godMode;
			obj.invulnerable = bombingTarget.HasBuff(Buffs.HiddenInvincibility);
			obj.pilotBleedChance = pilot.bleedChance;
			obj.fixture = "native GolemMaster; AI disabled; no health/stat writes, healing or pinning";
			devAutopilot3.Write(obj);
		}

		private AH64BombingRunProjectile[] NativeBombs()
		{
			return (from p in Object.FindObjectsOfType<AH64BombingRunProjectile>()
				where Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)((Component)p).GetComponent<ProjectileController>()) && (Object)(object)((Component)p).GetComponent<ProjectileController>().owner == (Object)(object)((Component)pilot).gameObject
				select p).ToArray();
		}

		private IEnumerator BombingCase(string name)
		{
			CleanupBombingFixture();
			((Component)pilot).GetComponent<AH64HoverController>().ResetAfterTeleport();
			yield return ResetCase("bombing-" + name);
			yield return Until(() => NativeBombs().Length == 0, 8f, "preceding native bombs drain");
			bombingObservations.Clear();
			bombingReports.Clear();
			bombingAcceptedNativeInfo.Clear();
			bombingProjectileIds.Clear();
			bombingDropByProjectile.Clear();
			bombingCastByProjectile.Clear();
			bombingCastId = 0uL;
			DevAutopilot devAutopilot = this;
			DevAutopilot devAutopilot2 = this;
			uint num = 0u;
			devAutopilot2.bombingTargetMasterId = 0u;
			devAutopilot.bombingTargetId = num;
			DevAutopilot devAutopilot3 = this;
			DevAutopilot devAutopilot4 = this;
			int num2 = 0;
			devAutopilot4.bombingOnAll = 0;
			devAutopilot3.bombingOnEnemy = num2;
			bool targetCase = name == "stationary" || name == "bleed";
			bool curve = name == "curve";
			bool invalid = name == "invalid";
			GenericSkill slot = pilot.skillLocator.special;
			SkillDef originalSpecial = slot.skillDef;
			SkillDef originalUtility = pilot.skillLocator.utility.skillDef;
			bombingSpecialOverride = Variant(slot, typeof(BombingRun));
			slot.SetSkillOverride((object)this, bombingSpecialOverride, (SkillOverridePriority)4);
			int bleedBefore = pilot.inventory.GetItemCount(Items.BleedOnHit);
			int icbmBefore = pilot.inventory.GetItemCount(Items.MoreMissile);
			float healthBefore = 0f;
			int stockBefore = 0;
			int stockBeforeRestore = -1;
			bool interrupted = false;
			bool primary = false;
			bool hydra = false;
			bool brake = false;
			bool nativeOverlap = false;
			bool noRefund = false;
			try
			{
				if (name == "bleed")
				{
					pilot.inventory.GiveItem(Items.BleedOnHit, 20);
					bombingAddedBleed = true;
					yield return Until(() => pilot.bleedChance >= 200f, 5f, "actual native bleedChance >=200 at proc0.5");
				}
				if (curve)
				{
					if (icbmBefore != 0)
					{
						throw new InvalidOperationException("Curve fixture requires exactly one isolated ICBM.");
					}
					pilot.inventory.GiveItem(Items.MoreMissile, 1);
					bombingAddedIcbm = true;
					bombingUtilityOverride = Variant(pilot.skillLocator.utility, typeof(BrakingTurn));
					pilot.skillLocator.utility.SetSkillOverride((object)this, bombingUtilityOverride, (SkillOverridePriority)4);
					yield return Until(() => pilot.skillLocator.utility.CanExecute(), 12f, "curve braking readiness");
				}
				if (targetCase)
				{
					yield return SpawnBombingTarget();
					healthBefore = bombingTarget.healthComponent.health;
				}
				yield return Until(() => slot.CanExecute() && (!curve || (pilot.skillLocator.primary.CanExecute() && pilot.skillLocator.secondary.CanExecute())), 15f, "native bombing readiness");
				if (!AH64BombingRunCast.SafeOrigin(pilot.corePosition, pilot.corePosition + Vector3.down * 0.5f))
				{
					throw new InvalidOperationException("Native origin invalid before owned fixture.");
				}
				if (invalid)
				{
					bombingObstruction = new GameObject("AH64OwnedBombingInvalidOriginFixture");
					bombingObstruction.layer = LayerIndex.world.intVal;
					bombingObstruction.transform.SetParent(((Component)pilot).gameObject.transform, true);
					bombingObstruction.transform.position = pilot.corePosition + Vector3.down * 0.25f;
					bombingObstruction.AddComponent<BoxCollider>().size = Vector3.one;
					Physics.SyncTransforms();
					if (AH64BombingRunCast.SafeOrigin(pilot.corePosition, pilot.corePosition + Vector3.down * 0.5f))
					{
						throw new InvalidOperationException("Actual native World obstruction did not reject origin.");
					}
				}
				if (curve)
				{
					move = facing;
					prototypeAim = facing;
					brakingCollective = true;
					pilot.inputBank.jump.down = true;
				}
				bombingCaseActive = true;
				stockBefore = slot.stock;
				bool accepted = slot.ExecuteIfReady();
				yield return Until(() => Machine("Weapon2").state is BombingRun, 2f, "native bombing Weapon2 entry");
				EntityState state = Machine("Weapon2").state;
				BombingCheck(name + ".activation", accepted && stockBefore > 0 && slot.stock == stockBefore - 1 && bombingCastId != 0, "accepted=" + accepted + " stock=" + stockBefore + "->" + slot.stock + " nativeCast=" + bombingCastId);
				if (curve)
				{
					yield return FixedSeconds(0.4f);
					move = Quaternion.AngleAxis(70f, Vector3.up) * facing;
					prototypeAim = move;
					pilot.inputBank.moveVector = move;
					pilot.inputBank.aimDirection = move;
					brake = pilot.skillLocator.utility.ExecuteIfReady();
					primary = pilot.skillLocator.primary.ExecuteIfReady();
					hydra = pilot.skillLocator.secondary.ExecuteIfReady();
					yield return (object)new WaitForFixedUpdate();
					nativeOverlap = Machine("Weapon2").state == state && Machine("Body").state is BrakingTurn && Machine("Weapon").state is FireChaingun && Machine("Weapon3").state is FireRocketPods;
					Event("bombing-native-overlap", "primary=" + primary + " hydra=" + hydra + " brake=" + brake + " actual=" + ((object)Machine("Body").state).GetType().Name + "/" + ((object)Machine("Weapon").state).GetType().Name + "/" + ((object)Machine("Weapon3").state).GetType().Name);
				}
				if (name == "interrupt")
				{
					yield return FixedSeconds(0.45f);
					interrupted = Machine("Weapon2").SetInterruptState((EntityState)new Idle(), (InterruptPriority)5);
				}
				yield return Until(() => Machine("Weapon2").state != state, 3f, "finite native bombing exit");
				int consumedAtExit = Opportunities().Length;
				brakingCollective = false;
				pilot.inputBank.jump.down = false;
				move = Vector3.zero;
				prototypeAim = Vector3.zero;
				yield return Until(() => NativeBombs().Length == 0, 8f, "native bombing lifetime drain");
				if (name == "bleed")
				{
					yield return FixedSeconds(1f);
				}
				BombingObservation[] array = Opportunities();
				BombingObservation[] releases = bombingObservations.Where((BombingObservation o) => o.kind == "release").ToArray();
				BombingObservation[] array2 = bombingObservations.Where((BombingObservation o) => o.kind == "impact" || o.kind == "despawn").ToArray();
				BombingObservation[] array3 = bombingObservations.Where((BombingObservation o) => o.kind == "hit" && o.targetId == bombingTargetId).ToArray();
				BombingDamage[] direct = bombingReports.Where((BombingDamage r) => r.bomb && r.targetId == bombingTargetId && r.damageDealt > 0f && !r.rejected).ToArray();
				BombingObservation[] array4 = bombingObservations.Where((BombingObservation o) => o.kind == "end").ToArray();
				int num3 = ((name == "interrupt") ? consumedAtExit : 6);
				bool flag = array.Length == num3 && array.Select((BombingObservation o) => o.dropIndex).Distinct().Count() == num3 && (from o in array
					select o.dropIndex into i
					orderby i
					select i).SequenceEqual(Enumerable.Range(0, num3)) && array.All((BombingObservation o) => Mathf.Abs(o.scheduledTime - (float)o.dropIndex * 0.3f) < 0.001f && o.actualTime >= o.scheduledTime - 0.001f && o.actualTime - o.scheduledTime < 0.2f) && bombingProjectileIds.Count == releases.Length && releases.All((BombingObservation o) => o.projectileId != 0) && array2.Length == releases.Length && array2.Select((BombingObservation o) => o.dropIndex).Distinct().Count() == releases.Length && array2.All((BombingObservation t) => releases.Any((BombingObservation r) => r.dropIndex == t.dropIndex && t.time >= r.time && t.time - r.time <= 6.2f)) && array4.Length == 1 && array4[0].reason == ((name == "interrupt") ? "interrupted" : "complete");
				if (name == "interrupt")
				{
					flag &= interrupted && num3 > 0 && num3 < 6 && array.Length == consumedAtExit;
				}
				BombingCheck(passed: (!invalid) ? (flag & (releases.Length == num3)) : (flag & (releases.Length == 0 && array.All((BombingObservation o) => o.kind == "suppressed" && o.reason == "invalid-or-obstructed-origin"))), id: name + ".opportunities", actual: "due=" + array.Length + " releases=" + releases.Length + " actualProjectileIds=" + bombingProjectileIds.Count + " end=" + string.Join(",", array4.Select((BombingObservation o) => o.reason)) + " interrupted=" + interrupted);
				bool flag2 = releases.All(delegate(BombingObservation o)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					//IL_002c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_003b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0040: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					//IL_0055: Unknown result type (might be due to invalid IL or missing references)
					//IL_0075: Unknown result type (might be due to invalid IL or missing references)
					//IL_007f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0084: Unknown result type (might be due to invalid IL or missing references)
					//IL_008e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0093: Unknown result type (might be due to invalid IL or missing references)
					//IL_0098: Unknown result type (might be due to invalid IL or missing references)
					//IL_009d: Unknown result type (might be due to invalid IL or missing references)
					if (Finite(o.position) && Finite(o.velocity))
					{
						Vector3 val3 = o.position - (o.nativeCore + Vector3.down * 0.5f);
						if (((Vector3)(ref val3)).magnitude < 0.001f)
						{
							val3 = o.velocity - (Vector3.ClampMagnitude(new Vector3(o.nativeVelocity.x, 0f, o.nativeVelocity.z), 25f) + Vector3.down * 4f);
							return ((Vector3)(ref val3)).magnitude < 0.001f;
						}
					}
					return false;
				});
				float num4 = 0f;
				if (curve && releases.Length >= 4)
				{
					Vector3 val = releases[2].position - releases[0].position;
					Vector3 val2 = releases[releases.Length - 1].position - releases[2].position;
					val.y = (val2.y = 0f);
					num4 = ((((Vector3)(ref val)).magnitude > 0.1f && ((Vector3)(ref val2)).magnitude > 0.1f) ? Vector3.Angle(val, val2) : 0f);
					flag2 &= num4 > 5f && primary && hydra && brake && nativeOverlap && releases.All((BombingObservation o) => AH64BombingRunCast.Finite(o.airtime) && AH64BombingRunCast.Finite(o.targetHeight) && o.airtime >= 0f && o.icbmCount == 1 && o.jumpHeld) && releases.Any((BombingObservation o) => o.ascending);
				}
				BombingCheck(name + ".motion", flag2 && (!curve || releases.Length == 6), "same-time native release origin/velocity agreement; path bend=" + num4 + "; simultaneous native states=" + nativeOverlap);
				bool flag3 = (targetCase ? (array3.Length == 3 && direct.Length == 3 && array3.All((BombingObservation h) => h.damage > 0f && Mathf.Abs(h.procCoefficient - 0.5f) < 0.001f) && direct.All((BombingDamage d) => Mathf.Abs(d.procCoefficient - 0.5f) < 0.001f && d.castId == bombingCastId) && direct.Select((BombingDamage d) => d.dropIndex).Distinct().Count() == 3 && array3.Select((BombingObservation h) => h.dropIndex).Distinct().Count() == 3 && (from d in direct
					select d.dropIndex into i
					orderby i
					select i).SequenceEqual(from h in array3
					select h.dropIndex into i
					orderby i
					select i) && bombingOnEnemy == 3 && bombingOnAll == 3 && bombingObservations.Any((BombingObservation o) => o.kind == "hit-suppressed" && o.targetId == bombingTargetId && o.reason == "overlap-budget")) : (!invalid || bombingReports.Count == 0));
				int num5 = bombingReports.Count((BombingDamage r) => r.dot == ((object)(DotIndex)0/*cast due to .constrained prefix*/).ToString() && r.targetId == bombingTargetId && r.damageDealt > 0f && !r.rejected);
				if (name == "bleed")
				{
					flag3 &= pilot.bleedChance >= 200f && num5 > 0 && direct.Any() && bombingReports.Any((BombingDamage r) => r.dot == ((object)(DotIndex)0/*cast due to .constrained prefix*/).ToString() && r.time >= direct[0].time && r.targetId == bombingTargetId && r.damageDealt > 0f);
				}
				flag3 &= bombingReports.All((BombingDamage r) => AH64BombingRunCast.Finite(r.damageDealt) && AH64BombingRunCast.Finite(r.rawDamage) && AH64BombingRunCast.Finite(r.procCoefficient));
				BombingCheck(name + ".payload", flag3, "native direct=" + direct.Length + " trace accepted=" + array3.Length + " native Bleed=" + num5 + " separate OnHitEnemy/All=" + bombingOnEnemy + "/" + bombingOnAll + " bleedChance=" + pilot.bleedChance + " HP=" + healthBefore + "->" + (Object.op_Implicit((Object)(object)bombingTarget) ? bombingTarget.healthComponent.health : (-1f)) + "; HP delta includes regeneration and is not raw coefficient proof");
				stockBeforeRestore = slot.stock;
				noRefund = stockBeforeRestore == stockBefore - 1;
			}
			finally
			{
				CleanupBombingFixture();
			}
			Physics.SyncTransforms();
			yield return (object)new WaitForFixedUpdate();
			bool flag4 = bombingTargetId != 0 && Object.FindObjectsOfType<CharacterBody>().Any(delegate(CharacterBody b)
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)b) && Object.op_Implicit((Object)(object)b.healthComponent))
				{
					NetworkInstanceId netId = ((NetworkBehaviour)b.healthComponent).netId;
					return ((NetworkInstanceId)(ref netId)).Value == bombingTargetId;
				}
				return false;
			});
			bool flag5 = bombingTargetMasterId != 0 && Object.FindObjectsOfType<CharacterMaster>().Any(delegate(CharacterMaster m)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)m))
				{
					NetworkInstanceId netId = ((NetworkBehaviour)m).netId;
					return ((NetworkInstanceId)(ref netId)).Value == bombingTargetMasterId;
				}
				return false;
			});
			bool flag6 = !Object.op_Implicit((Object)(object)bombingSpecialOverride) && !Object.op_Implicit((Object)(object)bombingUtilityOverride) && (Object)(object)slot.skillDef == (Object)(object)originalSpecial && (Object)(object)pilot.skillLocator.utility.skillDef == (Object)(object)originalUtility;
			Write(new BombingCleanup
			{
				recordType = "bombing-cleanup",
				runId = Path.GetFileName(output),
				scenario = segment,
				time = Time.fixedTime,
				castId = bombingCastId,
				bombs = NativeBombs().Length,
				targetAlive = flag4,
				targetMasterAlive = flag5,
				obstructionAlive = ((Object)(object)bombingObstruction != (Object)null),
				stockBefore = stockBefore,
				stockBeforeRestore = stockBeforeRestore,
				bleedBefore = bleedBefore,
				bleedAfter = pilot.inventory.GetItemCount(Items.BleedOnHit),
				icbmBefore = icbmBefore,
				icbmAfter = pilot.inventory.GetItemCount(Items.MoreMissile),
				noRefund = noRefund,
				originValid = AH64BombingRunCast.SafeOrigin(pilot.corePosition, pilot.corePosition + Vector3.down * 0.5f),
				weapon2State = ((object)Machine("Weapon2").state).GetType().Name,
				overrideReferencesReleased = flag6
			});
			BombingCheck(name + ".cleanup", !Object.op_Implicit((Object)(object)bombingObstruction) && !flag4 && !flag5 && flag6 && !bombingAddedBleed && !bombingAddedIcbm && pilot.inventory.GetItemCount(Items.BleedOnHit) == bleedBefore && pilot.inventory.GetItemCount(Items.MoreMissile) == icbmBefore && NativeBombs().Length == 0 && !(Machine("Weapon2").state is BombingRun) && noRefund && AH64BombingRunCast.SafeOrigin(pilot.corePosition, pilot.corePosition + Vector3.down * 0.5f), "owned target/world fixture/overrides/items removed; native payloads drained; no refund; origin valid");
		}

		private BombingObservation[] Opportunities()
		{
			return bombingObservations.Where((BombingObservation o) => o.kind == "release" || (o.kind == "suppressed" && o.reason == "invalid-or-obstructed-origin")).ToArray();
		}

		private void ObserveBombingTrace(AH64BombingRunTrace.Record value)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			if (!bombingCaseActive || finished || !Object.op_Implicit((Object)(object)pilot) || value == null)
			{
				return;
			}
			uint ownerId = value.ownerId;
			NetworkInstanceId netId = ((NetworkBehaviour)pilot).netId;
			if (ownerId != ((NetworkInstanceId)(ref netId)).Value)
			{
				return;
			}
			if (value.kind == "begin")
			{
				if (bombingCastId != 0L)
				{
					throw new InvalidOperationException("Multiple native casts in one fixture.");
				}
				bombingCastId = value.castId;
			}
			if (value.castId != bombingCastId)
			{
				return;
			}
			int num = 0;
			if (value.kind == "release")
			{
				AH64BombingRunProjectile[] array = (from p in NativeBombs()
					where !bombingProjectileIds.Contains(((Object)((Component)p).gameObject).GetInstanceID())
					select p).ToArray();
				if (array.Length == 1)
				{
					num = ((Object)((Component)array[0]).gameObject).GetInstanceID();
					bombingProjectileIds.Add(num);
					bombingDropByProjectile[num] = value.dropIndex;
					bombingCastByProjectile[num] = value.castId;
				}
			}
			AH64HoverController component = ((Component)pilot).GetComponent<AH64HoverController>();
			BombingObservation bombingObservation = new BombingObservation
			{
				recordType = "bombing-observation",
				runId = Path.GetFileName(output),
				scenario = segment,
				castId = value.castId,
				ownerId = value.ownerId,
				targetId = value.targetId,
				kind = value.kind,
				reason = value.reason,
				dropIndex = value.dropIndex,
				scheduledTime = value.scheduledTime,
				actualTime = value.actualTime,
				time = Time.fixedTime,
				position = value.position,
				velocity = value.velocity,
				nativeCore = pilot.corePosition,
				nativeVelocity = pilot.characterMotor.velocity,
				projectileId = num,
				damage = value.damage,
				procCoefficient = value.procCoefficient,
				acceptedHits = value.acceptedHits,
				remainingBaseCoefficient = value.remainingBaseCoefficient,
				crit = value.crit,
				airtime = component.Airtime,
				targetHeight = component.TargetHeight,
				icbmCount = pilot.inventory.GetItemCountEffective(Items.MoreMissile),
				jumpHeld = pilot.inputBank.jump.down,
				ascending = component.IsAscending,
				bodyState = ((object)Machine("Body").state).GetType().Name,
				weapon2State = ((object)Machine("Weapon2").state).GetType().Name
			};
			bombingObservations.Add(bombingObservation);
			Write(bombingObservation);
		}

		private bool OwnedBomb(DamageInfo info)
		{
			if (info != null && Object.op_Implicit((Object)(object)pilot) && (Object)(object)info.attacker == (Object)(object)((Component)pilot).gameObject && Object.op_Implicit((Object)(object)info.inflictor))
			{
				return Object.op_Implicit((Object)(object)info.inflictor.GetComponent<AH64BombingRunDamage>());
			}
			return false;
		}

		private void ObserveBombingDamage(DamageReport report)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			if (!bombingCaseActive || finished || report == null || !Object.op_Implicit((Object)(object)pilot) || (Object)(object)report.attacker != (Object)(object)((Component)pilot).gameObject)
			{
				return;
			}
			DamageInfo damageInfo = report.damageInfo;
			int num = (Object.op_Implicit((Object)(object)damageInfo.inflictor) ? ((Object)damageInfo.inflictor).GetInstanceID() : 0);
			bool flag = OwnedBomb(damageInfo);
			NetworkInstanceId netId;
			if (flag && Object.op_Implicit((Object)(object)report.victim))
			{
				netId = ((NetworkBehaviour)report.victim).netId;
				if (((NetworkInstanceId)(ref netId)).Value == bombingTargetId && report.damageDealt > 0f && AH64BombingRunCast.Finite(report.damageDealt) && !damageInfo.rejected)
				{
					bombingAcceptedNativeInfo.Add(damageInfo);
				}
			}
			ulong value;
			int value2;
			BombingDamage obj = new BombingDamage
			{
				recordType = "bombing-damage",
				runId = Path.GetFileName(output),
				scenario = segment,
				castId = (bombingCastByProjectile.TryGetValue(num, out value) ? value : 0),
				dropIndex = (bombingDropByProjectile.TryGetValue(num, out value2) ? value2 : (-1))
			};
			netId = ((NetworkBehaviour)pilot).netId;
			obj.ownerId = ((NetworkInstanceId)(ref netId)).Value;
			int targetId;
			if (!Object.op_Implicit((Object)(object)report.victim))
			{
				targetId = 0;
			}
			else
			{
				netId = ((NetworkBehaviour)report.victim).netId;
				targetId = (int)((NetworkInstanceId)(ref netId)).Value;
			}
			obj.targetId = (uint)targetId;
			obj.projectileId = num;
			obj.time = Time.fixedTime;
			obj.bomb = flag;
			obj.dot = ((object)Unsafe.As<DotIndex, DotIndex>(ref report.dotType)/*cast due to .constrained prefix*/).ToString();
			obj.damageDealt = report.damageDealt;
			obj.rawDamage = damageInfo.damage;
			obj.procCoefficient = damageInfo.procCoefficient;
			obj.crit = damageInfo.crit;
			obj.rejected = damageInfo.rejected;
			BombingDamage bombingDamage = obj;
			bombingReports.Add(bombingDamage);
			Write(bombingDamage);
		}

		private void ObserveBombingOnHitEnemy(orig_OnHitEnemy orig, GlobalEventManager self, DamageInfo info, GameObject victim)
		{
			if (bombingCaseActive && !finished && OwnedBomb(info) && bombingAcceptedNativeInfo.Contains(info) && Object.op_Implicit((Object)(object)bombingTarget) && (Object)(object)victim == (Object)(object)((Component)bombingTarget).gameObject)
			{
				bombingOnEnemy++;
				Event("bombing-native-OnHitEnemy", "projectile=" + ((Object)info.inflictor).GetInstanceID() + " victim=" + ((Object)victim).GetInstanceID());
			}
			orig.Invoke(self, info, victim);
		}

		private void ObserveBombingOnHitAll(orig_OnHitAll orig, GlobalEventManager self, DamageInfo info, GameObject victim)
		{
			if (bombingCaseActive && !finished && OwnedBomb(info) && bombingAcceptedNativeInfo.Contains(info) && Object.op_Implicit((Object)(object)bombingTarget) && (Object)(object)victim == (Object)(object)((Component)bombingTarget).gameObject)
			{
				bombingOnAll++;
				Event("bombing-native-OnHitAll", "projectile=" + ((Object)info.inflictor).GetInstanceID() + " victim=" + (Object.op_Implicit((Object)(object)victim) ? ((Object)victim).GetInstanceID() : 0));
			}
			orig.Invoke(self, info, victim);
		}

		private bool FinishBombingEvidence()
		{
			if (Environment.GetEnvironmentVariable("AH64_AUTOPILOT_BOMBING_CHECKS") != "bombing-solo-v1")
			{
				return true;
			}
			string[] array = new string[2] { "catalog.order", "catalog.definition" }.Concat(BombingNames.SelectMany((string n) => BombingChecks.Select((string c) => n + "." + c))).ToArray();
			bool flag = bombingStarted && bombingComplete && !bombingHooks && !bombingCaseActive && bombingChecks.Count == array.Length && bombingChecks.All((Check c) => c.passed) && bombingChecks.Select((Check c) => c.id).Distinct().Count() == array.Length && !array.Except(bombingChecks.Select((Check c) => c.id)).Any();
			File.WriteAllText(Path.Combine(output, "bombing-result.json"), JsonUtility.ToJson((object)new BombingResult
			{
				runId = Path.GetFileName(output),
				sourceSha = JsonUtility.FromJson<StageIdentity>(File.ReadAllText(Path.Combine(output, "identity.json"))).sourceSha,
				dllSha256 = Hash(typeof(AH64Plugin).Assembly.Location),
				suite = "bombing-solo-v1",
				status = (flag ? "passed" : "failed"),
				complete = bombingComplete,
				expectedChecks = array.Length,
				expectedIds = array,
				checks = bombingChecks.ToArray(),
				hooksReleased = !bombingHooks,
				limitation = "Bounded scripted SOLO native smoke. Raw reports, cast/owner/target/drop/time retained; OnHit callbacks are distinct from actual downstream Bleed. No physical bindings/feel, peer, long-session, full natural terrain, audio or authentic media acceptance. Raw strict runtime outcomes remain independently blocking/classifiable."
			}, true));
			return flag;
		}

		private void OnBombingTrace(AH64BombingRunTrace.Record value)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (scripting && !finished && Object.op_Implicit((Object)(object)pilot) && value != null)
			{
				uint ownerId = value.ownerId;
				NetworkInstanceId netId = ((NetworkBehaviour)pilot).netId;
				if (ownerId == ((NetworkInstanceId)(ref netId)).Value)
				{
					Event("bombing-" + value.kind, JsonUtility.ToJson((object)new BombingPayload
					{
						castId = value.castId,
						ownerId = value.ownerId,
						kind = value.kind,
						reason = value.reason,
						dropIndex = value.dropIndex,
						scheduledTime = value.scheduledTime,
						actualTime = value.actualTime,
						position = value.position,
						velocity = value.velocity,
						targetId = value.targetId,
						acceptedHits = value.acceptedHits,
						remainingBaseCoefficient = value.remainingBaseCoefficient,
						damage = value.damage,
						procCoefficient = value.procCoefficient,
						crit = value.crit
					}));
				}
			}
		}

		private static void DisableCombatDirectors()
		{
			CombatDirector[] array = CombatDirector.instancesList.ToArray();
			foreach (CombatDirector val in array)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					((Behaviour)val).enabled = false;
				}
			}
		}

		private void OnNetworkStarted(NetworkUser networkUser)
		{
			if (((NetworkBehaviour)networkUser).isLocalPlayer)
			{
				startedNetworkUser = networkUser;
				Event("bootstrap-network-started", "completed NetworkUser.Start; preference=" + ((object)Unsafe.As<BodyIndex, BodyIndex>(ref networkUser.bodyIndexPreference)/*cast due to .constrained prefix*/).ToString());
			}
		}

		private IEnumerator Bootstrap()
		{
			yield return BootstrapWait(delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene2 = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene2)).name;
				if (gameLoaded && name != "title" && name != "splash")
				{
					IntroCutsceneController.shouldSkip = true;
				}
				return gameLoaded && name == "title" && LocalUserManager.GetFirstLocalUser() != null;
			}, 90f, "title/local-user", null);
			LocalUser user = LocalUserManager.GetFirstLocalUser();
			if (LocalUserManager.readOnlyLocalUsersList.Count != 1 || Object.op_Implicit((Object)(object)user.currentNetworkUser) || NetworkServer.active || NetworkClient.active)
			{
				throw new InvalidOperationException("Bootstrap requires one offline local user before hosting: " + BootstrapSnapshot(user));
			}
			UserProfile profile = user.userProfile;
			if (profile == null)
			{
				throw new InvalidOperationException("No player profile for save protection.");
			}
			profile.canSave = false;
			profile.saveRequestPending = false;
			Event("save-protection", "loaded player profile canSave=false for this diagnostic process; no disk save changes");
			SurvivorDef survivor = null;
			yield return BootstrapWait(delegate
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Invalid comparison between Unknown and I4
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				expectedBody = BodyCatalog.FindBodyIndex("AH64Body");
				survivor = SurvivorCatalog.GetSurvivorDef(SurvivorCatalog.GetSurvivorIndexFromBodyIndex(expectedBody));
				return (int)expectedBody != -1 && Object.op_Implicit((Object)(object)survivor) && Object.op_Implicit((Object)(object)survivor.bodyPrefab) && BodyCatalog.FindBodyIndex(survivor.bodyPrefab) == expectedBody;
			}, 15f, "AH64-catalog", user);
			SurvivorDef survivorPreference = profile.GetSurvivorPreference();
			Event("bootstrap-profile", "prior=" + (Object.op_Implicit((Object)(object)survivorPreference) ? survivorPreference.cachedName : "null") + "; selecting=" + survivor.cachedName + "; body=" + ((object)Unsafe.As<BodyIndex, BodyIndex>(ref expectedBody)/*cast due to .constrained prefix*/).ToString());
			profile.SetSurvivorPreference(survivor);
			if (profile.canSave || (Object)(object)profile.GetSurvivorPreference() != (Object)(object)survivor)
			{
				throw new InvalidOperationException("Protected in-memory AH64 selection was not retained.");
			}
			Console.instance.SubmitCmd((NetworkUser)null, "transition_command \"gamemode ClassicRun; host 0;\"", false);
			yield return BootstrapWait(() => Object.op_Implicit((Object)(object)PreGameController.instance) && Object.op_Implicit((Object)(object)user.currentNetworkUser) && (Object)(object)startedNetworkUser == (Object)(object)user.currentNetworkUser && NetworkServer.active && NetworkClient.active && NetworkUser.readOnlyInstancesList.Count == 1 && ((NetworkBehaviour)user.currentNetworkUser).isLocalPlayer && ((NetworkBehaviour)user.currentNetworkUser).hasAuthority, 45f, "solo-lobby/NetworkUser.Start", user);
			user.currentNetworkUser.SetSurvivorPreferenceClient(survivor);
			yield return BootstrapWait(() => user.currentNetworkUser.bodyIndexPreference == expectedBody, 10f, "AH64-selection-acknowledged", user);
			if (!Object.op_Implicit((Object)(object)PreGameController.instance))
			{
				throw new InvalidOperationException("Lobby launched before explicit launch.");
			}
			PreGameController.instance.runSeed = 1301uL;
			Random.InitState(1301);
			Event("bootstrap-launch", BootstrapSnapshot(user));
			PreGameController.instance.StartLaunch();
			yield return BootstrapWait(() => Object.op_Implicit((Object)(object)Run.instance) && Object.op_Implicit((Object)(object)user.cachedBody) && BodyProblem(user).Length == 0, 60f, "first-body/AH64-prerequisites", user);
			RequireBody(user);
			SceneDef val = SceneCatalog.FindSceneDef("golemplains");
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Fixed arena missing.");
			}
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name != "golemplains")
			{
				CharacterBody previousBody = user.cachedBody;
				Run.instance.AdvanceStage(val);
				yield return BootstrapWait(delegate
				{
					//IL_0000: Unknown result type (might be due to invalid IL or missing references)
					//IL_0005: Unknown result type (might be due to invalid IL or missing references)
					Scene activeScene2 = SceneManager.GetActiveScene();
					return ((Scene)(ref activeScene2)).name == "golemplains" && Object.op_Implicit((Object)(object)user.cachedBody) && user.cachedBody != previousBody && BodyProblem(user).Length == 0;
				}, 60f, "fixed-arena/new-body", user);
			}
			yield return (object)new WaitForSecondsRealtime(2f);
			RequireBody(user);
			pilot = user.cachedBody;
			Event("bootstrap-ready", BootstrapSnapshot(user));
		}

		private void RequireBody(LocalUser user)
		{
			string text = BodyProblem(user);
			if (text.Length != 0)
			{
				throw new InvalidOperationException("AH64 prerequisite: " + text + "; " + BootstrapSnapshot(user));
			}
		}

		private string BodyProblem(LocalUser user)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody cachedBody = user.cachedBody;
			if (!Object.op_Implicit((Object)(object)cachedBody))
			{
				return "missing body";
			}
			if (cachedBody.bodyIndex != expectedBody)
			{
				return "wrong body index";
			}
			if (!((NetworkBehaviour)cachedBody).hasAuthority)
			{
				return "body lacks authority";
			}
			if (!Object.op_Implicit((Object)(object)cachedBody.characterMotor))
			{
				return "missing CharacterMotor";
			}
			if (!Object.op_Implicit((Object)(object)cachedBody.inputBank))
			{
				return "missing InputBankTest";
			}
			if (!Object.op_Implicit((Object)(object)cachedBody.characterDirection))
			{
				return "missing CharacterDirection";
			}
			if (!Object.op_Implicit((Object)(object)cachedBody.modelLocator))
			{
				return "missing ModelLocator";
			}
			if (!Object.op_Implicit((Object)(object)cachedBody.modelLocator.modelTransform))
			{
				return "missing model transform";
			}
			if (!Object.op_Implicit((Object)(object)user.cachedMaster) || !Object.op_Implicit((Object)(object)user.cachedMasterController) || (Object)(object)user.cachedMasterController.master != (Object)(object)user.cachedMaster || (Object)(object)user.cachedMaster.GetBody() != (Object)(object)cachedBody)
			{
				return "local master/controller/body control-chain mismatch";
			}
			string[] array = new string[2] { "Body", "Weapon2" };
			foreach (string name in array)
			{
				EntityStateMachine[] array2 = (from m in ((Component)cachedBody).GetComponents<EntityStateMachine>()
					where m.customName == name
					select m).ToArray();
				if (array2.Length != 1 || array2[0].state == null)
				{
					return "missing/ambiguous/uninitialized state machine " + name;
				}
			}
			return "";
		}

		private IEnumerator BootstrapWait(Func<bool> predicate, float timeout, string phase, LocalUser user)
		{
			segment = "bootstrap:" + phase;
			float end = Time.realtimeSinceStartup + timeout;
			string previous = null;
			string text;
			while (true)
			{
				bool num = predicate();
				text = BootstrapSnapshot(user);
				if (text != previous)
				{
					Event("bootstrap-wait", phase + "; " + text);
					previous = text;
				}
				if (num)
				{
					Event("bootstrap-phase-ready", phase + "; " + text);
					yield break;
				}
				if (Time.realtimeSinceStartup > end)
				{
					break;
				}
				yield return null;
			}
			throw new TimeoutException("bootstrap " + phase + "; " + text);
		}

		private string BootstrapSnapshot(LocalUser user)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			NetworkUser val = ((user == null) ? null : user.currentNetworkUser);
			CharacterBody val2 = ((user == null) ? null : user.cachedBody);
			string[] array = new string[22];
			array[0] = "scene=";
			Scene activeScene = SceneManager.GetActiveScene();
			array[1] = ((Scene)(ref activeScene)).name;
			array[2] = "; expectedBody=";
			array[3] = ((object)Unsafe.As<BodyIndex, BodyIndex>(ref expectedBody)/*cast due to .constrained prefix*/).ToString();
			array[4] = "; localUsers=";
			array[5] = LocalUserManager.readOnlyLocalUsersList.Count.ToString();
			array[6] = "; networkUsers=";
			array[7] = NetworkUser.readOnlyInstancesList.Count.ToString();
			array[8] = "; server=";
			array[9] = NetworkServer.active.ToString();
			array[10] = "; client=";
			array[11] = NetworkClient.active.ToString();
			array[12] = "; networkStarted=";
			array[13] = (Object.op_Implicit((Object)(object)val) && (Object)(object)startedNetworkUser == (Object)(object)val).ToString();
			array[14] = "; preference=";
			array[15] = (Object.op_Implicit((Object)(object)val) ? ((object)Unsafe.As<BodyIndex, BodyIndex>(ref val.bodyIndexPreference)/*cast due to .constrained prefix*/).ToString() : "none");
			array[16] = "; body=";
			array[17] = (Object.op_Implicit((Object)(object)val2) ? (((Object)((Component)val2).gameObject).name + "/" + ((object)Unsafe.As<BodyIndex, BodyIndex>(ref val2.bodyIndex)/*cast due to .constrained prefix*/).ToString()) : "none");
			array[18] = "; authority=";
			array[19] = (Object.op_Implicit((Object)(object)val2) && ((NetworkBehaviour)val2).hasAuthority).ToString();
			array[20] = "; prerequisite=";
			array[21] = ((user == null) ? "no local user" : BodyProblem(user));
			return string.Concat(array);
		}

		private void BrakingCheck(string id, bool passed, string actual)
		{
			brakingChecks.Add(new Check
			{
				id = id,
				passed = passed,
				actual = actual,
				scenario = segment
			});
			Event("braking-check", id + " " + (passed ? "PASS" : "FAIL") + " " + actual);
		}

		private IEnumerator BrakingCases()
		{
			if (Environment.GetEnvironmentVariable("AH64_AUTOPILOT_BRAKING_CHECKS") == "braking-solo-v1")
			{
				throw new InvalidOperationException("braking-solo-v1 is retired for Banked Break. Use the four pilot-visible cases in tools/braking-turn/BANKED-BREAK-HANDOFF.md.");
			}
			brakingStarted = true;
			Event("braking-scope", "braking-solo-v1: actual SOLO skill/stock and native PreMove; scripted aim, held collective, initial momentum, inventory and overrides. No physical input, peer, collision/item, target-hit or audio acceptance.");
			GenericSkill utility = pilot.skillLocator.utility;
			Variant[] variants = utility.skillFamily.variants;
			SkillDef val = Variant(utility, typeof(BrakingTurn));
			BrakingCheck("catalog.order", variants.Length == 3 && ((SerializableEntityStateType)(ref variants[0].skillDef.activationState)).stateType == typeof(ServoDash) && ((SerializableEntityStateType)(ref variants[1].skillDef.activationState)).stateType == typeof(SmokeBackflip) && (Object)(object)variants[2].skillDef == (Object)(object)val, string.Join(",", variants.Select((Variant v) => ((SerializableEntityStateType)(ref v.skillDef.activationState)).stateType.Name)) + "; current default=" + utility.skillDef.skillName);
			BrakingCheck("catalog.definition", val.activationStateMachineName == "Body" && val.baseMaxStock == 1 && val.baseRechargeInterval == 4f && val.stockToConsume == 1 && AH64BrakingTurnAcceptance.Priority(val.interruptPriority) && val.mustKeyPress && Object.op_Implicit((Object)(object)val.icon), "machine=" + val.activationStateMachineName + " stock=" + val.baseMaxStock + " recharge=" + val.baseRechargeInterval + " priority=" + ((object)Unsafe.As<InterruptPriority, InterruptPriority>(ref val.interruptPriority)/*cast due to .constrained prefix*/).ToString() + "; placeholder icon=" + (Object.op_Implicit((Object)(object)val.icon) ? ((Object)val.icon).name : "missing"));
			string[] brakingCaseNames = BrakingCaseNames;
			foreach (string name in brakingCaseNames)
			{
				yield return BrakingMotionCase(name);
			}
			yield return BrakingGuidanceCase();
			brakingComplete = true;
		}

		private IEnumerator ResetBrakingCase(string name)
		{
			brakingCollective = false;
			prototypeAim = Vector3.zero;
			move = Vector3.zero;
			((Component)pilot).GetComponent<AH64HoverController>().ResetAfterTeleport();
			yield return ResetCase(name);
			Event("braking-fixture", "teleport plus body-owned hover reset; no private stat writes or airtime restoration");
		}

		private unsafe IEnumerator BrakingMotionCase(string name)
		{
			yield return ResetBrakingCase("braking-" + name);
			GenericSkill slot = pilot.skillLocator.utility;
			SkillDef skill = Variant(slot, typeof(BrakingTurn));
			AH64HoverController hover = ((Component)pilot).GetComponent<AH64HoverController>();
			AH64FlightVisuals visuals = ((Component)pilot).GetComponent<AH64FlightVisuals>();
			CameraTargetParams camera = ((Component)pilot).GetComponent<CameraTargetParams>();
			bool spare = name == "spare";
			bool collective = name == "collective";
			bool interruption = name == "interrupt";
			bool removedSafety = false;
			if (spare)
			{
				pilot.inventory.GiveItem(Items.UtilitySkillMagazine, 1);
			}
			slot.SetSkillOverride((object)this, skill, (SkillOverridePriority)4);
			try
			{
				yield return Until(() => slot.CanExecute() && (!spare || slot.maxStock >= 2), 12f, "braking readiness");
				if (spare && slot.stock < 2)
				{
					slot.RestockSteplike();
				}
				yield return Until(() => !spare || slot.stock >= 2, 12f, "braking spare stock");
				if (hover.GroundDistance < 0f || hover.GroundDistance > 8f)
				{
					throw new InvalidOperationException("Braking fixture lacks safe low terrain: " + hover.GroundDistance);
				}
				if (collective)
				{
					brakingCollective = true;
					pilot.inputBank.jump.down = true;
					yield return FixedSeconds(0.12f);
				}
				float entryFov = camera.fovOverride;
				float entryAirControl = pilot.characterMotor.airControl;
				int beforeStock = slot.stock;
				int renderBefore = brakingRenderViolations;
				float targetBefore = hover.TargetHeight;
				float airtimeBefore = hover.Airtime;
				Vector3 requested = (prototypeAim = ((name == "small") ? (Quaternion.AngleAxis(30f, Vector3.up) * facing) : ((name == "stationary") ? (Quaternion.AngleAxis(90f, Vector3.up) * facing) : (-facing))));
				move = Vector3.zero;
				pilot.inputBank.moveVector = move;
				pilot.inputBank.aimDirection = requested;
				Vector3 val = ((name == "stationary" || collective) ? Vector3.zero : (facing * pilot.moveSpeed * ((name == "fast") ? 2f : 1f)));
				pilot.characterMotor.velocity = val + Vector3.up * pilot.characterMotor.velocity.y;
				if (spare)
				{
					pilot.RemoveBuff(Buffs.HiddenInvincibility);
					removedSafety = true;
				}
				bool accepted = slot.ExecuteIfReady();
				yield return Until(() => Machine("Body").state is BrakingTurn, 2f, "native braking entry");
				BrakingTurn state = (BrakingTurn)(object)Machine("Body").state;
				AH64BrakingTurnCapture capture = state.EntrySnapshot;
				AH64BrakingTurnMotor motor = ((Component)pilot).GetComponent<AH64BrakingTurnMotor>();
				AH64BrakingTurnPresentation presentation = ((Component)pilot).GetComponent<AH64BrakingTurnPresentation>();
				Vector3 val2 = AH64BrakingTurnMath.Horizontal(capture.EntryVelocity);
				float capturedSpeed = ((Vector3)(ref val2)).magnitude;
				BrakingCheck(name + ".activation-capture", accepted && slot.stock == beforeStock - 1 && capturedSpeed >= 0f && Vector3.Angle(capture.RequestedHeading, requested) < 0.1f && capture.Duration == 1f && (name != "stationary" || capturedSpeed < 0.2f) && (name != "small" || Mathf.Abs(capture.SignedCorrection - 30f) < 5f) && (name != "fast" || capturedSpeed > capture.MoveSpeed), "accepted=" + accepted + " stock=" + beforeStock + "->" + slot.stock + " captured=" + JsonUtility.ToJson((object)capture));
				int spareStock = slot.stock;
				bool early = spare && slot.ExecuteIfReady();
				prototypeAim = facing;
				yield return FixedSeconds(0.36f);
				AH64BrakingTurnFrame frame;
				bool flag = (object)Machine("Body").state == state && presentation.TryGetFrame(state, out frame);
				bool flag2 = spare && slot.ExecuteIfReady();
				bool flag3 = flag && !state.MotionYielded && motor.HasActiveLease && Vector3.Angle(state.EntrySnapshot.RequestedHeading, requested) < 0.1f;
				bool checkTurn = name == "small" || name == "fast";
				if (checkTurn)
				{
					flag3 &= AH64BrakingTurnAcceptance.Turned(capture, motor.LastAppliedVelocity, completed: false);
				}
				if (spare)
				{
					flag3 &= spareStock >= 1 && !early && !flag2 && slot.stock == spareStock && !pilot.HasBuff(Buffs.HiddenInvincibility) && !pilot.HasBuff(Buffs.Cloak);
				}
				if (collective)
				{
					flag3 &= hover.TargetHeight >= targetBefore && hover.IsAscending && hover.Airtime > 0f && hover.Airtime <= airtimeBefore + Time.fixedDeltaTime * 2f;
				}
				BrakingCheck(name + ".midflight", flag3, "active=" + flag + " yielded=" + state.MotionYielded + " age=" + motor.AppliedAge + " reentry=" + early + "," + flag2 + " target=" + targetBefore + "->" + hover.TargetHeight + " airtime=" + airtimeBefore + "->" + hover.Airtime + " actual directed turn=" + AH64BrakingTurnAcceptance.SignedProgress(capture, motor.LastAppliedVelocity));
				bool interruptAccepted = true;
				if (interruption)
				{
					interruptAccepted = Machine("Body").SetInterruptState((EntityState)(object)new AH64Main(), (InterruptPriority)5);
				}
				yield return Until(() => (object)Machine("Body").state != state, 3f, "braking exit");
				val2 = AH64BrakingTurnMath.Horizontal(motor.LastAppliedVelocity);
				float magnitude = ((Vector3)(ref val2)).magnitude;
				bool flag4 = motor.AppliedSteps > 0 && Finite(motor.LastAppliedVelocity) && motor.LastAppliedVelocity.y == motor.LastNativeVelocity.y && magnitude <= Mathf.Max(capturedSpeed, capture.ExitSpeed) + 0.1f;
				if (name == "stationary")
				{
					flag4 = flag4 && magnitude < 0.2f;
				}
				if (name == "fast")
				{
					flag4 &= motor.AppliedAge >= 0.95f && magnitude <= capture.MoveSpeed + 0.1f && magnitude > 0.1f;
				}
				if (checkTurn)
				{
					flag4 &= AH64BrakingTurnAcceptance.Turned(capture, motor.LastAppliedVelocity, completed: true);
				}
				DevAutopilot devAutopilot = this;
				string id = name + ".motion";
				bool passed = flag4;
				string[] obj = new string[17]
				{
					"steps=",
					motor.AppliedSteps.ToString(),
					" last age=",
					motor.AppliedAge.ToString(),
					" native=",
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null,
					null
				};
				val2 = motor.LastNativeVelocity;
				obj[5] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString();
				obj[6] = " applied=";
				val2 = motor.LastAppliedVelocity;
				obj[7] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString();
				obj[8] = " final active speed=";
				obj[9] = magnitude.ToString();
				obj[10] = " exit ceiling=";
				obj[11] = capture.ExitSpeed.ToString();
				obj[12] = " actual directed turn=";
				obj[13] = AH64BrakingTurnAcceptance.SignedProgress(capture, motor.LastAppliedVelocity).ToString();
				obj[14] = " final alignment=";
				obj[15] = AH64BrakingTurnAcceptance.Alignment(capture, motor.LastAppliedVelocity).ToString();
				obj[16] = "; post-Main velocity is not used as exit carry";
				devAutopilot.BrakingCheck(id, passed, string.Concat(obj));
				BrakingCheck(name + ".exit", interruptAccepted && Machine("Body").state is AH64Main && !(Machine("Body").state is BrakingTurn) && !motor.HasActiveLease && !presentation.HasActiveOwner && (interruption || motor.AppliedAge >= 0.95f), "actual=" + ((object)Machine("Body").state).GetType().Name + " native stronger interruption=" + interruptAccepted + " age=" + motor.AppliedAge);
				brakingCollective = false;
				pilot.inputBank.jump.down = false;
				prototypeAim = Vector3.zero;
				yield return FixedSeconds(1.4f);
				BrakingCheck(name + ".cleanup", MovementResourcesReleased(entryFov, entryAirControl) && !motor.HasActiveLease && !presentation.HasActiveOwner && !visuals.HasBrakingOwner && !visuals.IsBrakingRecovering && brakingRenderViolations == renderBefore, "motor=" + motor.HasActiveLease + " presentation=" + presentation.HasActiveOwner + " visual=" + visuals.HasBrakingOwner + " recovery=" + visuals.IsBrakingRecovering + " render violations=" + (brakingRenderViolations - renderBefore));
			}
			finally
			{
				DevAutopilot devAutopilot2 = this;
				devAutopilot2.brakingCollective = false;
				devAutopilot2.prototypeAim = Vector3.zero;
				devAutopilot2.move = Vector3.zero;
				slot.UnsetSkillOverride((object)devAutopilot2, skill, (SkillOverridePriority)4);
				if (spare)
				{
					devAutopilot2.pilot.inventory.RemoveItem(Items.UtilitySkillMagazine.itemIndex, 1);
				}
				if (removedSafety && Object.op_Implicit((Object)(object)devAutopilot2.pilot) && devAutopilot2.pilot.healthComponent.alive)
				{
					devAutopilot2.pilot.AddBuff(Buffs.HiddenInvincibility);
				}
			}
		}

		private IEnumerator BrakingGuidanceCase()
		{
			yield return ResetBrakingCase("braking-guidance");
			GenericSkill utility = pilot.skillLocator.utility;
			GenericSkill special = pilot.skillLocator.special;
			SkillDef brake = Variant(utility, typeof(BrakingTurn));
			SkillDef hellfire = Variant(special, typeof(FireHellfire));
			utility.SetSkillOverride((object)this, brake, (SkillOverridePriority)4);
			special.SetSkillOverride((object)this, hellfire, (SkillOverridePriority)4);
			try
			{
				yield return Until(() => utility.CanExecute() && special.CanExecute(), 15f, "concurrent guidance readiness");
				prototypeHeld = true;
				DevAutopilot devAutopilot = this;
				Vector3 val = facing + Vector3.up * 1.5f;
				devAutopilot.prototypeAim = ((Vector3)(ref val)).normalized;
				pilot.inputBank.skill4.down = true;
				pilot.inputBank.aimDirection = prototypeAim;
				bool launch = special.ExecuteIfReady();
				yield return FixedSeconds(0.12f);
				ProjectileController lead = ((IEnumerable<ProjectileController>)NativeHellfires()).SingleOrDefault((Func<ProjectileController, bool>)((ProjectileController p) => p.combo == 0));
				if (!Object.op_Implicit((Object)(object)lead))
				{
					throw new InvalidOperationException("Braking guidance has no unique native lead.");
				}
				AH64HellfireGuidance guidance = ((Component)lead).GetComponent<AH64HellfireGuidance>();
				AH64HellfireOwner owner = ((Component)pilot).GetComponent<AH64HellfireOwner>();
				uint token = guidance.Token;
				Vector3 heading = ((Component)lead).transform.forward;
				bool activate = utility.ExecuteIfReady();
				yield return FixedSeconds(0.08f);
				BrakingCheck("guidance.entry", launch && activate && Machine("Body").state is BrakingTurn && token != 0 && owner.Policy.CanGuide(token, Time.fixedTime), "braking=" + ((object)Machine("Body").state).GetType().Name + " token=" + token);
				prototypeAim = Quaternion.AngleAxis(30f, Vector3.up) * prototypeAim;
				pilot.inputBank.aimDirection = prototypeAim;
				bool primary = pilot.skillLocator.primary.ExecuteIfReady();
				bool hydra = pilot.skillLocator.secondary.ExecuteIfReady();
				yield return FixedSeconds(0.3f);
				BrakingCheck("guidance.turn-weapons", Object.op_Implicit((Object)(object)lead) && Machine("Body").state is BrakingTurn && primary && hydra && owner.Policy.CanGuide(token, Time.fixedTime) && guidance.LastTurnDegrees > 0f && Vector3.Angle(heading, ((Component)lead).transform.forward) > 0.1f, "primary=" + primary + " hydra=" + hydra + " active=" + owner.Policy.ActiveToken + " turn=" + (Object.op_Implicit((Object)(object)lead) ? Vector3.Angle(heading, ((Component)lead).transform.forward) : (-1f)));
				prototypeHeld = false;
				pilot.inputBank.skill4.down = false;
				yield return FixedSeconds(0.12f);
				Vector3 coast = (Object.op_Implicit((Object)(object)lead) ? ((Component)lead).transform.forward : Vector3.zero);
				prototypeAim = Quaternion.AngleAxis(-90f, Vector3.up) * prototypeAim;
				yield return FixedSeconds(0.2f);
				BrakingCheck("guidance.release", Object.op_Implicit((Object)(object)lead) && owner.Policy.ActiveToken == 0 && Vector3.Angle(coast, ((Component)lead).transform.forward) < 0.01f, "active=" + owner.Policy.ActiveToken + "; native release coasts");
				yield return Until(() => NativeHellfires().Length == 0, 12f, "braking Hellfire drain");
				BrakingCheck("guidance.drain", NativeHellfires().Length == 0 && !(Machine("Body").state is BrakingTurn) && !((Component)pilot).GetComponent<AH64BrakingTurnMotor>().HasActiveLease, "all native guided missiles drained; no damage/hit claim");
			}
			finally
			{
				DevAutopilot devAutopilot2 = this;
				devAutopilot2.prototypeHeld = false;
				devAutopilot2.prototypeAim = Vector3.zero;
				utility.UnsetSkillOverride((object)devAutopilot2, brake, (SkillOverridePriority)4);
				special.UnsetSkillOverride((object)devAutopilot2, hellfire, (SkillOverridePriority)4);
			}
		}

		private void ObserveBrakingPhysics()
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			if (brakingStarted)
			{
				AH64BrakingTurnMotor component = ((Component)pilot).GetComponent<AH64BrakingTurnMotor>();
				AH64HoverController component2 = ((Component)pilot).GetComponent<AH64HoverController>();
				AH64FlightVisuals component3 = ((Component)pilot).GetComponent<AH64FlightVisuals>();
				BrakingTurn brakingTurn = Machine("Body").state as BrakingTurn;
				AH64BrakingTurnPresentation component4 = ((Component)pilot).GetComponent<AH64BrakingTurnPresentation>();
				AH64BrakingTurnFrame frame = default(AH64BrakingTurnFrame);
				bool flag = brakingTurn != null && Object.op_Implicit((Object)(object)component4) && component4.TryGetFrame(brakingTurn, out frame);
				Write(new BrakingSample
				{
					recordType = "braking-sample",
					runId = Path.GetFileName(output),
					scenario = segment,
					tick = tick,
					simulationTime = Time.fixedTime,
					capture = ((brakingTurn != null) ? JsonUtility.ToJson((object)brakingTurn.EntrySnapshot) : "none"),
					phase = (flag ? frame.Phase.ToString() : "inactive"),
					progress = (brakingTurn?.ManeuverProgress ?? 0f),
					commandedHeading = frame.CommandedHeading,
					position = ((Component)pilot).gameObject.transform.position,
					velocity = pilot.characterMotor.velocity,
					nativeAim = pilot.inputBank.aimDirection,
					targetHeight = component2.TargetHeight,
					airtime = component2.Airtime,
					groundDistance = component2.GroundDistance,
					ascending = component2.IsAscending,
					appliedAge = (Object.op_Implicit((Object)(object)component) ? component.AppliedAge : 0f),
					appliedSteps = (Object.op_Implicit((Object)(object)component) ? component.AppliedSteps : 0),
					nativeVelocity = (Object.op_Implicit((Object)(object)component) ? component.LastNativeVelocity : Vector3.zero),
					appliedVelocity = (Object.op_Implicit((Object)(object)component) ? component.LastAppliedVelocity : Vector3.zero),
					lease = (Object.op_Implicit((Object)(object)component) && component.HasActiveLease),
					yieldReason = (Object.op_Implicit((Object)(object)component) ? component.YieldReason : "none"),
					visualOwner = (Object.op_Implicit((Object)(object)component3) && component3.HasBrakingOwner),
					visualRecovery = (Object.op_Implicit((Object)(object)component3) && component3.IsBrakingRecovering),
					displayedBaseWorld = (Object.op_Implicit((Object)(object)component3) ? component3.RenderedBaseWorld : Quaternion.identity)
				});
			}
		}

		private void LateUpdate()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			if (brakingStarted && scripting && !finished && Object.op_Implicit((Object)(object)pilot))
			{
				Quaternion rotation = pilot.modelLocator.modelTransform.rotation;
				AH64FlightVisuals component = ((Component)pilot).GetComponent<AH64FlightVisuals>();
				bool flag = Object.op_Implicit((Object)(object)component) && (component.HasBrakingOwner || component.IsBrakingRecovering);
				float num = ((brakingHasRender && brakingRenderEpoch == poseEpoch) ? Quaternion.Angle(brakingPreviousRender, rotation) : 0f);
				float num2 = 5f + 360f * Time.deltaTime;
				if (brakingHasRender && brakingRenderEpoch == poseEpoch && (flag || brakingPreviousVisualActive) && num > num2)
				{
					brakingRenderViolations++;
				}
				Write(new BrakingRender
				{
					recordType = "braking-render",
					runId = Path.GetFileName(output),
					scenario = segment,
					renderedTime = Time.time,
					renderDeltaTime = Time.deltaTime,
					poseEpoch = poseEpoch,
					worldAttitude = rotation,
					observedDelta = num,
					alarmBound = num2,
					visualActive = flag,
					bodyState = ((object)Machine("Body").state).GetType().Name
				});
				brakingPreviousRender = rotation;
				brakingHasRender = true;
				brakingRenderEpoch = poseEpoch;
				brakingRenderSamples++;
				brakingPreviousVisualActive = flag;
			}
		}

		private bool FinishBrakingEvidence()
		{
			if (Environment.GetEnvironmentVariable("AH64_AUTOPILOT_BRAKING_CHECKS") != "braking-solo-v1")
			{
				return true;
			}
			string[] array = new string[2] { "catalog.order", "catalog.definition" }.Concat(BrakingCaseNames.SelectMany((string n) => BrakingCaseChecks.Select((string c) => n + "." + c))).Concat(new string[4] { "guidance.entry", "guidance.turn-weapons", "guidance.release", "guidance.drain" }).ToArray();
			bool flag = brakingStarted && brakingComplete && brakingChecks.Count == array.Length && brakingChecks.All((Check c) => c.passed) && brakingChecks.Select((Check c) => c.id).Distinct().Count() == array.Length && !array.Except(brakingChecks.Select((Check c) => c.id)).Any() && brakingRenderSamples > 0 && brakingRenderViolations == 0;
			File.WriteAllText(Path.Combine(output, "braking-result.json"), JsonUtility.ToJson((object)new BrakingResult
			{
				runId = Path.GetFileName(output),
				sourceSha = JsonUtility.FromJson<StageIdentity>(File.ReadAllText(Path.Combine(output, "identity.json"))).sourceSha,
				dllSha256 = Hash(typeof(AH64Plugin).Assembly.Location),
				suite = "braking-solo-v1",
				status = (flag ? "passed" : "failed"),
				complete = brakingComplete,
				expectedChecks = array.Length,
				expectedIds = array,
				checks = brakingChecks.ToArray(),
				renderSamples = brakingRenderSamples,
				renderViolations = brakingRenderViolations,
				utilityInterruptPriority = ((object)Unsafe.As<InterruptPriority, InterruptPriority>(ref Variant(pilot.skillLocator.utility, typeof(BrakingTurn)).interruptPriority)/*cast due to .constrained prefix*/).ToString(),
				limitation = "SOLO scripted input, initial velocity and isolated inventory/overrides. No new braking screenshots. The five baseline images do not show braking. Physical modern descend, native geometry/force/item edge fixtures, targeted hits/audio, controller feel, peers and long sessions remain unverified. Render bound is a coarse alarm. Raw strict runtime failures retain independent blocking/classification."
			}, true));
			return flag;
		}

		private void CheckWindowCapturePhase()
		{
			if (pendingCapture != null)
			{
				capturePhaseChecks++;
				if (!Object.op_Implicit((Object)(object)pilot) || ((Object)((Component)pilot).gameObject).GetInstanceID() != pendingCapture.bodyId || segment != pendingCapture.phase || ((object)Machine("Body").state).GetType().FullName != pendingCapture.bodyState || ((object)Machine("Weapon2").state).GetType().FullName != pendingCapture.weaponState || (pendingCapture.requiresProjectile && OwnedProjectiles() == 0))
				{
					capturePhaseInvalid = true;
				}
			}
		}

		private IEnumerator Capture(string name)
		{
			if (Environment.GetEnvironmentVariable("AH64_AUTOPILOT_WINDOW_CAPTURE") != "1")
			{
				throw new InvalidOperationException("Baseline requires its explicitly configured owned-window helper.");
			}
			yield return (object)new WaitForEndOfFrame();
			WindowCaptureStage windowCaptureStage = JsonUtility.FromJson<WindowCaptureStage>(File.ReadAllText(Path.Combine(output, "identity.json")));
			string directory = Path.Combine(output, "window-captures");
			Directory.CreateDirectory(directory);
			WindowCaptureRequest request = (pendingCapture = new WindowCaptureRequest
			{
				runId = Path.GetFileName(output),
				token = Guid.NewGuid().ToString("N"),
				name = name,
				phase = segment,
				bodyId = ((Object)((Component)pilot).gameObject).GetInstanceID(),
				bodyName = ((Object)((Component)pilot).gameObject).name,
				bodyState = ((object)Machine("Body").state).GetType().FullName,
				weaponState = ((object)Machine("Weapon2").state).GetType().FullName,
				requiresProjectile = (name == "hellfire-launched"),
				pid = Process.GetCurrentProcess().Id,
				executable = Path.Combine(windowCaptureStage.gameDirectory, "Risk of Rain 2.exe"),
				sourceSha = windowCaptureStage.sourceSha,
				owner = windowCaptureStage.owner,
				reservation = windowCaptureStage.reservation,
				lockPath = windowCaptureStage.runtimeLockPath,
				requestFrame = Time.frameCount,
				requestFixedTime = Time.fixedTime,
				requestRealtime = Time.realtimeSinceStartup,
				requestedUtc = DateTime.UtcNow.ToString("o")
			});
			capturePhaseInvalid = false;
			capturePhaseChecks = 0;
			string text = Path.Combine(directory, request.token + ".request.json");
			string ackPath = Path.Combine(directory, request.token + ".ack.json");
			try
			{
				CheckWindowCapturePhase();
				File.WriteAllText(text + ".tmp", JsonUtility.ToJson((object)request, true));
				File.Move(text + ".tmp", text);
				Event("capture-request", name + "; token=" + request.token + "; frame=" + request.requestFrame + "; utc=" + request.requestedUtc);
				float deadline = Time.realtimeSinceStartup + 10f;
				while (!File.Exists(ackPath))
				{
					CheckWindowCapturePhase();
					if (capturePhaseInvalid)
					{
						throw new InvalidOperationException("Requested capture phase expired: " + name);
					}
					if (Time.realtimeSinceStartup > deadline)
					{
						throw new TimeoutException("Owned-window acknowledgement: " + name);
					}
					yield return null;
				}
				CheckWindowCapturePhase();
				WindowCaptureAck windowCaptureAck = JsonUtility.FromJson<WindowCaptureAck>(File.ReadAllText(ackPath));
				string path = Path.Combine(output, name + ".png");
				WindowCaptureContract.Validate(request, windowCaptureAck, capturePhaseInvalid, Hash(path), File.ReadAllBytes(path), DateTime.UtcNow);
				File.WriteAllText(Path.Combine(directory, request.token + ".phase.json"), JsonUtility.ToJson((object)new WindowPhaseEvidence
				{
					runId = request.runId,
					token = request.token,
					phaseValid = true,
					phaseChecks = capturePhaseChecks,
					confirmedFrame = Time.frameCount,
					confirmedFixedTime = Time.fixedTime,
					confirmedUtc = DateTime.UtcNow.ToString("o"),
					limitation = "State/body/phase observed at frame and physics cadence through acknowledgement; request frame is not the captured rendered frame; simulation never paused"
				}, true));
				captures++;
				Event("capture", name + ".png; token=" + request.token + "; source=owned-game-window; interval=" + windowCaptureAck.startedUtc + ".." + windowCaptureAck.finishedUtc + "; state/phase retained; no exact rendered-frame claim; controller/audio unverified");
			}
			finally
			{
				pendingCapture = null;
			}
		}

		internal static void TryStart()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			string environmentVariable = Environment.GetEnvironmentVariable("AH64_AUTOPILOT_DIR");
			if (!(Environment.GetEnvironmentVariable("AH64_AUTOPILOT_MODE") != "solo-baseline-v1") && !string.IsNullOrEmpty(environmentVariable))
			{
				if (!Path.IsPathRooted(environmentVariable) || !Directory.Exists(environmentVariable) || !File.Exists(Path.Combine(environmentVariable, "identity.json")))
				{
					throw new InvalidOperationException("AH64 autopilot requires an existing absolute run directory and staged identity.");
				}
				if (File.Exists(Path.Combine(environmentVariable, "telemetry.jsonl")))
				{
					throw new InvalidOperationException("AH64 autopilot refuses reused output.");
				}
				GameObject val = new GameObject("AH64DevAutopilot");
				Object.DontDestroyOnLoad((Object)val);
				DevAutopilot devAutopilot = val.AddComponent<DevAutopilot>();
				devAutopilot.output = environmentVariable;
				devAutopilot.started = Time.realtimeSinceStartup;
				devAutopilot.OpenEvidence();
				devAutopilot.InstallHooks();
				devAutopilot.InstallBombingProbeHooks();
				((MonoBehaviour)devAutopilot).StartCoroutine(devAutopilot.Guarded(devAutopilot.Script()));
			}
		}

		private void InstallHooks()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnLoaded));
			NetworkUser.onPostNetworkUserStart += new NetworkUserGenericDelegate(OnNetworkStarted);
			Application.logMessageReceived += new LogCallback(OnLog);
			PlayerCharacterMasterController.FixedUpdate += new hook_FixedUpdate(AfterInput);
			PlayerCharacterMasterController.Update += new hook_Update(AfterAim);
			ProjectileManager.FireProjectile_FireProjectileInfo += new hook_FireProjectile_FireProjectileInfo(OnProjectile);
			AH64BombingRunTrace.Emitted += OnBombingTrace;
		}

		private void OnDestroy()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			RoR2Application.onLoad = (Action)Delegate.Remove(RoR2Application.onLoad, new Action(OnLoaded));
			NetworkUser.onPostNetworkUserStart -= new NetworkUserGenericDelegate(OnNetworkStarted);
			Application.logMessageReceived -= new LogCallback(OnLog);
			PlayerCharacterMasterController.FixedUpdate -= new hook_FixedUpdate(AfterInput);
			PlayerCharacterMasterController.Update -= new hook_Update(AfterAim);
			ProjectileManager.FireProjectile_FireProjectileInfo -= new hook_FireProjectile_FireProjectileInfo(OnProjectile);
			AH64BombingRunTrace.Emitted -= OnBombingTrace;
			CleanupBombingProbe();
			if (output != null && !finished)
			{
				Finish("incomplete", "runner destroyed");
			}
		}

		private void OnLoaded()
		{
			gameLoaded = true;
		}

		private void Update()
		{
			CheckWindowCapturePhase();
			if (finished)
			{
				if (Time.realtimeSinceStartup >= quitAt)
				{
					Application.Quit(terminalExit);
				}
				return;
			}
			if (Time.realtimeSinceStartup - started > 240f)
			{
				Finish("incomplete", "runtime deadline");
			}
			if (NetworkUser.readOnlyInstancesList.Count > 1 || LocalUserManager.readOnlyLocalUsersList.Count > 1)
			{
				Finish("failed", "solo guard: multiple users");
			}
		}

		private IEnumerator Guarded(IEnumerator root)
		{
			Stack<IEnumerator> stack = new Stack<IEnumerator>();
			stack.Push(root);
			while (stack.Count > 0 && !finished)
			{
				object obj = null;
				bool flag = false;
				try
				{
					flag = stack.Peek().MoveNext();
					if (flag)
					{
						obj = stack.Peek().Current;
					}
				}
				catch (Exception ex)
				{
					Finish("failed", "script exception: " + ex);
				}
				if (finished)
				{
					yield break;
				}
				if (!flag)
				{
					stack.Pop();
				}
				else if (obj is IEnumerator item)
				{
					stack.Push(item);
				}
				else
				{
					yield return obj;
				}
			}
			if (!finished)
			{
				Finish("completed", "script ended");
			}
		}

		private IEnumerator Until(Func<bool> predicate, float timeout, string reason)
		{
			float end = Time.realtimeSinceStartup + timeout;
			while (!predicate())
			{
				if (Time.realtimeSinceStartup > end)
				{
					throw new TimeoutException(reason);
				}
				yield return null;
			}
		}

		private unsafe IEnumerator Script()
		{
			yield return Bootstrap();
			DisableCombatDirectors();
			pilot.AddBuff(Buffs.HiddenInvincibility);
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(new Vector3(-112.88f, -