Decompiled source of StayCombatFix v3.0.0

StayCombatFix.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DM;
using HarmonyLib;
using Landfall.TABS;
using Landfall.TABS.AI.Components;
using Landfall.TABS.AI.Components.Events;
using Landfall.TABS.AI.Components.Modifiers;
using Landfall.TABS.AI.Components.Pathfinding;
using Landfall.TABS.AI.Components.Tags;
using Landfall.TABS.AI.Systems;
using Landfall.TABS.GameMode;
using Landfall.TABS.GameState;
using Landfall.TABS.UnitEditor;
using Landfall.TABS.Workshop;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Pathfinding;
using StayCombatFix.FleeDebug;
using StayCombatFix.UnitMarker;
using TFBGames;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Stay & Combat Fixes")]
[assembly: AssemblyDescription("Stay aura, lay-down combat, water physics, mirror shield, barrel death, gas grenade, and faction creator fixes for TABS")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Pretz")]
[assembly: AssemblyProduct("StayCombatFix")]
[assembly: AssemblyCopyright("Pretz")]
[assembly: ComVisible(false)]
[assembly: Guid("b2c3d4e5-f6a7-8901-bcde-f12345678901")]
[assembly: AssemblyFileVersion("3.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("3.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace StayCombatFix
{
	internal sealed class BarrelDeathPlan
	{
		internal Transform Root;

		internal float DelaySeconds;

		internal GameObject[] BarrelVisuals;

		internal Rigidbody[] BarrelRigidbodies;

		internal Transform[] BarrelAnchors;

		internal Vector3 SnapshotPosition;

		internal bool HasSnapshotPosition;

		internal Explosion CachedBarrelExplosion;

		internal GameObject CachedExplosionPrefab;

		internal Explosion FallbackExplosionTemplate;

		internal Unit OwnerUnit;
	}
	internal static class BarrelRollerDeathLogic
	{
		private struct PendingBarrelDeath
		{
			internal int RootId;

			internal BarrelDeathPlan Plan;

			internal float ExplodeAt;

			internal Vector3 ExplodePosition;

			internal bool HasExplodePosition;
		}

		[CompilerGenerated]
		private sealed class <ProcessDeathQueue>d__46 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ProcessDeathQueue>d__46(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (PendingDeaths.Count > 0)
				{
					float time = Time.time;
					int num = 0;
					int num2 = PendingDeaths.Count - 1;
					while (num2 >= 0 && num < 8)
					{
						PendingBarrelDeath pendingBarrelDeath = PendingDeaths[num2];
						if (!(time < pendingBarrelDeath.ExplodeAt))
						{
							if ((Object)(object)pendingBarrelDeath.Plan?.Root == (Object)null)
							{
								PendingDeaths.RemoveAt(num2);
								PendingDeathRootIds.Remove(pendingBarrelDeath.RootId);
							}
							else
							{
								PendingDeaths.RemoveAt(num2);
								PendingDeathRootIds.Remove(pendingBarrelDeath.RootId);
								ExecuteDeathExplosion(pendingBarrelDeath.RootId, pendingBarrelDeath.Plan, pendingBarrelDeath.ExplodePosition, pendingBarrelDeath.HasExplodePosition);
								num++;
							}
						}
						num2--;
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				_queueRunner = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		internal const int BarrelRollerUnitId = 846602731;

		private const float MinimumDelaySeconds = 0.45f;

		private const float MaxBarrelDistanceFromUnit = 80f;

		private static MonoBehaviour _runner;

		private static ManualLogSource _log;

		private static readonly Dictionary<int, float> RecentBarrelExplosionTimeByRoot = new Dictionary<int, float>();

		private static readonly Dictionary<int, float> AllowedBarrelExplosionTimeByRoot = new Dictionary<int, float>();

		private static readonly Dictionary<int, Transform> ActiveBarrelRollerRoots = new Dictionary<int, Transform>();

		private static readonly HashSet<int> KnownBarrelRollerRootIds = new HashSet<int>();

		private static readonly HashSet<int> NotBarrelRollerRootIds = new HashSet<int>();

		private static readonly List<PendingBarrelDeath> PendingDeaths = new List<PendingBarrelDeath>(32);

		private static readonly HashSet<int> PendingDeathRootIds = new HashSet<int>();

		private const float RecentBarrelExplosionWindowSeconds = 2.5f;

		private const float DuplicateAbilityExplosionWindowSeconds = 0.75f;

		private const float AbilityDeathSkipExplosionAgeSeconds = 0.5f;

		private const float AbilityExplosionOwnerSearchRadius = 20f;

		private const float DeathExplosionDamage = 15f;

		private const int MaxExplosionsPerFrame = 8;

		private static GameObject _sharedBarrelDeathExplosionPrefab;

		private static Explosion _sharedBarrelDeathExplosionTemplate;

		private static Coroutine _queueRunner;

		private static bool _executingDeathExplosion;

		internal static void Initialize(MonoBehaviour runner, ManualLogSource log)
		{
			_runner = runner;
			_log = log;
		}

		internal static void ResetBattleCaches()
		{
			RecentBarrelExplosionTimeByRoot.Clear();
			AllowedBarrelExplosionTimeByRoot.Clear();
			ActiveBarrelRollerRoots.Clear();
			KnownBarrelRollerRootIds.Clear();
			NotBarrelRollerRootIds.Clear();
			PendingDeaths.Clear();
			PendingDeathRootIds.Clear();
			_executingDeathExplosion = false;
			_queueRunner = null;
		}

		private static void EvictRootCache(int rootId)
		{
			KnownBarrelRollerRootIds.Remove(rootId);
			NotBarrelRollerRootIds.Remove(rootId);
			ActiveBarrelRollerRoots.Remove(rootId);
			RecentBarrelExplosionTimeByRoot.Remove(rootId);
			AllowedBarrelExplosionTimeByRoot.Remove(rootId);
			PendingDeathRootIds.Remove(rootId);
			for (int num = PendingDeaths.Count - 1; num >= 0; num--)
			{
				if (PendingDeaths[num].RootId == rootId)
				{
					PendingDeaths.RemoveAt(num);
				}
			}
		}

		private static bool IsCachedBarrelRollerRoot(Transform root, int rootId)
		{
			if (!KnownBarrelRollerRootIds.Contains(rootId))
			{
				return false;
			}
			if (!ActiveBarrelRollerRoots.TryGetValue(rootId, out var value) || (Object)(object)value == (Object)null)
			{
				EvictRootCache(rootId);
				return false;
			}
			if ((Object)(object)value != (Object)(object)root)
			{
				EvictRootCache(rootId);
				return false;
			}
			RememberBarrelRollerRoot(root);
			return true;
		}

		internal static void MarkRecentBarrelExplosion(Transform ownerRoot)
		{
			if (!((Object)(object)ownerRoot == (Object)null))
			{
				RecentBarrelExplosionTimeByRoot[((Object)ownerRoot).GetInstanceID()] = Time.time;
				CancelPendingDeathExplosion(ownerRoot);
			}
		}

		internal static void PrepareBarrelOwnedExplosionForDetonation(Explosion explosion)
		{
			if (!((Object)(object)explosion == (Object)null) && MightBeBarrelRollerExplosion(explosion))
			{
				Transform val = ResolveBarrelRollerOwnerRoot(((Component)explosion).transform);
				if (!((Object)(object)val == (Object)null) && IsBarrelRollerOwnedExplosion(explosion, val))
				{
					StripDeathExplosionStatusEffects(((Component)((Component)explosion).transform.root).gameObject);
				}
			}
		}

		internal static bool TryBlockDuplicateBarrelExplosion(Explosion explosion)
		{
			if ((Object)(object)explosion == (Object)null || _executingDeathExplosion || !MightBeBarrelRollerExplosion(explosion))
			{
				return false;
			}
			Transform val = ResolveBarrelRollerOwnerRoot(((Component)explosion).transform);
			if ((Object)(object)val == (Object)null || !IsBarrelRollerOwnedExplosion(explosion, val))
			{
				return false;
			}
			int instanceID = ((Object)val).GetInstanceID();
			float time = Time.time;
			if (AllowedBarrelExplosionTimeByRoot.TryGetValue(instanceID, out var value) && time - value <= 0.75f)
			{
				return true;
			}
			AllowedBarrelExplosionTimeByRoot[instanceID] = time;
			MarkRecentBarrelExplosion(val);
			return false;
		}

		private static bool MightBeBarrelRollerExplosion(Explosion explosion)
		{
			if ((Object)(object)explosion == (Object)null)
			{
				return false;
			}
			Transform transform = ((Component)explosion).transform;
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			if (IsRollingBarrelGearTransform(transform))
			{
				return true;
			}
			if (ContainsBarrelExplosionName(((Object)((Component)transform).gameObject).name) || ContainsBarrelExplosionName(((Object)transform.root).name))
			{
				return true;
			}
			int instanceID = ((Object)transform.root).GetInstanceID();
			return KnownBarrelRollerRootIds.Contains(instanceID);
		}

		internal static void NotifyBarrelAbilityExplosionFromSpawn(Transform scope, GameObject prefab)
		{
			if (!((Object)(object)scope == (Object)null) && !((Object)(object)prefab == (Object)null) && !_executingDeathExplosion && ContainsBarrelExplosionName(((Object)prefab).name))
			{
				Transform root = scope.root;
				if (IsBarrelRollerRoot(root))
				{
					MarkRecentBarrelExplosion(root);
				}
			}
		}

		private static void CancelPendingDeathExplosion(Transform ownerRoot)
		{
			if ((Object)(object)ownerRoot == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)ownerRoot).GetInstanceID();
			PendingDeathRootIds.Remove(instanceID);
			for (int num = PendingDeaths.Count - 1; num >= 0; num--)
			{
				if (PendingDeaths[num].RootId == instanceID)
				{
					PendingDeaths.RemoveAt(num);
				}
			}
		}

		private static Transform ResolveBarrelRollerOwnerRoot(Transform explosionTransform)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)explosionTransform == (Object)null)
			{
				return null;
			}
			TeamHolder val = ((Component)explosionTransform).GetComponent<TeamHolder>() ?? ((Component)explosionTransform).GetComponentInParent<TeamHolder>();
			if ((Object)(object)val?.spawner != (Object)null)
			{
				Transform root = val.spawner.transform.root;
				if (IsBarrelRollerRoot(root))
				{
					return root;
				}
			}
			if (ContainsBarrelExplosionName(((Object)((Component)explosionTransform).gameObject).name) || ContainsBarrelExplosionName(((Object)explosionTransform.root).name))
			{
				Transform val2 = FindBarrelRollerRootNear(explosionTransform.position);
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			Transform root2 = explosionTransform.root;
			if (IsSpawnedBarrelExplosionPrefabRoot(root2))
			{
				return null;
			}
			if (IsBarrelRollerRoot(root2))
			{
				return root2;
			}
			return null;
		}

		private static bool IsSpawnedBarrelExplosionPrefabRoot(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)root).GetComponentInChildren<Unit>(true) != (Object)null)
			{
				return false;
			}
			return ContainsBarrelExplosionName(((Object)root).name);
		}

		private static Transform FindBarrelRollerRootNear(Vector3 position)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Transform result = null;
			float num = 400f;
			foreach (KeyValuePair<int, Transform> activeBarrelRollerRoot in ActiveBarrelRollerRoots)
			{
				if (!KnownBarrelRollerRootIds.Contains(activeBarrelRollerRoot.Key))
				{
					continue;
				}
				Transform value = activeBarrelRollerRoot.Value;
				if (!((Object)(object)value == (Object)null) && !IsSpawnedBarrelExplosionPrefabRoot(value))
				{
					Vector3 val = value.position - position;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude > num))
					{
						num = sqrMagnitude;
						result = value;
					}
				}
			}
			return result;
		}

		private static void RememberBarrelRollerRoot(Transform root)
		{
			if (!((Object)(object)root == (Object)null))
			{
				ActiveBarrelRollerRoots[((Object)root).GetInstanceID()] = root;
			}
		}

		private static bool IsBarrelRollerOwnedExplosion(Explosion explosion, Transform ownerRoot)
		{
			if ((Object)(object)explosion == (Object)null || (Object)(object)ownerRoot == (Object)null)
			{
				return false;
			}
			if (ContainsBarrelExplosionName(((Object)((Component)explosion).gameObject).name) || ContainsBarrelExplosionName(((Object)((Component)explosion).transform.root).name))
			{
				return true;
			}
			if (!BelongsToRoot(((Component)explosion).transform, ownerRoot))
			{
				return false;
			}
			if (IsRollingBarrelGearTransform(((Component)explosion).transform))
			{
				return true;
			}
			return IsUnderBarrelRollerAbilityMount(((Component)explosion).transform, ownerRoot);
		}

		private static bool ContainsBarrelExplosionName(string objectName)
		{
			if (string.IsNullOrEmpty(objectName))
			{
				return false;
			}
			if (objectName.IndexOf("ExplosionBombBarrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (objectName.IndexOf("BarrelE_Explosion", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return false;
		}

		internal static bool IsBarrelRollerRoot(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			if (IsSpawnedBarrelExplosionPrefabRoot(root))
			{
				return false;
			}
			int instanceID = ((Object)root).GetInstanceID();
			if (IsCachedBarrelRollerRoot(root, instanceID))
			{
				return true;
			}
			if (NotBarrelRollerRootIds.Contains(instanceID))
			{
				return false;
			}
			Unit component = ((Component)root).GetComponent<Unit>();
			if (!IsBarrelAbilityUnit(root, component))
			{
				NotBarrelRollerRootIds.Add(instanceID);
				return false;
			}
			KnownBarrelRollerRootIds.Add(instanceID);
			RememberBarrelRollerRoot(root);
			return true;
		}

		private static bool ShouldSkipDeathForAbilityKill(Transform root)
		{
			if ((Object)(object)root == (Object)null || !IsBarrelRollerRoot(root))
			{
				return false;
			}
			if (TryGetRecentBarrelExplosionAge(root, out var ageSeconds))
			{
				return ageSeconds <= 0.5f;
			}
			return false;
		}

		private static bool TryGetRecentBarrelExplosionAge(Transform root, out float ageSeconds)
		{
			ageSeconds = float.MaxValue;
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			if (!RecentBarrelExplosionTimeByRoot.TryGetValue(((Object)root).GetInstanceID(), out var value))
			{
				return false;
			}
			ageSeconds = Time.time - value;
			return ageSeconds <= 2.5f;
		}

		internal static bool ShouldSuppressDeathExplosion(Transform root)
		{
			if ((Object)(object)root == (Object)null || !IsBarrelRollerRoot(root))
			{
				return false;
			}
			return HasRecentBarrelExplosion(root);
		}

		internal static void EnsureScheduledFromDead(DataHandler data)
		{
			if (!((Object)(object)data == (Object)null) && data.Dead)
			{
				TryScheduleFromScope(((Component)data).transform, "DataHandler.Dead");
			}
		}

		private static void TryScheduleFromScope(Transform scope, string source)
		{
			if ((Object)(object)scope == (Object)null)
			{
				return;
			}
			Transform root = scope.root;
			if (!IsBarrelRollerRoot(root))
			{
				return;
			}
			if (!TryBuildPlan(root, out var plan))
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Barrel death plan failed (" + source + ") on " + ((Object)root).name));
				}
			}
			else
			{
				TrySchedule(plan, source);
			}
		}

		private static void TrySchedule(BarrelDeathPlan plan, string source)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)plan?.Root == (Object)null || (Object)(object)_runner == (Object)null)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Barrel death skip schedule (" + source + "): runner or root missing"));
				}
				return;
			}
			int instanceID = ((Object)plan.Root).GetInstanceID();
			if (!ShouldSkipDeathForAbilityKill(plan.Root) && PendingDeathRootIds.Add(instanceID))
			{
				Vector3 position;
				bool flag = TryResolveExplosionPosition(plan, out position);
				if (!flag && plan.HasSnapshotPosition && IsFinite(plan.SnapshotPosition))
				{
					position = plan.SnapshotPosition;
					flag = true;
				}
				PendingDeaths.Add(new PendingBarrelDeath
				{
					RootId = instanceID,
					Plan = plan,
					ExplodeAt = Time.time + plan.DelaySeconds,
					ExplodePosition = position,
					HasExplodePosition = flag
				});
				if (_queueRunner == null)
				{
					_queueRunner = _runner.StartCoroutine(ProcessDeathQueue());
				}
			}
		}

		[IteratorStateMachine(typeof(<ProcessDeathQueue>d__46))]
		private static IEnumerator ProcessDeathQueue()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ProcessDeathQueue>d__46(0);
		}

		private static void ExecuteDeathExplosion(int rootId, BarrelDeathPlan plan, Vector3 scheduledPosition, bool hasScheduledPosition)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Transform val = plan?.Root;
			if ((Object)(object)val != (Object)null && ShouldSuppressDeathExplosion(val))
			{
				CancelPendingDeathExplosion(val);
				return;
			}
			if (!TryResolveDeathExplosionPosition(plan, scheduledPosition, hasScheduledPosition, out var position))
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)$"Barrel death execute failed: no position (rootId={rootId})");
				}
				return;
			}
			HideBarrelGear(plan);
			RefreshOwnerUnit(plan);
			_executingDeathExplosion = true;
			try
			{
				TriggerSingleBarrelExplosion(plan, position);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)$"Barrel death execute failed (rootId={rootId}): {ex.Message}");
				}
			}
			finally
			{
				_executingDeathExplosion = false;
			}
		}

		private static bool TryResolveDeathExplosionPosition(BarrelDeathPlan plan, Vector3 scheduledPosition, bool hasScheduledPosition, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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)
			position = default(Vector3);
			if (plan == null)
			{
				return false;
			}
			if ((Object)(object)plan.Root != (Object)null && TryResolveExplosionPosition(plan, out position))
			{
				return true;
			}
			if (hasScheduledPosition && IsFinite(scheduledPosition))
			{
				position = scheduledPosition;
				return true;
			}
			if (plan.HasSnapshotPosition && IsFinite(plan.SnapshotPosition))
			{
				position = plan.SnapshotPosition;
				return true;
			}
			return false;
		}

		private static bool TryBuildPlan(Transform root, out BarrelDeathPlan plan)
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			plan = null;
			if ((Object)(object)root == (Object)null || !IsBarrelRollerRoot(root))
			{
				return false;
			}
			float delayFromConditionalEvents = GetDelayFromConditionalEvents(((Component)root).GetComponentsInChildren<ConditionalEvent>(true));
			Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren<Holdable>(true);
			CollectBarrelHoldableData(root, componentsInChildren, out var barrelRigidbodies, out var barrelAnchors, out var barrelVisuals);
			PickExplosionAssets(((Component)root).GetComponentsInChildren<Explosion>(true), out var cachedExplosion, out var fallbackTemplate);
			GameObject val = FindExplosionPrefab(root);
			if ((Object)(object)val == (Object)null && (Object)(object)cachedExplosion != (Object)null)
			{
				val = FindExplosionPrefabFromTemplate(cachedExplosion);
			}
			if ((Object)(object)val != (Object)null)
			{
				RememberSharedDeathExplosionAssets(val, cachedExplosion ?? fallbackTemplate);
			}
			else if ((Object)(object)_sharedBarrelDeathExplosionPrefab != (Object)null)
			{
				val = _sharedBarrelDeathExplosionPrefab;
			}
			if ((Object)(object)cachedExplosion == (Object)null && (Object)(object)fallbackTemplate == (Object)null && (Object)(object)_sharedBarrelDeathExplosionTemplate != (Object)null)
			{
				fallbackTemplate = _sharedBarrelDeathExplosionTemplate;
			}
			Vector3 position;
			bool hasSnapshotPosition = TryCaptureBarrelSnapshot(barrelRigidbodies, barrelAnchors, root, out position);
			plan = new BarrelDeathPlan
			{
				Root = root,
				DelaySeconds = delayFromConditionalEvents,
				BarrelVisuals = barrelVisuals,
				BarrelRigidbodies = barrelRigidbodies,
				BarrelAnchors = barrelAnchors,
				SnapshotPosition = position,
				HasSnapshotPosition = hasSnapshotPosition,
				CachedBarrelExplosion = cachedExplosion,
				CachedExplosionPrefab = val,
				FallbackExplosionTemplate = (cachedExplosion ?? fallbackTemplate),
				OwnerUnit = ((Component)root).GetComponent<Unit>()
			};
			return true;
		}

		private static float GetDelayFromConditionalEvents(ConditionalEvent[] conditionalEvents)
		{
			float num = 0.45f;
			if (conditionalEvents == null)
			{
				return num;
			}
			for (int i = 0; i < conditionalEvents.Length; i++)
			{
				ConditionalEventInstance[] array = conditionalEvents[i]?.events;
				if (array == null)
				{
					continue;
				}
				foreach (ConditionalEventInstance val in array)
				{
					if (HasUnitDeathCondition(val))
					{
						float delay = val.delay;
						if (delay > num)
						{
							num = delay;
						}
					}
				}
			}
			return num;
		}

		private static void CollectBarrelHoldableData(Transform root, Holdable[] holdables, out Rigidbody[] barrelRigidbodies, out Transform[] barrelAnchors, out GameObject[] barrelVisuals)
		{
			List<Rigidbody> list = new List<Rigidbody>();
			List<Transform> list2 = new List<Transform>();
			List<GameObject> list3 = new List<GameObject>();
			HashSet<int> hashSet = new HashSet<int>();
			HashSet<int> hashSet2 = new HashSet<int>();
			HashSet<int> hashSet3 = new HashSet<int>();
			if (holdables != null)
			{
				foreach (Holdable holdable in holdables)
				{
					if (IsBarrelHoldable(holdable))
					{
						AddBarrelHoldable(holdable, list, list2, list3, hashSet, hashSet2, hashSet3);
					}
				}
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					if (hashSet2.Add(((Object)val).GetInstanceID()))
					{
						list2.Add(val);
					}
					if (hashSet3.Add(((Object)((Component)val).gameObject).GetInstanceID()))
					{
						list3.Add(((Component)val).gameObject);
					}
					Rigidbody componentInChildren = ((Component)val).GetComponentInChildren<Rigidbody>();
					if ((Object)(object)componentInChildren != (Object)null && hashSet.Add(((Object)componentInChildren).GetInstanceID()))
					{
						list.Add(componentInChildren);
					}
				}
			}
			barrelRigidbodies = list.ToArray();
			barrelAnchors = list2.ToArray();
			barrelVisuals = list3.ToArray();
		}

		private static void AddBarrelHoldable(Holdable holdable, List<Rigidbody> rigidbodies, List<Transform> anchors, List<GameObject> visuals, HashSet<int> seenBodies, HashSet<int> seenAnchors, HashSet<int> seenVisuals)
		{
			Transform val = (((Object)(object)holdable.rig != (Object)null) ? ((Component)holdable.rig).transform : ((Component)holdable).transform);
			if ((Object)(object)val != (Object)null && seenAnchors.Add(((Object)val).GetInstanceID()))
			{
				anchors.Add(val);
			}
			Rigidbody val2 = holdable.rig ?? ((Component)holdable).GetComponentInChildren<Rigidbody>();
			if ((Object)(object)val2 != (Object)null && seenBodies.Add(((Object)val2).GetInstanceID()))
			{
				rigidbodies.Add(val2);
			}
			if (seenVisuals.Add(((Object)((Component)holdable).gameObject).GetInstanceID()))
			{
				visuals.Add(((Component)holdable).gameObject);
			}
		}

		private static void PickExplosionAssets(Explosion[] explosions, out Explosion cachedExplosion, out Explosion fallbackTemplate)
		{
			cachedExplosion = null;
			fallbackTemplate = null;
			float num = float.MinValue;
			if (explosions == null)
			{
				return;
			}
			foreach (Explosion val in explosions)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				if (fallbackTemplate == null)
				{
					fallbackTemplate = val;
				}
				if (IsBarrelDeathExplosionSource(((Component)val).transform, ((Component)val).transform.root))
				{
					float num2 = ScoreBarrelExplosion(val);
					if (!(num2 <= num))
					{
						num = num2;
						cachedExplosion = val;
					}
				}
			}
		}

		private static GameObject FindExplosionPrefab(Transform root)
		{
			GameObject preferred = null;
			GameObject val = null;
			GameObject any = null;
			RemoveAfterSeconds[] componentsInChildren = ((Component)root).GetComponentsInChildren<RemoveAfterSeconds>(true);
			foreach (RemoveAfterSeconds val2 in componentsInChildren)
			{
				GameObject val3 = val2?.objectToSpawn;
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				if (any == null)
				{
					any = val3;
				}
				if (val2.spawnObjectOnMainRig)
				{
					if (val == null)
					{
						val = val3;
					}
				}
				else
				{
					preferred = val3;
				}
			}
			if ((Object)(object)preferred != (Object)null)
			{
				return preferred;
			}
			KillAfterSeconds[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<KillAfterSeconds>(true);
			foreach (KillAfterSeconds val4 in componentsInChildren2)
			{
				GameObject val5 = val4?.objectToSpawn;
				if (!((Object)(object)val5 == (Object)null))
				{
					if (any == null)
					{
						any = val5;
					}
					if (!val4.spawnObjectOnMainRig)
					{
						return val5;
					}
					if (val == null)
					{
						val = val5;
					}
				}
			}
			CollectSpawnPrefabs(root, ref preferred, ref any);
			return preferred ?? val ?? any;
		}

		private static void CollectSpawnPrefabs(Transform root, ref GameObject preferred, ref GameObject any)
		{
			SpawnObject[] componentsInChildren = ((Component)root).GetComponentsInChildren<SpawnObject>(true);
			foreach (SpawnObject val in componentsInChildren)
			{
				GameObject objectToSpawn = val.objectToSpawn;
				if (!((Object)(object)objectToSpawn == (Object)null))
				{
					if (any == null)
					{
						any = objectToSpawn;
					}
					if (IsRollingBarrelGearTransform(((Component)val).transform))
					{
						preferred = objectToSpawn;
					}
				}
			}
			CollisionEvent[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<CollisionEvent>(true);
			foreach (CollisionEvent val2 in componentsInChildren2)
			{
				GameObject objectToSpawn2 = val2.objectToSpawn;
				if (!((Object)(object)objectToSpawn2 == (Object)null))
				{
					if (any == null)
					{
						any = objectToSpawn2;
					}
					if (IsRollingBarrelGearTransform(((Component)val2).transform))
					{
						preferred = objectToSpawn2;
					}
				}
			}
		}

		internal static bool IsBarrelDeathDelayEvent(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			ConditionalEvent componentInParent = component.GetComponentInParent<ConditionalEvent>();
			if (componentInParent?.events == null)
			{
				return IsRollingBarrelGearTransform(component.transform);
			}
			for (int i = 0; i < componentInParent.events.Length; i++)
			{
				if (HasUnitDeathCondition(componentInParent.events[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static GameObject FindExplosionPrefabFromTemplate(Explosion template)
		{
			if ((Object)(object)template == (Object)null)
			{
				return null;
			}
			Transform val = ((Component)template).transform;
			while ((Object)(object)val != (Object)null)
			{
				RemoveAfterSeconds component = ((Component)val).GetComponent<RemoveAfterSeconds>();
				if ((Object)(object)component?.objectToSpawn != (Object)null)
				{
					return component.objectToSpawn;
				}
				val = val.parent;
			}
			return null;
		}

		private static bool IsBarrelAbilityMountTransform(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			string name = ((Object)transform).name;
			if (name.IndexOf("Wings_Leg_Barrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (name.IndexOf("Leg_Barrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return name.IndexOf("BarrelRoller", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static bool IsBarrelRollerAbilityTransform(Transform transform)
		{
			return IsBarrelAbilityMountTransform(transform);
		}

		private static bool IsUnderBarrelAbilityMount(Transform transform, Transform ownerRoot)
		{
			Transform val = transform;
			while ((Object)(object)val != (Object)null && (!((Object)(object)ownerRoot != (Object)null) || !((Object)(object)val == (Object)(object)ownerRoot)))
			{
				if (IsBarrelAbilityMountTransform(val))
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static bool IsUnderBarrelRollerAbilityMount(Transform transform, Transform ownerRoot)
		{
			return IsUnderBarrelAbilityMount(transform, ownerRoot);
		}

		private static bool IsBarrelAbilityUnit(Transform root, Unit unit)
		{
			return MatchesBarrelRollerBlueprint(unit);
		}

		private static bool HasBarrelAbilityGear(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (IsBarrelAbilityMountTransform(componentsInChildren[i]))
				{
					return true;
				}
			}
			Holdable[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Holdable>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				if (IsBarrelHoldable(componentsInChildren2[i]))
				{
					return true;
				}
			}
			Explosion[] componentsInChildren3 = ((Component)root).GetComponentsInChildren<Explosion>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				if (IsBarrelDeathExplosionSource(((Component)componentsInChildren3[i]).transform, root))
				{
					return true;
				}
			}
			DelayEvent[] componentsInChildren4 = ((Component)root).GetComponentsInChildren<DelayEvent>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				if (IsBarrelDeathDelayEvent((Component)(object)componentsInChildren4[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsBarrelDeathExplosionSource(Transform transform, Transform root)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			if (ContainsBarrelExplosionName(((Object)((Component)transform).gameObject).name))
			{
				return true;
			}
			if (IsRollingBarrelGearTransform(transform))
			{
				return true;
			}
			return IsUnderBarrelAbilityMount(transform, root);
		}

		private static bool MatchesBarrelRollerBlueprint(Unit unit)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			object obj;
			if (unit == null)
			{
				obj = null;
			}
			else
			{
				UnitBlueprint unitBlueprint = unit.unitBlueprint;
				obj = ((unitBlueprint != null) ? unitBlueprint.Entity : null);
			}
			if (obj == null)
			{
				return false;
			}
			if (unit.unitBlueprint.Entity.GUID.m_ID == 846602731)
			{
				return true;
			}
			string name = unit.unitBlueprint.Entity.Name;
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			if (name.IndexOf("BOXER", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (name.IndexOf("BARRELROLLER", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return false;
		}

		private static bool HasUnitDeathCondition(ConditionalEventInstance instance)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			EventCondition[] array = instance?.conditions;
			if (array == null)
			{
				return false;
			}
			foreach (EventCondition obj in array)
			{
				if (obj != null && (int)obj.conditionType == 5)
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryResolveExplosionPosition(BarrelDeathPlan plan, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			if ((Object)(object)plan?.Root == (Object)null)
			{
				return false;
			}
			if (TryGetTrackedRigidbodyPosition(plan.BarrelRigidbodies, plan.Root, out position))
			{
				return true;
			}
			if (TryGetLiveScanPosition(plan.Root, plan.BarrelVisuals, out position))
			{
				return true;
			}
			if (TryGetAnchorPosition(plan.BarrelAnchors, plan.Root, out position))
			{
				return true;
			}
			if (plan.HasSnapshotPosition && IsUsableExplosionPosition(plan.Root, plan.SnapshotPosition))
			{
				position = plan.SnapshotPosition;
				return true;
			}
			DataHandler componentInChildren = ((Component)plan.Root).GetComponentInChildren<DataHandler>();
			if ((Object)(object)componentInChildren?.mainRig != (Object)null && IsUsableExplosionPosition(plan.Root, componentInChildren.mainRig.position))
			{
				position = componentInChildren.mainRig.position;
				return true;
			}
			if (IsUsableExplosionPosition(plan.Root, plan.Root.position))
			{
				position = plan.Root.position;
				return true;
			}
			return false;
		}

		private static bool TryCaptureBarrelSnapshot(Rigidbody[] barrelRigidbodies, Transform[] barrelAnchors, Transform root, out Vector3 position)
		{
			if (TryGetTrackedRigidbodyPosition(barrelRigidbodies, root, out position))
			{
				return true;
			}
			return TryGetAnchorPosition(barrelAnchors, root, out position);
		}

		private static bool TryGetAnchorPosition(Transform[] anchors, Transform root, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			if (anchors == null)
			{
				return false;
			}
			foreach (Transform val in anchors)
			{
				if (!((Object)(object)val == (Object)null))
				{
					position = GetTransformCenter(val);
					if (IsUsableExplosionPosition(root, position))
					{
						return true;
					}
				}
			}
			position = default(Vector3);
			return false;
		}

		private static bool TryGetTrackedRigidbodyPosition(Rigidbody[] trackedRigidbodies, Transform root, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			Rigidbody val = null;
			float num = float.MinValue;
			if (trackedRigidbodies != null)
			{
				foreach (Rigidbody val2 in trackedRigidbodies)
				{
					if (IsAliveRigidbody(val2))
					{
						float num2 = ScoreBarrelRigidbody(val2);
						if (num2 > num)
						{
							num = num2;
							val = val2;
						}
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			position = val.worldCenterOfMass;
			return IsUsableExplosionPosition(root, position);
		}

		private static bool TryGetLiveScanPosition(Transform root, GameObject[] barrelVisuals, out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			Rigidbody val = FindBarrelRigidbody(root, null);
			if ((Object)(object)val != (Object)null)
			{
				position = val.worldCenterOfMass;
				return IsUsableExplosionPosition(root, position);
			}
			Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren<Holdable>(true);
			foreach (Holdable val2 in componentsInChildren)
			{
				if (!IsBarrelHoldable(val2))
				{
					continue;
				}
				Transform val3 = (((Object)(object)val2.rig != (Object)null) ? ((Component)val2.rig).transform : ((Component)val2).transform);
				if (!((Object)(object)val3 == (Object)null))
				{
					position = GetTransformCenter(val3);
					if (IsUsableExplosionPosition(root, position))
					{
						return true;
					}
				}
			}
			Transform[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val4 in componentsInChildren2)
			{
				if (((Object)val4).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					position = GetTransformCenter(val4);
					if (IsUsableExplosionPosition(root, position))
					{
						return true;
					}
				}
			}
			if (barrelVisuals != null)
			{
				foreach (GameObject val5 in barrelVisuals)
				{
					if (!((Object)(object)val5 == (Object)null) && val5.activeInHierarchy)
					{
						position = GetTransformCenter(val5.transform);
						if (IsUsableExplosionPosition(root, position))
						{
							return true;
						}
					}
				}
			}
			position = default(Vector3);
			return false;
		}

		private static bool IsUsableExplosionPosition(Transform root, Vector3 position)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			if (float.IsNaN(position.x) || float.IsNaN(position.y) || float.IsNaN(position.z))
			{
				return false;
			}
			if (((Vector3)(ref position)).sqrMagnitude < 0.25f)
			{
				return false;
			}
			Vector3 position2 = root.position;
			DataHandler componentInChildren = ((Component)root).GetComponentInChildren<DataHandler>();
			if ((Object)(object)componentInChildren?.mainRig != (Object)null)
			{
				position2 = componentInChildren.mainRig.position;
			}
			Vector3 val = position - position2;
			return ((Vector3)(ref val)).sqrMagnitude <= 6400f;
		}

		private static bool IsAliveRigidbody(Rigidbody rigidbody)
		{
			return (Object)(object)rigidbody != (Object)null;
		}

		private static bool BelongsToRoot(Transform transform, Transform root)
		{
			if ((Object)(object)transform == (Object)null || (Object)(object)root == (Object)null)
			{
				return false;
			}
			return (Object)(object)transform.root == (Object)(object)root;
		}

		private static Rigidbody FindBarrelRigidbody(Transform root, Rigidbody[] trackedRigidbodies)
		{
			Rigidbody result = null;
			float num = float.MinValue;
			if (trackedRigidbodies != null)
			{
				foreach (Rigidbody val in trackedRigidbodies)
				{
					if (IsAliveRigidbody(val))
					{
						float num2 = ScoreBarrelRigidbody(val);
						if (num2 > num)
						{
							num = num2;
							result = val;
						}
					}
				}
			}
			Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren<Holdable>(true);
			foreach (Holdable val2 in componentsInChildren)
			{
				if (!IsBarrelHoldable(val2))
				{
					continue;
				}
				Rigidbody val3 = val2.rig ?? ((Component)val2).GetComponentInChildren<Rigidbody>();
				if (!((Object)(object)val3 == (Object)null) && BelongsToRoot(((Component)val3).transform, root))
				{
					float num3 = ScoreBarrelRigidbody(val3) + 50f;
					if (num3 > num)
					{
						num = num3;
						result = val3;
					}
				}
			}
			Rigidbody[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val4 in componentsInChildren2)
			{
				if (BelongsToRoot(((Component)val4).transform, root) && IsRollingBarrelGearTransform(((Component)val4).transform))
				{
					float num4 = ScoreBarrelRigidbody(val4);
					if (num4 > num)
					{
						num = num4;
						result = val4;
					}
				}
			}
			return result;
		}

		private static bool IsBarrelHoldable(Holdable holdable)
		{
			if ((Object)(object)holdable == (Object)null)
			{
				return false;
			}
			if (IsAbilityMountName(((Object)holdable).name))
			{
				return false;
			}
			if (IsBarrelName(((Object)holdable).name))
			{
				return true;
			}
			return IsRollingBarrelGearTransform(((Component)holdable).transform);
		}

		private static bool IsAbilityMountName(string objectName)
		{
			if (string.IsNullOrEmpty(objectName))
			{
				return false;
			}
			if (objectName.IndexOf("BarrelRoller", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return objectName.IndexOf("Wings_Leg_Barrel", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		internal static bool IsRollingBarrelGearTransform(Transform transform)
		{
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				if (IsAbilityMountName(((Object)val).name))
				{
					return false;
				}
				if (((Object)val).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				if (IsBarrelName(((Object)val).name))
				{
					return true;
				}
				if ((Object)(object)val.parent == (Object)null)
				{
					break;
				}
				val = val.parent;
			}
			return false;
		}

		private static float ScoreBarrelRigidbody(Rigidbody rigidbody)
		{
			float num = rigidbody.mass;
			string name = ((Object)((Component)rigidbody).transform).name;
			if (name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				num += 200f;
			}
			if (IsBarrelName(name))
			{
				num += 100f;
			}
			return num;
		}

		private static Vector3 GetTransformCenter(Transform transform)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform == (Object)null)
			{
				return Vector3.zero;
			}
			Renderer[] componentsInChildren = ((Component)transform).GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren.Length != 0)
			{
				Bounds bounds = componentsInChildren[0].bounds;
				for (int i = 1; i < componentsInChildren.Length; i++)
				{
					((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds);
				}
				return ((Bounds)(ref bounds)).center;
			}
			Rigidbody componentInChildren = ((Component)transform).GetComponentInChildren<Rigidbody>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return componentInChildren.worldCenterOfMass;
			}
			return transform.position;
		}

		private static bool IsBarrelName(string objectName)
		{
			if (string.IsNullOrEmpty(objectName))
			{
				return false;
			}
			if (objectName.IndexOf("Barrel", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return false;
			}
			if (objectName.IndexOf("DoubleBarrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (objectName.IndexOf("GunBarrel", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			return true;
		}

		private static Unit RefreshOwnerUnit(BarrelDeathPlan plan)
		{
			if (plan == null)
			{
				return null;
			}
			if ((Object)(object)plan.OwnerUnit != (Object)null)
			{
				return plan.OwnerUnit;
			}
			if ((Object)(object)plan.Root == (Object)null)
			{
				return null;
			}
			plan.OwnerUnit = ((Component)plan.Root).GetComponent<Unit>();
			return plan.OwnerUnit;
		}

		private static void RememberSharedDeathExplosionAssets(GameObject prefab, Explosion template)
		{
			if ((Object)(object)prefab != (Object)null && (Object)(object)_sharedBarrelDeathExplosionPrefab == (Object)null)
			{
				_sharedBarrelDeathExplosionPrefab = prefab;
			}
			if ((Object)(object)template != (Object)null && (Object)(object)_sharedBarrelDeathExplosionTemplate == (Object)null)
			{
				_sharedBarrelDeathExplosionTemplate = template;
			}
		}

		private static void TriggerSingleBarrelExplosion(BarrelDeathPlan plan, Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFinite(position))
			{
				return;
			}
			Unit ownerUnit = RefreshOwnerUnit(plan);
			Explosion template = plan.FallbackExplosionTemplate ?? plan.CachedBarrelExplosion ?? _sharedBarrelDeathExplosionTemplate;
			if ((Object)(object)plan.CachedExplosionPrefab != (Object)null)
			{
				GameObject obj = Object.Instantiate<GameObject>(plan.CachedExplosionPrefab, position, Quaternion.identity);
				PrepareDeathExplosionObject(obj, template);
				FinalizeDeathExplosionInstance(obj, ownerUnit);
				obj.SetActive(true);
				TriggerExplosionOnObject(obj, template);
			}
			else if ((Object)(object)_sharedBarrelDeathExplosionPrefab != (Object)null)
			{
				GameObject obj2 = Object.Instantiate<GameObject>(_sharedBarrelDeathExplosionPrefab, position, Quaternion.identity);
				PrepareDeathExplosionObject(obj2, template);
				FinalizeDeathExplosionInstance(obj2, ownerUnit);
				obj2.SetActive(true);
				TriggerExplosionOnObject(obj2, template);
			}
			else if ((Object)(object)plan.CachedBarrelExplosion != (Object)null)
			{
				GameObject obj3 = Object.Instantiate<GameObject>(((Component)plan.CachedBarrelExplosion).gameObject, position, ((Component)plan.CachedBarrelExplosion).transform.rotation);
				PrepareDeathExplosionObject(obj3, template);
				FinalizeDeathExplosionInstance(obj3, ownerUnit);
				obj3.SetActive(true);
				TriggerExplosionOnObject(obj3, template);
				Object.Destroy((Object)(object)obj3, 12f);
			}
			else if (!TryCreateFallbackExplosion(position, template, ownerUnit))
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)"Barrel death fallback explode failed: no viable explosion path");
				}
			}
		}

		private static void AttachTeamHolder(GameObject instance, Unit ownerUnit)
		{
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)ownerUnit == (Object)null))
			{
				TeamHolder.AddTeamHolder(instance, ownerUnit, (TeamHolder)null);
			}
		}

		private static void FinalizeDeathExplosionInstance(GameObject instance, Unit ownerUnit)
		{
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)ownerUnit == (Object)null))
			{
				AttachTeamHolder(instance, ownerUnit);
				ApplyOwnerLevel(instance, ownerUnit);
			}
		}

		private static void StripDeathExplosionStatusEffects(GameObject instance)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				Explosion[] componentsInChildren = instance.GetComponentsInChildren<Explosion>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].addEffectFromParent = false;
				}
				ExplosionEffect[] componentsInChildren2 = instance.GetComponentsInChildren<ExplosionEffect>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren2[i]);
				}
				AddTargetableEffect[] componentsInChildren3 = instance.GetComponentsInChildren<AddTargetableEffect>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren3[i]);
				}
			}
		}

		private static void ApplyOwnerLevel(GameObject instance, Unit ownerUnit)
		{
			Level val = FindOwnerLevel(ownerUnit);
			if (!((Object)(object)val == (Object)null))
			{
				Level obj = instance.GetComponent<Level>() ?? instance.AddComponent<Level>();
				obj.levelMultiplier = val.levelMultiplier;
				obj.level = val.level;
				obj.ignoreTeam = val.ignoreTeam;
				TargetableEffect[] componentsInChildren = instance.GetComponentsInChildren<TargetableEffect>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].damageMultiplier = val.levelMultiplier;
				}
			}
		}

		private static Level FindOwnerLevel(Unit ownerUnit)
		{
			if ((Object)(object)ownerUnit == (Object)null)
			{
				return null;
			}
			Level component = ((Component)ownerUnit).GetComponent<Level>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			return ((Component)ownerUnit).GetComponentInChildren<Level>(true);
		}

		private static void HideBarrelGear(BarrelDeathPlan plan)
		{
			if (plan != null)
			{
				HideBarrelGearLive(plan.Root, plan.BarrelVisuals, plan.BarrelRigidbodies);
			}
		}

		private static void HideBarrelGearLive(Transform root, GameObject[] cachedVisuals, Rigidbody[] cachedRigidbodies)
		{
			if (cachedVisuals != null)
			{
				for (int i = 0; i < cachedVisuals.Length; i++)
				{
					HideGameObjectTree(cachedVisuals[i]);
				}
			}
			if (cachedRigidbodies != null)
			{
				for (int j = 0; j < cachedRigidbodies.Length; j++)
				{
					HideRigidbodyGear(cachedRigidbodies[j]);
				}
			}
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Holdable[] componentsInChildren = ((Component)root).GetComponentsInChildren<Holdable>(true);
			foreach (Holdable val in componentsInChildren)
			{
				if (IsBarrelHoldable(val))
				{
					HideGameObjectTree(((Component)val).gameObject);
					if ((Object)(object)val.rig != (Object)null)
					{
						HideRigidbodyGear(val.rig);
					}
				}
			}
			Transform[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren2)
			{
				if (IsRollingBarrelGearTransform(val2) || ((Object)val2).name.IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					HideGameObjectTree(((Component)val2).gameObject);
				}
			}
		}

		private static void HideRigidbodyGear(Rigidbody rigidbody)
		{
			if (!((Object)(object)rigidbody == (Object)null))
			{
				HideGameObjectTree(((Component)rigidbody).gameObject);
			}
		}

		private static void HideGameObjectTree(GameObject target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = target.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.enabled = false;
				}
			}
			Collider[] componentsInChildren2 = target.GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.enabled = false;
				}
			}
			target.SetActive(false);
		}

		private static bool HasRecentBarrelExplosion(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			if (!RecentBarrelExplosionTimeByRoot.TryGetValue(((Object)root).GetInstanceID(), out var value))
			{
				return false;
			}
			return Time.time - value <= 2.5f;
		}

		private static float ScoreBarrelExplosion(Explosion explosion)
		{
			float num = (((Object)(object)explosion != (Object)null) ? (explosion.radius + explosion.damage * 0.01f) : 0f);
			if ((((explosion != null) ? ((Object)((Component)explosion).transform).name : null) ?? string.Empty).IndexOf("BarrelArmor", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				num += 100f;
			}
			return num;
		}

		private static void PrepareDeathExplosionObject(GameObject instance, Explosion template)
		{
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			instance.SetActive(false);
			StripDeathExplosionStatusEffects(instance);
			Explosion[] componentsInChildren = instance.GetComponentsInChildren<Explosion>(true);
			foreach (Explosion val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.automatic = false;
					ApplyDeathExplosionStats(val, template);
				}
			}
		}

		private static bool TryCreateFallbackExplosion(Vector3 position, Explosion template, Unit ownerUnit)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFinite(position) || ((Vector3)(ref position)).sqrMagnitude < 0.25f)
			{
				return false;
			}
			GameObject val = new GameObject("StayCombatFix_BarrelExplosion");
			try
			{
				val.transform.position = position;
				FinalizeDeathExplosionInstance(val, ownerUnit);
				Explosion obj = val.AddComponent<Explosion>();
				ApplyDeathExplosionStats(obj, template);
				obj.automatic = false;
				obj.Explode();
				Object.Destroy((Object)(object)val, 10f);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)("Barrel death fallback explode failed: " + ex.Message));
				}
				Object.Destroy((Object)(object)val);
				return false;
			}
		}

		private static bool IsFinite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(value.x) && !float.IsNaN(value.y))
			{
				return !float.IsNaN(value.z);
			}
			return false;
		}

		private static void TriggerExplosionOnObject(GameObject instance, Explosion template)
		{
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Explosion[] componentsInChildren = instance.GetComponentsInChildren<Explosion>(true);
			Explosion val = null;
			float num = float.MinValue;
			foreach (Explosion val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					float num2 = val2.radius + val2.damage * 0.01f;
					if (!(num2 <= num))
					{
						num = num2;
						val = val2;
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				ApplyDeathExplosionStats(val, template);
				val.automatic = false;
				val.Explode();
			}
		}

		private unsafe static void ApplyDeathExplosionStats(Explosion explosion, Explosion template)
		{
			//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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099->IL0099: Incompatible stack types: O vs I4
			//IL_0093->IL0099: Incompatible stack types: I4 vs O
			//IL_0093->IL0099: Incompatible stack types: O vs I4
			if (!((Object)(object)explosion == (Object)null))
			{
				float radius = (((Object)(object)template != (Object)null) ? template.radius : 4f);
				float force = (((Object)(object)template != (Object)null) ? template.force : 350f);
				float minMassCap = (((Object)(object)template != (Object)null) ? template.minMassCap : 25f);
				explosion.damage = 15f;
				explosion.percentDamage = 0f;
				explosion.radius = radius;
				explosion.force = force;
				explosion.minMassCap = minMassCap;
				explosion.layerMask = LayerMask.op_Implicit(-1);
				object obj = explosion;
				int num;
				if ((Object)(object)template != (Object)null)
				{
					obj = template.forceDirection;
					num = (int)obj;
				}
				else
				{
					num = 0;
					obj = num;
					num = (int)obj;
				}
				System.Runtime.CompilerServices.Unsafe.Write(&((Explosion)num).forceDirection, (ForceDirection)obj);
				explosion.ignoreTeamMates = (Object)(object)template != (Object)null && template.ignoreTeamMates;
				explosion.ignoreRoot = true;
			}
		}
	}
	internal static class BarrelRollerDeathPatches
	{
		public static bool ConditionalEvent_OnUnitDead_Prefix(ConditionalEvent __instance)
		{
			Transform val = ((__instance != null) ? ((Component)__instance).transform.root : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			return !BarrelRollerDeathLogic.IsBarrelRollerRoot(val);
		}

		public static bool Explosion_Explode_Prefix(Explosion __instance)
		{
			BarrelRollerDeathLogic.PrepareBarrelOwnedExplosionForDetonation(__instance);
			return !BarrelRollerDeathLogic.TryBlockDuplicateBarrelExplosion(__instance);
		}

		public static void KillAfterSeconds_Spawn_Postfix(KillAfterSeconds __instance)
		{
			BarrelRollerDeathLogic.NotifyBarrelAbilityExplosionFromSpawn((__instance != null) ? ((Component)__instance).transform : null, __instance?.objectToSpawn);
		}

		public static void RemoveAfterSeconds_TriggerRemoval_Postfix(MonoBehaviour __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !(((object)__instance).GetType().Name != "RemoveAfterSeconds"))
			{
				GameObject value = Traverse.Create((object)__instance).Field<GameObject>("objectToSpawn").Value;
				BarrelRollerDeathLogic.NotifyBarrelAbilityExplosionFromSpawn(((Component)__instance).transform, value);
			}
		}

		public static bool DelayEvent_Go_Prefix(DelayEvent __instance)
		{
			Transform val = ((__instance != null) ? ((Component)__instance).transform.root : null);
			if ((Object)(object)val == (Object)null || !BarrelRollerDeathLogic.IsBarrelRollerRoot(val))
			{
				return true;
			}
			if (!BarrelRollerDeathLogic.IsBarrelDeathDelayEvent((Component)(object)__instance))
			{
				return true;
			}
			DataHandler componentInChildren = ((Component)val).GetComponentInChildren<DataHandler>();
			if ((Object)(object)componentInChildren == (Object)null || !componentInChildren.Dead)
			{
				return true;
			}
			return false;
		}

		public static void GameStateManager_EnterPlacementState_Postfix()
		{
			BarrelRollerDeathLogic.ResetBattleCaches();
		}
	}
	internal static class BattleCreatorSaveWhitelistFix
	{
		private static readonly FieldInfo BannedUnitsField = AccessTools.Field(AccessTools.TypeByName("BattleCreatorSaveUI"), "BannedUnits");

		private static readonly FieldInfo AllowedFactionsField = AccessTools.Field(AccessTools.TypeByName("BattleCreatorSaveUI"), "AllowedFactions");

		private static readonly MethodInfo GetAllowedUnitIdsMethod = AccessTools.Method(AccessTools.TypeByName("BattleCreatorSaveUI"), "GetAllowedUnitIDs", (Type[])null, (Type[])null);

		private static readonly MethodInfo UpdateUnitFilterMethod = AccessTools.Method(AccessTools.TypeByName("BattleCreatorSaveUI"), "UpdateUnitFilter", (Type[])null, (Type[])null);

		private static readonly FieldInfo FactionButtonPlacementUiField = AccessTools.Field(AccessTools.TypeByName("FactionButton"), "m_placementUI");

		private static readonly FieldInfo FactionButtonIsDraggingField = AccessTools.Field(AccessTools.TypeByName("FactionButton"), "isDragging");

		private static readonly Type UnitWhitelistUiType = AccessTools.TypeByName("UnitWhitelistUI");

		internal static bool OnUnitClicked(object saveUi, DatabaseID unit)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (saveUi == null || BannedUnitsField == null)
			{
				return true;
			}
			if (!(BannedUnitsField.GetValue(saveUi) is List<DatabaseID> list))
			{
				return true;
			}
			List<DatabaseID> allUnits = CollectAllUnitIds(AllowedFactionsField?.GetValue(saveUi) as Faction[]);
			DatabaseID[] allowedUnitIds = GetAllowedUnitIds(saveUi);
			if (IsFullyUnrestricted(list, allowedUnitIds, allUnits))
			{
				BanAllExceptUnit(list, allUnits, unit);
				RefreshFilter(saveUi);
				return false;
			}
			if (IsSoloUnit(allowedUnitIds, unit))
			{
				list.Clear();
				RefreshFilter(saveUi);
				return false;
			}
			if (list.Contains(unit))
			{
				list.Remove(unit);
			}
			else
			{
				list.Add(unit);
			}
			RefreshFilter(saveUi);
			return false;
		}

		internal static void OnFactionPointerUp(object factionButton, object eventData)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			if (factionButton == null || FactionButtonPlacementUiField == null || UnitWhitelistUiType == null || eventData == null || (FactionButtonIsDraggingField != null && (bool)FactionButtonIsDraggingField.GetValue(factionButton)))
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(eventData.GetType(), "button");
			if (fieldInfo != null && (int)fieldInfo.GetValue(eventData) != 0)
			{
				return;
			}
			object value = FactionButtonPlacementUiField.GetValue(factionButton);
			if (value == null || !UnitWhitelistUiType.IsInstanceOfType(value))
			{
				return;
			}
			PropertyInfo propertyInfo = AccessTools.Property(factionButton.GetType(), "WasAlreadySelected");
			if (propertyInfo == null || !(bool)propertyInfo.GetValue(factionButton))
			{
				return;
			}
			PropertyInfo propertyInfo2 = AccessTools.Property(factionButton.GetType(), "m_factionID");
			if (!(propertyInfo2 == null))
			{
				DatabaseID factionId = (DatabaseID)propertyInfo2.GetValue(factionButton);
				object obj = AccessTools.Field(UnitWhitelistUiType, "m_SaveUI")?.GetValue(value);
				if (obj != null)
				{
					SoloFaction(obj, factionId);
				}
			}
		}

		private static void SoloFaction(object saveUi, DatabaseID factionId)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!(BannedUnitsField?.GetValue(saveUi) is List<DatabaseID> list))
			{
				return;
			}
			List<DatabaseID> allUnits = CollectAllUnitIds(AllowedFactionsField?.GetValue(saveUi) as Faction[]);
			DatabaseID[] allowedUnitIds = GetAllowedUnitIds(saveUi);
			Faction faction = ContentDatabase.Instance().GetFaction(factionId);
			if (!((Object)(object)faction == (Object)null))
			{
				if (IsFullyUnrestricted(list, allowedUnitIds, allUnits))
				{
					BanAllExceptFaction(list, allUnits, faction);
					RefreshFilter(saveUi);
				}
				else if (IsSoloFaction(allowedUnitIds, allUnits, faction))
				{
					list.Clear();
					RefreshFilter(saveUi);
				}
			}
		}

		private static void BanAllExceptUnit(List<DatabaseID> bannedUnits, List<DatabaseID> allUnits, DatabaseID keepUnit)
		{
			//IL_000c: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			bannedUnits.Clear();
			for (int i = 0; i < allUnits.Count; i++)
			{
				if (allUnits[i] != keepUnit)
				{
					bannedUnits.Add(allUnits[i]);
				}
			}
		}

		private static void BanAllExceptFaction(List<DatabaseID> bannedUnits, List<DatabaseID> allUnits, Faction faction)
		{
			//IL_000d: 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)
			bannedUnits.Clear();
			for (int i = 0; i < allUnits.Count; i++)
			{
				if (!faction.DoesIncludeUnit(allUnits[i]))
				{
					bannedUnits.Add(allUnits[i]);
				}
			}
		}

		private static List<DatabaseID> CollectAllUnitIds(Faction[] allowedFactions)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			List<DatabaseID> list = new List<DatabaseID>();
			if (allowedFactions == null)
			{
				return list;
			}
			foreach (Faction val in allowedFactions)
			{
				if (((val != null) ? val.Units : null) == null)
				{
					continue;
				}
				for (int j = 0; j < val.Units.Length; j++)
				{
					UnitBlueprint val2 = val.Units[j];
					if (!((Object)(object)val2 == (Object)null) && val2.Entity != null)
					{
						DatabaseID gUID = val2.Entity.GUID;
						if (!list.Contains(gUID))
						{
							list.Add(gUID);
						}
					}
				}
			}
			return list;
		}

		private static DatabaseID[] GetAllowedUnitIds(object saveUi)
		{
			if (GetAllowedUnitIdsMethod == null)
			{
				return (DatabaseID[])(object)new DatabaseID[0];
			}
			return (DatabaseID[])(((object)(GetAllowedUnitIdsMethod.Invoke(saveUi, null) as DatabaseID[])) ?? ((object)new DatabaseID[0]));
		}

		private static bool IsFullyUnrestricted(List<DatabaseID> bannedUnits, DatabaseID[] allowedUnits, List<DatabaseID> allUnits)
		{
			if (bannedUnits.Count == 0 && allowedUnits.Length == allUnits.Count)
			{
				return allUnits.Count > 0;
			}
			return false;
		}

		private static bool IsSoloUnit(DatabaseID[] allowedUnits, DatabaseID unit)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (allowedUnits.Length == 1)
			{
				return allowedUnits[0] == unit;
			}
			return false;
		}

		private static bool IsSoloFaction(DatabaseID[] allowedUnits, List<DatabaseID> allUnits, Faction faction)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (allUnits.Count == 0 || (Object)(object)faction == (Object)null)
			{
				return false;
			}
			for (int i = 0; i < allUnits.Count; i++)
			{
				DatabaseID val = allUnits[i];
				bool num = faction.DoesIncludeUnit(val);
				bool flag = ContainsUnit(allowedUnits, val);
				if (num != flag)
				{
					return false;
				}
			}
			return true;
		}

		private static bool ContainsUnit(DatabaseID[] allowedUnits, DatabaseID id)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < allowedUnits.Length; i++)
			{
				if (allowedUnits[i] == id)
				{
					return true;
				}
			}
			return false;
		}

		private static void RefreshFilter(object saveUi)
		{
			UpdateUnitFilterMethod?.Invoke(saveUi, null);
		}
	}
	internal static class BattleCreatorSaveWhitelistPatches
	{
		public static bool OnUnitClicked_Prefix(object __instance, DatabaseID unit)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return BattleCreatorSaveWhitelistFix.OnUnitClicked(__instance, unit);
		}

		public static void OnFactionPointerUp_Postfix(object __instance, object eventData)
		{
			BattleCreatorSaveWhitelistFix.OnFactionPointerUp(__instance, eventData);
		}
	}
	internal static class ConfigCleanup
	{
		private static readonly ConfigDefinition[] OrphanedMonolithKeys = (ConfigDefinition[])(object)new ConfigDefinition[42]
		{
			new ConfigDefinition("Mirror.Shield", "Enabled"),
			new ConfigDefinition("Mirror.Shield", "Improved"),
			new ConfigDefinition("Mirror.Shield", "BreakSoundEnabled"),
			new ConfigDefinition("Mirror.Shield", "BreakSoundMode"),
			new ConfigDefinition("Mirror.Shield", "VanillaBreakSoundRef"),
			new ConfigDefinition("Mirror.Shield", "CustomBreakSoundFile"),
			new ConfigDefinition("Mirror.Shield", "BreakSoundVolume"),
			new ConfigDefinition("Possession.FirstPerson", "FreeAim"),
			new ConfigDefinition("Combat.HeadshotFeedback", "Enabled"),
			new ConfigDefinition("Combat.HeadshotFeedback", "FirstHeadDamageMultiplier"),
			new ConfigDefinition("Combat.HeadshotFeedback", "RepeatHeadDamageMultiplier"),
			new ConfigDefinition("Combat.HeadshotFeedback", "FirstStaggerDamageThreshold"),
			new ConfigDefinition("Combat.HeadshotFeedback", "RepeatStaggerDamageThreshold"),
			new ConfigDefinition("Combat.HeadshotFeedback", "BaseStunSeconds"),
			new ConfigDefinition("Combat.HeadshotFeedback", "DamageStep"),
			new ConfigDefinition("Combat.HeadshotFeedback", "StunSecondsPer50Damage"),
			new ConfigDefinition("Combat.LimbDamage", "Enabled"),
			new ConfigDefinition("Combat.LimbDamage", "LimbMultiplier"),
			new ConfigDefinition("CustomVoices", "Enabled"),
			new ConfigDefinition("CustomVoices", "PreviewVolume"),
			new ConfigDefinition("CustomVoices", "BattleVolume"),
			new ConfigDefinition("CustomVoices", "MaxDurationSeconds"),
			new ConfigDefinition("UnitEditor", "CustomTargetingTypes"),
			new ConfigDefinition("UnitEditor", "NearRangeAttackRangeFraction"),
			new ConfigDefinition("UnitEditor", "MaxSearchRangeMultiplier"),
			new ConfigDefinition("UnitEditor", "ShortRangeAttackThreshold"),
			new ConfigDefinition("UnitEditor", "ShortRangeNearFraction"),
			new ConfigDefinition("UnitEditor", "ShortRangeApproachMultiplier"),
			new ConfigDefinition("UnitEditor", "LongRangeNearFraction"),
			new ConfigDefinition("UnitEditor", "LongRangeApproachMultiplier"),
			new ConfigDefinition("UnitEditor", "RangedEnemiesShortNearFraction"),
			new ConfigDefinition("UnitEditor", "RangedEnemiesLongNearFraction"),
			new ConfigDefinition("UnitEditor", "MostExpensiveEnemyRetargetInterval"),
			new ConfigDefinition("UnitEditor", "CustomEnemyTargetingRetargetInterval"),
			new ConfigDefinition("UnitEditor", "CustomFootsteps"),
			new ConfigDefinition("UnitEditor", "MoveWhileTurningEnabled"),
			new ConfigDefinition("UnitEditor", "CustomFootstepsDebug"),
			new ConfigDefinition("UnitEditor", "FootstepPitchMin"),
			new ConfigDefinition("UnitEditor", "FootstepPitchMax"),
			new ConfigDefinition("Movement", "FixNeverStopDirectChargeInRange"),
			new ConfigDefinition("TeamLine", "Enabled"),
			new ConfigDefinition("WinConditions", "Enabled")
		};

		internal static void RemoveOrphanedMonolithKeys(ConfigFile config)
		{
			ConfigDefinition[] orphanedMonolithKeys = OrphanedMonolithKeys;
			foreach (ConfigDefinition val in orphanedMonolithKeys)
			{
				config.Remove(val);
			}
		}
	}
	internal static class CustomUnitRangedMovementFix
	{
		private const float FallbackWaitingDistance = 100f;

		private static float? _cachedVanillaWaitingDistance;

		private static bool _loggedResolution;

		private static string _waitingDistanceSource = "default fallback";

		internal static void EnsureRangedHoldDistance(UnitBlueprint blueprint)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!UnitMarkerConfig.FixRangedEdgeHold || (Object)(object)blueprint == (Object)null || !blueprint.IsCustomUnit)
			{
				return;
			}
			List<IMovementComponent> movementComponents = blueprint.MovementComponents;
			if (movementComponents == null || movementComponents.Count == 0)
			{
				return;
			}
			float num = ResolveWaitingDistance(blueprint);
			bool flag = false;
			for (int i = 0; i < movementComponents.Count; i++)
			{
				if (movementComponents[i] is KeepRangedDistance val && !(val.WaitingDistance > 0f))
				{
					val.WaitingDistance = num;
					movementComponents[i] = (IMovementComponent)(object)val;
					flag = true;
				}
			}
			if (flag && !_loggedResolution)
			{
				_loggedResolution = true;
				Plugin.LogInfo($"Custom unit ranged edge hold: WaitingDistance={num:0.##} " + "(source=" + DescribeWaitingDistanceSource() + ")");
			}
		}

		public static void DeserializedUnit_Postfix(ref UnitBlueprint __result)
		{
			EnsureRangedHoldDistance(__result);
		}

		public static void Spawn_Prefix(UnitBlueprint __instance)
		{
			EnsureRangedHoldDistance(__instance);
		}

		private static float ResolveWaitingDistance(UnitBlueprint blueprint)
		{
			float? num = TryGetVanillaWaitingDistance();
			if (num.HasValue)
			{
				_waitingDistanceSource = "vanilla template";
				return num.Value;
			}
			float num2 = TryGetWaitingDistanceFromWeapons(blueprint);
			if (num2 > 0f)
			{
				_waitingDistanceSource = "weapon range fallback";
				return num2;
			}
			_waitingDistanceSource = "default fallback";
			return 100f;
		}

		private static float? TryGetVanillaWaitingDistance()
		{
			if (_cachedVanillaWaitingDistance.HasValue)
			{
				return _cachedVanillaWaitingDistance.Value;
			}
			ContentDatabase val = ContentDatabase.Instance();
			if (val == null)
			{
				return null;
			}
			foreach (UnitBlueprint item in val.GetAllUnitBlueprints() ?? Enumerable.Empty<UnitBlueprint>())
			{
				if (!((Object)(object)item == (Object)null) && !item.IsCustomUnit && TryGetKeepRangedDistance(item.MovementComponents, out var waitingDistance))
				{
					_cachedVanillaWaitingDistance = waitingDistance;
					return waitingDistance;
				}
			}
			return null;
		}

		private static bool TryGetKeepRangedDistance(IReadOnlyList<IMovementComponent> movementComponents, out float waitingDistance)
		{
			//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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			waitingDistance = 0f;
			if (movementComponents == null)
			{
				return false;
			}
			for (int i = 0; i < movementComponents.Count; i++)
			{
				if (movementComponents[i] is KeepRangedDistance val && !(val.WaitingDistance <= 0f))
				{
					waitingDistance = val.WaitingDistance;
					return true;
				}
			}
			return false;
		}

		private static float TryGetWaitingDistanceFromWeapons(UnitBlueprint blueprint)
		{
			float num = 0f;
			if ((Object)(object)blueprint.RightWeapon != (Object)null)
			{
				RangeWeapon component = blueprint.RightWeapon.GetComponent<RangeWeapon>();
				if ((Object)(object)component != (Object)null)
				{
					num = Mathf.Max(num, ((Weapon)component).maxRange);
				}
			}
			if ((Object)(object)blueprint.LeftWeapon != (Object)null)
			{
				RangeWeapon component2 = blueprint.LeftWeapon.GetComponent<RangeWeapon>();
				if ((Object)(object)component2 != (Object)null)
				{
					num = Mathf.Max(num, ((Weapon)component2).maxRange);
				}
			}
			if (num <= 0f)
			{
				return 0f;
			}
			return num + 0.3f;
		}

		private static string DescribeWaitingDistanceSource()
		{
			return _waitingDistanceSource;
		}
	}
	internal static class EcsComponentHelper
	{
		private static readonly PropertyInfo WorldActiveProperty = AccessTools.Property(typeof(World), "Active");

		private static readonly MethodInfo GetExistingManagerMethod = AccessTools.Method(typeof(World), "GetExistingManager", (Type[])null, (Type[])null);

		private static readonly PropertyInfo ComponentSystemEntityManagerProperty = AccessTools.Property(typeof(ComponentSystemBase), "EntityManager");

		internal static readonly Type GameObjectEntityType = AccessTools.TypeByName("GameObjectEntity") ?? AccessTools.TypeByName("Unity.Entities.Hybrid.GameObjectEntity, Unity.Entities.Hybrid");

		internal static bool IsAvailable
		{
			get
			{
				if (WorldActiveProperty != null && GetExistingManagerMethod != null)
				{
					return ComponentSystemEntityManagerProperty != null;
				}
				return false;
			}
		}

		internal static World GetActiveWorld()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return (World)(WorldActiveProperty?.GetValue(null, null));
		}

		internal static EntityManager GetEntityManager()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			World activeWorld = GetActiveWorld();
			if (activeWorld == null || GetExistingManagerMethod == null)
			{
				return null;
			}
			Type type = AccessTools.TypeByName("Landfall.TABS.AI.Systems.UnitECSToMonoSyncSystem, Assembly-CSharp");
			if (type == null)
			{
				return null;
			}
			object? obj = GetExistingManagerMethod.MakeGenericMethod(type).Invoke(activeWorld, null);
			ComponentSystemBase val = (ComponentSystemBase)((obj is ComponentSystemBase) ? obj : null);
			if (val == null)
			{
				return null;
			}
			return (EntityManager)ComponentSystemEntityManagerProperty.GetValue(val, null);
		}

		internal static TManager GetExistingManager<TManager>() where TManager : class
		{
			World activeWorld = GetActiveWorld();
			if (activeWorld == null || GetExistingManagerMethod == null)
			{
				return null;
			}
			return (TManager)GetExistingManagerMethod.MakeGenericMethod(typeof(TManager)).Invoke(activeWorld, null);
		}

		internal static bool TryGetComponentData<T>(EntityManager entityManager, Entity entity, out T data) where T : struct, IComponentData
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			data = default(T);
			if (!entityManager.IsCreated || !entityManager.Exists(entity) || !entityManager.HasComponent<T>(entity))
			{
				return false;
			}
			data = entityManager.GetComponentData<T>(entity);
			return true;
		}

		internal static bool TryGetEntityManager(Component component, out Entity entity, out EntityManager entityManager)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			entity = Entity.Null;
			entityManager = null;
			if ((Object)(object)component == (Object)null || GameObjectEntityType == null)
			{
				return false;
			}
			Component component2 = component.GetComponent(GameObjectEntityType);
			if ((Object)(object)component2 == (Object)null)
			{
				return false;
			}
			PropertyInfo propertyInfo = AccessTools.Property(GameObjectEntityType, "Entity");
			PropertyInfo propertyInfo2 = AccessTools.Property(GameObjectEntityType, "EntityManager");
			if (propertyInfo == null || propertyInfo2 == null)
			{
				return false;
			}
			entity = (Entity)propertyInfo.GetValue(component2, null);
			entityManager = (EntityManager)propertyInfo2.GetValue(component2, null);
			return entityManager.IsCreated;
		}

		internal static T GetArrayItem<T>(object array, int index)
		{
			PropertyInfo? property = array.GetType().GetProperty("Item", new Type[1] { typeof(int) });
			if (property == null)
			{
				throw new MissingMemberException(array.GetType().FullName, "Item[int]");
			}
			return (T)property.GetValue(array, new object[1] { index });
		}
	}
	internal sealed class FactionCreatorCostHoverState : MonoBehaviour
	{
		private bool _captured;

		private Transform _costParent;

		private int _costSiblingIndex;

		private Vector2 _anchorMin;

		private Vector2 _anchorMax;

		private Vector2 _pivot;

		private Vector2 _anchoredPosition;

		private Vector3 _localScale;

		internal void CaptureCostLayout(RectTransform costRect)
		{
			//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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!_captured && !((Object)(object)costRect == (Object)null))
			{
				_costParent = ((Transform)costRect).parent;
				_costSiblingIndex = ((Transform)costRect).GetSiblingIndex();
				_anchorMin = costRect.anchorMin;
				_anchorMax = costRect.anchorMax;
				_pivot = costRect.pivot;
				_anchoredPosition = costRect.anchoredPosition;
				_localScale = ((Transform)costRect).localScale;
				_captured = true;
			}
		}

		internal void RestoreCostLayout(RectTransform costRect)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (_captured && !((Object)(object)costRect == (Object)null))
			{
				((Transform)costRect).SetParent(_costParent, false);
				((Transform)costRect).SetSiblingIndex(_costSiblingIndex);
				costRect.anchorMin = _anchorMin;
				costRect.anchorMax = _anchorMax;
				costRect.pivot = _pivot;
				costRect.anchoredPosition = _anchoredPosition;
				((Transform)costRect).localScale = _localScale;
			}
		}

		internal static FactionCreatorCostHoverState GetOrCreate(UnitButtonBase button)
		{
			return ((Component)button).gameObject.GetComponent<FactionCreatorCostHoverState>() ?? ((Component)button).gameObject.AddComponent<FactionCreatorCostHoverState>();
		}
	}
	internal sealed class FactionCreatorDragScrollSession : MonoBehaviour
	{
		private ScrollRect _scrollRect;

		private Camera _eventCamera;

		private FactionCreatorUnitDragReorder _drag;

		internal void Begin(ScrollRect scrollRect, Camera eventCamera, FactionCreatorUnitDragReorder drag)
		{
			_scrollRect = scrollRect;
			_eventCamera = eventCamera;
			_drag = drag;
		}

		private void Update()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_scrollRect == (Object)null) && !((Object)(object)_drag == (Object)null))
			{
				FactionCreatorReorderLogic.UpdateDragScroll(_scrollRect, _drag.CurrentScreenPosition, _eventCamera);
			}
		}
	}
	internal static class FactionCreatorDropGap
	{
		private const string GapObjectName = "StayCombatFix_DropGap";

		internal static RectTransform Create(RectTransform listParent, RectTransform unitButton, bool horizontal)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("StayCombatFix_DropGap", new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)listParent, false);
			((Transform)component).localScale = Vector3.one;
			LayoutElement obj = val.AddComponent<LayoutElement>();
			float num = LayoutUtility.GetPreferredWidth(unitButton);
			float num2 = LayoutUtility.GetPreferredHeight(unitButton);
			Rect rect;
			if (num <= 1f)
			{
				rect = unitButton.rect;
				num = ((Rect)(ref rect)).width;
			}
			if (num2 <= 1f)
			{
				rect = unitButton.rect;
				num2 = ((Rect)(ref rect)).height;
			}
			obj.preferredWidth = num;
			obj.preferredHeight = num2;
			obj.minWidth = num;
			obj.minHeight = num2;
			obj.flexibleWidth = 0f;
			obj.flexibleHeight = 0f;
			CreateCircleHighlight(component, unitButton, num, num2);
			return component;
		}

		internal static void Destroy(RectTransform gap)
		{
			if ((Object)(object)gap != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)gap).gameObject);
			}
		}

		private static void CreateCircleHighlight(RectTransform gapRect, RectTransform unitButton, float width, float height)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			UnitButtonBase component = ((Component)unitButton).GetComponent<UnitButtonBase>();
			Image val = component?.NameSelect;
			float num = Mathf.Min(width, height);
			GameObject val2 = new GameObject("Highlight", new Type[1] { typeof(RectTransform) });
			RectTransform component2 = val2.GetComponent<RectTransform>();
			((Transform)component2).SetParent((Transform)(object)gapRect, false);
			component2.anchorMin = new Vector2(0.5f, 0.5f);
			component2.anchorMax = new Vector2(0.5f, 0.5f);
			component2.pivot = new Vector2(0.5f, 0.5f);
			component2.sizeDelta = new Vector2(num, num);
			component2.anchoredPosition = Vector2.zero;
			Image val3 = val2.AddComponent<Image>();
			((Graphic)val3).raycastTarget = false;
			val3.preserveAspect = true;
			((Graphic)val3).color = new Color(1f, 1f, 1f, 0.38f);
			if ((Object)(object)val != (Object)null && (Object)(object)val.sprite != (Object)null)
			{
				val3.sprite = val.sprite;
				val3.type = val.type;
			}
			else if ((Object)(object)component?.IconImage != (Object)null && (Object)(object)component.IconImage.sprite != (Object)null)
			{
				val3.sprite = component.IconImage.sprite;
			}
		}
	}
	internal static class FactionCreatorPatches
	{
		public static void AddNewUnit_Postfix(FactionCreatorManager __instance)
		{
			if (!((Object)(object)__instance?.FactionListParent == (Object)null) && __instance.FactionListParent.childCount != 0)
			{
				FactionCreatorReorderLogic.AttachDragHandle(((Component)__instance.FactionListParent.GetChild(__instance.FactionListParent.childCount - 1)).GetComponent<UnitButtonBase>(), __instance);
			}
		}

		public static void LoadFaction_Postfix(FactionCreatorManager __instance)
		{
			FactionCreatorReorderLogic.RefreshAllDragHandles(__instance);
		}

		public static void SaveNewFaction_Prefix(FactionCreatorManager __instance)
		{
			FactionCreatorReorderLogic.SyncAddedUnitsFromHierarchy(__instance);
		}

		public static void GetFactionUnits_Prefix(FactionCreatorManager __instance)
		{
			FactionCreatorReorderLogic.SyncAddedUnitsFromHierarchy(__instance);
		}

		public static bool UnitButtonFactionCreator_OnClick_Prefix(UnitButtonFactionCreator __instance)
		{
			FactionCreatorUnitDragReorder component = ((Component)__instance).GetComponent<FactionCreatorUnitDragReorder>();
			if (!((Object)(object)component == (Object)null))
			{
				return !component.ConsumeClickSuppression();
			}
			return true;
		}

		public static void UnitButtonBase_OnPointerEnter_Postfix(UnitButtonBase __instance)
		{
			FactionCreatorUnitCostHover.ShowOnHover(__instance);
		}

		public static void UnitButtonBase_OnPointerExit_Postfix(UnitButtonBase __instance)
		{
			FactionCreatorUnitCostHover.HideOnHover(__instance);
		}

		public static void UnitButtonBase_OnSelect_Postfix(UnitButtonBase __instance)
		{
			FactionCreatorUnitCostHover.ShowOnHover(__instance);
		}

		public static void UnitButtonBase_OnDeselect_Postfix(UnitButtonBase __instance)
		{
			FactionCreatorUnitCostHover.HideOnHover(__instance);
		}
	}
	internal static class FactionCreatorReorderLogic
	{
		private static readonly FieldInfo AddedUnitsField = AccessTools.Field(typeof(FactionCreatorManager), "addedUnits");

		private static FieldInfo _spawnedButtonField;

		internal static void AttachDragHandle(UnitButtonBase button, FactionCreatorManager manager)
		{
			if (!((Object)(object)button == (Object)null) && !((Object)(object)manager == (Object)null) && !((Object)(object)((Component)button).GetComponent<FactionCreatorUnitDragReorder>() != (Object)null))
			{
				((Component)button).gameObject.AddComponent<FactionCreatorUnitDragReorder>().Initialize(manager, button);
			}
		}

		internal static void RefreshAllDragHandles(FactionCreatorManager manager)
		{
			if ((Object)(object)manager?.FactionListParent == (Object)null)
			{
				return;
			}
			for (int i = 0; i < manager.FactionListParent.childCount; i++)
			{
				UnitButtonBase component = ((Component)manager.FactionListParent.GetChild(i)).GetComponent<UnitButtonBase>();
				if ((Object)(object)component != (Object)null)
				{
					AttachDragHandle(component, manager);
				}
			}
		}

		internal static int GetUnitIndex(FactionCreatorManager manager, UnitButtonBase button)
		{
			IList addedUnits = GetAddedUnits(manager);
			if (addedUnits == null || (Object)(object)button == (Object)null)
			{
				return -1;
			}
			for (int i = 0; i < addedUnits.Count; i++)
			{
				if ((Object)(object)GetSpawnedButton(addedUnits[i]) == (Object)(object)button)
				{
					return i;
				}
			}
			return -1;
		}

		internal static void SyncAddedUnitsFromHierarchy(FactionCreatorManager manager)
		{
			IList addedUnits = GetAddedUnits(manager);
			Transform val = manager?.FactionListParent;
			if (addedUnits == null || (Object)(object)val == (Object)null || addedUnits.Count == 0)
			{
				return;
			}
			Dictionary<UnitButtonBase, object> dictionary = new Dictionary<UnitButtonBase, object>();
			for (int i = 0; i < addedUnits.Count; i++)
			{
				UnitButtonBase spawnedButton = GetSpawnedButton(addedUnits[i]);
				if ((Object)(object)spawnedButton != (Object)null && !dictionary.ContainsKey(spawnedButton))
				{
					dictionary[spawnedButton] = addedUnits[i];
				}
			}
			List<object> list = new List<object>();
			for (int j = 0; j < val.childCount; j++)
			{
				UnitButtonBase component = ((Component)val.GetChild(j)).GetComponent<UnitButtonBase>();
				if ((Object)(object)component != (Object)null && dictionary.TryGetValue(component, out var value))
				{
					list.Add(value);
				}
			}
			if (list.Count == addedUnits.Count)
			{
				addedUnits.Clear();
				for (int k = 0; k < list.Count; k++)
				{
					addedUnits.Add(list[k]);
				}
			}
		}

		internal static ScrollRect FindListScrollRect(FactionCreatorManager manager)
		{
			if (!((Object)(object)manager?.FactionListParent != (Object)null))
			{
				return null;
			}
			return ((Component)manager.FactionListParent).GetComponentInParent<ScrollRect>();
		}

		internal static bool IsHorizontalLayout(RectTransform listParent)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)listParent != (Object)null)
			{
				Rect rect = listParent.rect;
				float width = ((Rect)(ref rect)).width;
				rect = listParent.rect;
				return width >= ((Rect)(ref rect)).height;
			}
			return false;
		}

		internal static void UpdateDragScroll(ScrollRect scrollRect, Vector2 screenPosition, Camera eventCamera)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)scrollRect == (Object)null)
			{
				return;
			}
			RectTransform val = (RectTransform)(((Object)(object)scrollRect.viewport != (Object)null) ? ((object)scrollRect.viewport) : ((object)/*isinst with value type is only supported in some contexts*/));
			Vector2 val2 = default(Vector2);
			if ((Object)(object)val == (Object)null || !RectTransformUtility.ScreenPointToLocalPointInRectangle(val, screenPosition, eventCamera, ref val2))
			{
				return;
			}
			Rect rect = val.rect;
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			if (scrollRect.horizontal)
			{
				float num = val2.x - ((Rect)(ref rect)).xMin;
				float num2 = ((Rect)(ref rect)).xMax - val2.x;
				float num3 = 0f;
				if (num < 72f)
				{
					num3 = (0f - Mathf.InverseLerp(72f, 0f, num)) * 2.5f * unscaledDeltaTime;
				}
				else if (num2 < 72f)
				{
					num3 = Mathf.InverseLerp(72f, 0f, num2) * 2.5f * unscaledDeltaTime;
				}
				if (Mathf.Abs(num3) > 0.0001f)
				{
					scrollRect.horizontalNormalizedPosition = Mathf.Clamp01(scrollRect.horizontalNormalizedPosition + num3);
				}
			}
			if (scrollRect.vertical)
			{
				float num4 = val2.y - ((Rect)(ref rect)).yMin;
				float num5 = ((Rect)(ref rect)).yMax - val2.y;
				float num6 = 0f;
				if (num4 < 72f)
				{
					num6 = (0f - Mathf.InverseLerp(72f, 0f, num4)) * 2.5f * unscaledDeltaTime;
				}
				else if (num5 < 72f)
				{
					num6 = Mathf.InverseLerp(72f, 0f, num5) * 2.5f * unscaledDeltaTime;
				}
				if (Mathf.Abs(num6) > 0.0001f)
				{
					scrollRect.verticalNormalizedPosition = Mathf.Clamp01(scrollRect.verticalNormalizedPosition + num6);
				}
			}
		}

		internal static int GetInsertionIndex(FactionCreatorManager manager, Vector2 screenPosition, Camera camera, Transform ignore, int currentIndex = -1)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or