Decompiled source of H3TVR v2.0.0

H3TVR.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.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
using UnityEngine.UI;
using Valve.VR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace H3TVR
{
	public class AirdropManager : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass7_0
		{
			public GameObject crateGO;

			internal bool <AirdropSequence>b__0()
			{
				//IL_0019: 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)
				return (Object)(object)crateGO == (Object)null || crateGO.transform.position.y < ((Component)GM.CurrentPlayerBody).transform.position.y + 2f;
			}
		}

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

			private object <>2__current;

			public AirdropManager <>4__this;

			private <>c__DisplayClass7_0 <>8__1;

			private Vector3 <spawnPos>5__2;

			private FVRObject <crateTemplate>5__3;

			private Rigidbody <rb>5__4;

			private bool <isHelpful>5__5;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<crateTemplate>5__3 = null;
				<rb>5__4 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0067: 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_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0180: Unknown result type (might be due to invalid IL or missing references)
				//IL_018a: Expected O, but got Unknown
				//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass7_0();
					if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
					{
						ManualLogSource logger2 = <>4__this.logger;
						if (logger2 != null)
						{
							logger2.LogError((object)"Cannot start airdrop: Player body not found.");
						}
						return false;
					}
					<spawnPos>5__2 = ((Component)GM.CurrentPlayerBody).transform.position + Vector3.up * 40f;
					if (!IM.OD.ContainsKey("Crate_Wood_1"))
					{
						ManualLogSource logger3 = <>4__this.logger;
						if (logger3 != null)
						{
							logger3.LogError((object)"Cannot start airdrop: Crate template 'Crate_Wood_1' not found.");
						}
						return false;
					}
					<crateTemplate>5__3 = IM.OD["Crate_Wood_1"];
					<>8__1.crateGO = Object.Instantiate<GameObject>(((AnvilAsset)<crateTemplate>5__3).GetGameObject(), <spawnPos>5__2, Quaternion.identity);
					<rb>5__4 = <>8__1.crateGO.GetComponent<Rigidbody>();
					if ((Object)(object)<rb>5__4 == (Object)null)
					{
						ManualLogSource logger4 = <>4__this.logger;
						if (logger4 != null)
						{
							logger4.LogError((object)"Airdrop crate has no Rigidbody!");
						}
						Object.Destroy((Object)(object)<>8__1.crateGO);
						return false;
					}
					<rb>5__4.drag = 0.2f;
					<isHelpful>5__5 = Random.value < 0.7f;
					<>2__current = (object)new WaitUntil((Func<bool>)(() => (Object)(object)<>8__1.crateGO == (Object)null || <>8__1.crateGO.transform.position.y < ((Component)GM.CurrentPlayerBody).transform.position.y + 2f));
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)<>8__1.crateGO != (Object)null)
					{
						<>4__this.PopulateCrate(<>8__1.crateGO.transform.position, <isHelpful>5__5);
						<>8__1.crateGO.SendMessage("Damage", (object)1000f, (SendMessageOptions)1);
						ManualLogSource logger = <>4__this.logger;
						if (logger != null)
						{
							logger.LogInfo((object)"Airdrop has landed!");
						}
					}
					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();
			}
		}

		private H3TVRImproved plugin;

		private ManualLogSource logger;

		private const string CrateId = "Crate_Wood_1";

		private const float SpawnHeight = 40f;

		private const float ParachuteSlowdown = 0.2f;

		public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource)
		{
			plugin = pluginInstance;
			logger = logSource;
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)"Airdrop Manager initialized.");
			}
		}

		public void CallAirdrop(string username)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)("Airdrop called in by " + username + "!"));
			}
			((MonoBehaviour)this).StartCoroutine(AirdropSequence());
		}

		private IEnumerator AirdropSequence()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <AirdropSequence>d__7(0)
			{
				<>4__this = this
			};
		}

		private void PopulateCrate(Vector3 position, bool isHelpful)
		{
			//IL_0068: 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_002c: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (isHelpful)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)"Airdrop is... HELPFUL!");
				}
				SpawnRandomHelpfulItem(position);
				SpawnItem("Health_Sausage", position + Vector3.up * 0.1f);
			}
			else
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogInfo((object)"Airdrop is... a TROLL!");
				}
				SpawnItem("PinnedGrenadeM67", position);
			}
		}

		private void SpawnRandomHelpfulItem(Vector3 position)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			string[] array = new string[3] { "MeatBatBaseball", "Health_Sausage", "SuppressorBottle" };
			string itemId = array[Random.Range(0, array.Length)];
			SpawnItem(itemId, position);
		}

		private void SpawnItem(string itemId, Vector3 position)
		{
			//IL_0024: 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)
			try
			{
				if (IM.OD.ContainsKey(itemId))
				{
					FVRObject val = IM.OD[itemId];
					Object.Instantiate<GameObject>(((AnvilAsset)val).GetGameObject(), position, Quaternion.identity);
					return;
				}
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)("Item '" + itemId + "' not found in ObjectDictionary"));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Failed to spawn item '" + itemId + "': " + ex.Message));
				}
			}
		}
	}
	public class SosigBehaviorController
	{
		private ManualLogSource logger;

		private static readonly LayerMask EnvironmentMask = LayerMask.op_Implicit(LayerMask.GetMask(new string[1] { "Environment" }));

		public float AllyFollowDistance { get; set; } = 5f;


		public float AllyMinDistance { get; set; } = 2f;


		public float AllyCombatRange { get; set; } = 15f;


		public float AllyDefendRadius { get; set; } = 10f;


		public bool AllyProtectPlayer { get; set; } = true;


		public bool AllyHoldFire { get; set; } = false;


		public void Initialize(ManualLogSource logSource)
		{
			logger = logSource;
		}

		public void SetupAllyBehavior(Sosig sosig)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				object obj;
				if (currentPlayerBody == null)
				{
					obj = null;
				}
				else
				{
					Transform head = currentPlayerBody.Head;
					obj = ((head != null) ? ((Component)head).transform : null);
				}
				if ((Object)obj == (Object)null)
				{
					return;
				}
				sosig.E.IFFCode = 0;
				sosig.SetIFF(0);
				if (sosig.Priority.IFFChart != null)
				{
					for (int i = 0; i < sosig.Priority.IFFChart.Length; i++)
					{
						sosig.Priority.IFFChart[i] = i != 0;
					}
				}
				Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position;
				float num = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f);
				float num2 = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f);
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(position.x + num, position.y, position.z + num2);
				sosig.CommandAssaultPoint(val);
				sosig.FallbackOrder = (SosigOrder)4;
				ConfigureAllyFireSafety(sosig);
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogInfo((object)"Ally sosig configured with IFF 0 (player-friendly)");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogError((object)("Ally behavior setup failed: " + ex.Message));
				}
			}
		}

		private void ConfigureAllyFireSafety(Sosig sosig)
		{
			try
			{
				sosig.Mustard = 1f;
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)("Fire safety config warning: " + ex.Message));
				}
			}
		}

		public void SetupEnemyBehavior(Sosig sosig)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)((currentPlayerBody != null) ? ((Component)currentPlayerBody).transform : null) == (Object)null)
				{
					return;
				}
				int num = 1;
				sosig.E.IFFCode = num;
				sosig.SetIFF(num);
				if (sosig.Priority.IFFChart != null)
				{
					for (int i = 0; i < sosig.Priority.IFFChart.Length; i++)
					{
						sosig.Priority.IFFChart[i] = i == 0;
					}
				}
				sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position);
				sosig.FallbackOrder = (SosigOrder)4;
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Enemy behavior setup failed: " + ex.Message));
				}
			}
		}

		public void UpdateAllyBehavior(Sosig sosig, float followDistance)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0073: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Invalid comparison between Unknown and I4
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Invalid comparison between Unknown and I4
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null)
			{
				return;
			}
			try
			{
				if (sosig.E.IFFCode != 0)
				{
					sosig.E.IFFCode = 0;
					sosig.SetIFF(0);
				}
				if (!sosig.m_isStunned)
				{
					Vector3 position = GM.CurrentPlayerBody.Head.position;
					float num = Vector3.Distance(position, ((Component)sosig).transform.position);
					float num2 = Vector3.Distance(position, sosig.m_assaultPoint);
					if (CheckForNearbyEnemies(sosig, AllyCombatRange) && AllyProtectPlayer)
					{
						if ((int)sosig.CurrentOrder != 2)
						{
							sosig.SetCurrentOrder((SosigOrder)2);
						}
					}
					else if (num2 > followDistance)
					{
						float num3 = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f);
						float num4 = (float)(Random.Range(0, 2) * 2 - 1) * Random.Range(0.75f, 2.5f);
						Vector3 val = default(Vector3);
						((Vector3)(ref val))..ctor(position.x + num3, position.y, position.z + num4);
						if (!Physics.Linecast(position, val, LayerMask.op_Implicit(EnvironmentMask)))
						{
							sosig.CommandAssaultPoint(val);
						}
					}
					else if (num < AllyMinDistance)
					{
						Vector3 val2 = ((Component)sosig).transform.position - position;
						Vector3 normalized = ((Vector3)(ref val2)).normalized;
						Vector3 val3 = ((Component)sosig).transform.position + normalized * 2f;
						sosig.CommandAssaultPoint(val3);
					}
				}
				if (sosig.Priority.HasFreshTarget() && (int)sosig.CurrentOrder == 3 && sosig.m_entityRecognition >= 0.65f && IsValidEnemyTarget(sosig))
				{
					sosig.SetCurrentOrder((SosigOrder)2);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)("Ally update warning: " + ex.Message));
				}
			}
		}

		private bool CheckForNearbyEnemies(Sosig allySosig, float range)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (allySosig.Priority.HasFreshTarget())
				{
					return true;
				}
				Sosig[] array = Object.FindObjectsOfType<Sosig>();
				Sosig[] array2 = array;
				foreach (Sosig val in array2)
				{
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)allySosig) && (int)val.BodyState != 3 && val.E.IFFCode != 0)
					{
						float num = Vector3.Distance(((Component)allySosig).transform.position, ((Component)val).transform.position);
						if (num <= range)
						{
							return true;
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)("Enemy check warning: " + ex.Message));
				}
			}
			return false;
		}

		private bool IsValidEnemyTarget(Sosig sosig)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if ((Object)(object)((currentPlayerBody != null) ? ((Component)currentPlayerBody).transform : null) == (Object)null)
				{
					return false;
				}
				Vector3 position = ((Component)GM.CurrentPlayerBody).transform.position;
				Vector3 position2 = ((Component)sosig).transform.position;
				if (sosig.Priority.HasFreshTarget())
				{
					return true;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogWarning((object)("Target validation warning: " + ex.Message));
				}
			}
			return false;
		}

		public void UpdateEnemyBehavior(Sosig sosig, float aggressionDistance)
		{
			//IL_0039: 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_0051: 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: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Invalid comparison between Unknown and I4
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Invalid comparison between Unknown and I4
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null)
			{
				return;
			}
			if (!sosig.m_isStunned)
			{
				Vector3 position = GM.CurrentPlayerBody.Head.position;
				float num = Vector3.Distance(position, ((Component)sosig.Links[1]).transform.position);
				if (num > aggressionDistance)
				{
					sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position);
				}
			}
			if (sosig.Priority.HasFreshTarget() && (int)sosig.CurrentOrder == 3 && sosig.m_entityRecognition >= 0.55f)
			{
				sosig.SetCurrentOrder((SosigOrder)2);
			}
			if ((int)sosig.CurrentOrder == 0 || (int)sosig.CurrentOrder == 9 || (int)sosig.CurrentOrder == 1)
			{
				sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position);
			}
		}

		public void SetAlliesHoldFire(bool holdFire)
		{
			AllyHoldFire = holdFire;
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)$"Allies hold fire: {holdFire}");
			}
		}

		public void CommandAlliesDefendPoint(Vector3 point)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				foreach (Sosig spawnedChatter in AdvancedChatSosigSpawner.spawnedChatters)
				{
					if ((Object)(object)spawnedChatter != (Object)null && (int)spawnedChatter.BodyState != 3)
					{
						spawnedChatter.CommandAssaultPoint(point);
						spawnedChatter.SetCurrentOrder((SosigOrder)1);
					}
				}
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)$"Allies commanded to defend point: {point}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Defend point command failed: " + ex.Message));
				}
			}
		}

		public void CommandAlliesFollowPlayer()
		{
			//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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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)
			try
			{
				if ((Object)(object)GM.CurrentPlayerBody?.Head == (Object)null)
				{
					return;
				}
				Vector3 position = GM.CurrentPlayerBody.Head.position;
				Vector3 val = default(Vector3);
				foreach (Sosig spawnedChatter in AdvancedChatSosigSpawner.spawnedChatters)
				{
					if ((Object)(object)spawnedChatter != (Object)null && (int)spawnedChatter.BodyState != 3)
					{
						float num = Random.Range(-2f, 2f);
						float num2 = Random.Range(-2f, 2f);
						((Vector3)(ref val))..ctor(position.x + num, position.y, position.z + num2);
						spawnedChatter.CommandAssaultPoint(val);
						spawnedChatter.FallbackOrder = (SosigOrder)4;
					}
				}
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)"Allies commanded to follow player");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Follow command failed: " + ex.Message));
				}
			}
		}

		public void CommandAlliesAttackTarget(Vector3 targetPosition)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				foreach (Sosig spawnedChatter in AdvancedChatSosigSpawner.spawnedChatters)
				{
					if ((Object)(object)spawnedChatter != (Object)null && (int)spawnedChatter.BodyState != 3)
					{
						spawnedChatter.CommandAssaultPoint(targetPosition);
						spawnedChatter.SetCurrentOrder((SosigOrder)7);
					}
				}
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)$"Allies commanded to attack: {targetPosition}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Attack command failed: " + ex.Message));
				}
			}
		}
	}
	public class SosigNameManager
	{
		private List<string> allyNames = new List<string>();

		private List<string> enemyNames = new List<string>();

		private ManualLogSource logger;

		public void Initialize(ManualLogSource logSource)
		{
			logger = logSource;
		}

		public void LoadNameLists(string allyPath, string enemyPath)
		{
			try
			{
				if (File.Exists(allyPath))
				{
					string[] array = File.ReadAllLines(allyPath);
					string[] array2 = array;
					foreach (string text in array2)
					{
						string text2 = text.Trim();
						if (!string.IsNullOrEmpty(text2) && !text2.StartsWith("#") && !text2.StartsWith(";"))
						{
							allyNames.Add(text2);
						}
					}
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogInfo((object)$"Loaded {allyNames.Count} ally names");
					}
				}
				else
				{
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogWarning((object)("Ally names file not found: " + allyPath));
					}
					CreateDefaultNameFile(allyPath, isAlly: true);
				}
				if (File.Exists(enemyPath))
				{
					string[] array3 = File.ReadAllLines(enemyPath);
					string[] array4 = array3;
					foreach (string text3 in array4)
					{
						string text4 = text3.Trim();
						if (!string.IsNullOrEmpty(text4) && !text4.StartsWith("#") && !text4.StartsWith(";"))
						{
							enemyNames.Add(text4);
						}
					}
					ManualLogSource obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogInfo((object)$"Loaded {enemyNames.Count} enemy names");
					}
				}
				else
				{
					ManualLogSource obj4 = logger;
					if (obj4 != null)
					{
						obj4.LogWarning((object)("Enemy names file not found: " + enemyPath));
					}
					CreateDefaultNameFile(enemyPath, isAlly: false);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj5 = logger;
				if (obj5 != null)
				{
					obj5.LogError((object)("Failed to load name lists: " + ex.Message));
				}
			}
		}

		private void CreateDefaultNameFile(string path, bool isAlly)
		{
			try
			{
				string directoryName = Path.GetDirectoryName(path);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				string[] array = ((!isAlly) ? new string[6] { "# Enemy Sosig Names", "Hostile Bot", "Attacker", "Enemy", "Threat", "Opponent" } : new string[6] { "# Ally Sosig Names", "Friendly Bot", "Guardian", "Protector", "Ally", "Helper" });
				File.WriteAllLines(path, array);
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)("Created default name file: " + path));
				}
				if (isAlly)
				{
					for (int i = 1; i < array.Length; i++)
					{
						allyNames.Add(array[i]);
					}
				}
				else
				{
					for (int j = 1; j < array.Length; j++)
					{
						enemyNames.Add(array[j]);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Failed to create default name file: " + ex.Message));
				}
			}
		}

		public string GetRandomName(bool isAlly, SteamFriendsIntegration steamFriends = null, bool useSteamFriends = false)
		{
			if ((Object)(object)steamFriends != (Object)null && steamFriends.IsAvailable() && useSteamFriends)
			{
				try
				{
					string randomFriendName = steamFriends.GetRandomFriendName();
					if (!string.IsNullOrEmpty(randomFriendName) && randomFriendName != "Steam Friend")
					{
						return randomFriendName;
					}
				}
				catch (Exception ex)
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogWarning((object)("Failed to get Steam friend name: " + ex.Message));
					}
				}
			}
			List<string> list = (isAlly ? allyNames : enemyNames);
			if (list.Count == 0)
			{
				return isAlly ? "Ally" : "Enemy";
			}
			return list[Random.Range(0, list.Count)];
		}
	}
	public class SosigNameplateManager
	{
		public void AttachNameplate(Sosig sosig, string name, GameObject nameplatePrefab, bool isEnemy)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (sosig.Links.Count != 0 && !((Object)(object)nameplatePrefab == (Object)null))
				{
					GameObject val = Object.Instantiate<GameObject>(nameplatePrefab, ((Component)sosig.Links[0]).transform, false);
					val.transform.localPosition = new Vector3(0f, 0.3f, 0f);
					val.transform.localRotation = Quaternion.identity;
					Text[] componentsInChildren = val.GetComponentsInChildren<Text>();
					Text[] array = componentsInChildren;
					foreach (Text val2 in array)
					{
						val2.text = name;
					}
				}
			}
			catch (Exception)
			{
			}
		}
	}
	public class SosigSpawnConfig
	{
		public ConfigEntry<int> maxAllySosigs;

		public ConfigEntry<int> maxEnemySosigs;

		public ConfigEntry<float> spawnCooldown;

		public ConfigEntry<bool> enableNameplates;

		public ConfigEntry<float> sosigLifetime;

		public ConfigEntry<bool> enableAutoCleanup;

		public ConfigEntry<float> enemyIFF;

		public ConfigEntry<float> followDistance;

		public ConfigEntry<float> enemyAggressionDistance;

		public ConfigEntry<bool> useModernSpawnSystem;

		public ConfigEntry<string> allySosigPool;

		public ConfigEntry<string> enemySosigPool;

		public ConfigEntry<bool> enableArmorCustomization;

		public ConfigEntry<string> allyNamesFilePath;

		public ConfigEntry<string> enemyNamesFilePath;

		public ConfigEntry<bool> useRandomNames;

		public ConfigEntry<int> maxSosigsPerUser;

		public ConfigEntry<bool> enableCoverAI;

		public ConfigEntry<float> sosigUpdateInterval;

		public ConfigEntry<bool> enableChatWatcherIntegration;

		public List<SosigEnemyID> allyPoolIDs = new List<SosigEnemyID>();

		public List<SosigEnemyID> enemyPoolIDs = new List<SosigEnemyID>();

		public SosigEnemyID defaultAllyID = (SosigEnemyID)100;

		public SosigEnemyID defaultEnemyID = (SosigEnemyID)108;

		private ManualLogSource logger;

		public void Initialize(ConfigFile config, ManualLogSource logSource)
		{
			logger = logSource;
			maxAllySosigs = config.Bind<int>("Chat Spawner", "MaxAllySosigs", 8, "Maximum ally sosigs");
			maxEnemySosigs = config.Bind<int>("Chat Spawner", "MaxEnemySosigs", 8, "Maximum enemy sosigs");
			spawnCooldown = config.Bind<float>("Chat Spawner", "SpawnCooldown", 2f, "Cooldown between spawns");
			enableNameplates = config.Bind<bool>("Chat Spawner", "EnableNameplates", true, "Show nameplates above sosigs");
			sosigLifetime = config.Bind<float>("Chat Spawner", "SosigLifetime", 300f, "Sosig lifetime in seconds (0 = infinite)");
			enableAutoCleanup = config.Bind<bool>("Chat Spawner", "EnableAutoCleanup", true, "Auto cleanup dead sosigs");
			enemyIFF = config.Bind<float>("Chat Spawner", "EnemyIFF", 1f, "Enemy IFF code");
			followDistance = config.Bind<float>("Chat Spawner", "FollowDistance", 6f, "Distance for allies to follow player");
			enemyAggressionDistance = config.Bind<float>("Chat Spawner", "EnemyAggressionDistance", 20f, "Distance at which enemies become aggressive");
			useModernSpawnSystem = config.Bind<bool>("Chat Spawner", "UseModernSpawnSystem", true, "Use Update 120's modern TNH sosig spawn system (recommended)");
			allySosigPool = config.Bind<string>("Chat Spawner", "AllySosigPool", "M_Swat_Scout,M_Swat_Sniper,M_Swat_Breacher", "Comma-separated list of SosigEnemyID names for allies");
			enemySosigPool = config.Bind<string>("Chat Spawner", "EnemySosigPool", "M_Swat_Heavy,M_Swat_Breacher,M_Swat_Sniper", "Comma-separated list of SosigEnemyID names for enemies");
			enableArmorCustomization = config.Bind<bool>("Chat Spawner Advanced", "EnableArmorCustomization", true, "Enable armor customization system");
			allyNamesFilePath = config.Bind<string>("Chat Spawner Advanced", "AllyNamesFilePath", "Plugins/H3TwitchTools/AllyNames.ini", "File path for ally names list (INI file)");
			enemyNamesFilePath = config.Bind<string>("Chat Spawner Advanced", "EnemyNamesFilePath", "Plugins/H3TwitchTools/EnemyNames.ini", "File path for enemy names list (INI file)");
			useRandomNames = config.Bind<bool>("Chat Spawner Advanced", "UseRandomNames", true, "Use random names from name lists");
			maxSosigsPerUser = config.Bind<int>("Chat Spawner Advanced", "MaxSosigsPerUser", 2, "Maximum sosigs per Twitch user");
			enableCoverAI = config.Bind<bool>("Chat Spawner Advanced", "EnableCoverAI", true, "Enable advanced cover-taking AI behavior");
			sosigUpdateInterval = config.Bind<float>("Chat Spawner Advanced", "UpdateInterval", 1f, "Interval between sosig AI updates (seconds)");
			enableChatWatcherIntegration = config.Bind<bool>("Chat Spawner Integration", "EnableChatWatcher", true, "Enable ChatWatcher integration for file-based Twitch chat spawning");
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)"Sosig spawn configuration initialized");
			}
		}

		public void InitializeSosigPools()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string[] array = allySosigPool.Value.Split(new char[1] { ',' });
				string[] array2 = array;
				foreach (string text in array2)
				{
					try
					{
						SosigEnemyID item = (SosigEnemyID)Enum.Parse(typeof(SosigEnemyID), text.Trim());
						allyPoolIDs.Add(item);
					}
					catch
					{
						ManualLogSource obj = logger;
						if (obj != null)
						{
							obj.LogWarning((object)("Invalid ally sosig ID: " + text));
						}
					}
				}
				string[] array3 = enemySosigPool.Value.Split(new char[1] { ',' });
				string[] array4 = array3;
				foreach (string text2 in array4)
				{
					try
					{
						SosigEnemyID item2 = (SosigEnemyID)Enum.Parse(typeof(SosigEnemyID), text2.Trim());
						enemyPoolIDs.Add(item2);
					}
					catch
					{
						ManualLogSource obj3 = logger;
						if (obj3 != null)
						{
							obj3.LogWarning((object)("Invalid enemy sosig ID: " + text2));
						}
					}
				}
				if (allyPoolIDs.Count == 0)
				{
					allyPoolIDs.Add((SosigEnemyID)100);
					allyPoolIDs.Add((SosigEnemyID)102);
				}
				if (enemyPoolIDs.Count == 0)
				{
					enemyPoolIDs.Add((SosigEnemyID)108);
					enemyPoolIDs.Add((SosigEnemyID)109);
				}
				ManualLogSource obj5 = logger;
				if (obj5 != null)
				{
					obj5.LogInfo((object)$"Loaded {allyPoolIDs.Count} ally sosig types, {enemyPoolIDs.Count} enemy sosig types");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj6 = logger;
				if (obj6 != null)
				{
					obj6.LogError((object)("Failed to initialize sosig pools: " + ex.Message));
				}
				allyPoolIDs.Add((SosigEnemyID)100);
				enemyPoolIDs.Add((SosigEnemyID)108);
			}
		}

		public SosigEnemyID GetRandomAllyID()
		{
			//IL_0033: 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_0014: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			if (allyPoolIDs.Count == 0)
			{
				return defaultAllyID;
			}
			return allyPoolIDs[Random.Range(0, allyPoolIDs.Count)];
		}

		public SosigEnemyID GetRandomEnemyID()
		{
			//IL_0033: 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_0014: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			if (enemyPoolIDs.Count == 0)
			{
				return defaultEnemyID;
			}
			return enemyPoolIDs[Random.Range(0, enemyPoolIDs.Count)];
		}
	}
	public class SosigSpawner
	{
		private ManualLogSource logger;

		private SosigTemplateCache templateCache;

		public void Initialize(ManualLogSource logSource, SosigTemplateCache cache)
		{
			logger = logSource;
			templateCache = cache;
		}

		public Sosig SpawnModern(SosigEnemyID enemyID, Vector3 pos, Quaternion rot, int IFF)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				SosigEnemyTemplate template = templateCache.GetTemplate(enemyID);
				if ((Object)(object)template == (Object)null)
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogError((object)$"Could not find template for SosigEnemyID: {enemyID}");
					}
					return null;
				}
				Sosig val = SpawnLegacy(template, pos, rot, IFF);
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogError((object)"Modern sosig spawn returned null");
					}
					return null;
				}
				try
				{
					if (template.ConfigTemplates != null && template.ConfigTemplates.Count > 0)
					{
						SosigConfigTemplate val2 = template.ConfigTemplates[Random.Range(0, template.ConfigTemplates.Count)];
						val.Configure(val2);
					}
				}
				catch (Exception ex)
				{
					ManualLogSource obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogWarning((object)("Failed to apply config template: " + ex.Message));
					}
				}
				int armorLevel = ((IFF == 0) ? SosigCustomizationUI.AllyArmor.Value : SosigCustomizationUI.EnemyArmor.Value);
				SosigArmorManager.ApplyArmorToSosig(val, armorLevel);
				val.E.IFFCode = IFF;
				val.SetIFF(IFF);
				try
				{
					val.Inventory.FillAllAmmo();
				}
				catch (Exception ex2)
				{
					ManualLogSource obj4 = logger;
					if (obj4 != null)
					{
						obj4.LogWarning((object)("Failed to fill ammo: " + ex2.Message));
					}
				}
				try
				{
					if (template.OutfitConfig != null && template.OutfitConfig.Count > 0)
					{
						ApplyOutfit(val, template.OutfitConfig[Random.Range(0, template.OutfitConfig.Count)]);
					}
				}
				catch (Exception ex3)
				{
					ManualLogSource obj5 = logger;
					if (obj5 != null)
					{
						obj5.LogWarning((object)("Failed to apply outfit: " + ex3.Message));
					}
				}
				return val;
			}
			catch (Exception ex4)
			{
				ManualLogSource obj6 = logger;
				if (obj6 != null)
				{
					obj6.LogError((object)("Modern sosig spawn failed: " + ex4.Message + "\n" + ex4.StackTrace));
				}
				return null;
			}
		}

		public Sosig SpawnLegacy(SosigEnemyTemplate template, Vector3 pos, Quaternion rot, int IFF)
		{
			//IL_00a5: 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_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)template == (Object)null || template.SosigPrefabs == null || template.SosigPrefabs.Count == 0)
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogError((object)"Invalid template");
					}
					return null;
				}
				FVRObject val = template.SosigPrefabs[Random.Range(0, template.SosigPrefabs.Count)];
				if ((Object)(object)((val != null) ? ((AnvilAsset)val).GetGameObject() : null) == (Object)null)
				{
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogError((object)"Invalid prefab");
					}
					return null;
				}
				GameObject val2 = Object.Instantiate<GameObject>(((AnvilAsset)val).GetGameObject(), pos, rot);
				Sosig componentInChildren = val2.GetComponentInChildren<Sosig>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					return null;
				}
				if (template.ConfigTemplates != null && template.ConfigTemplates.Count > 0)
				{
					SosigConfigTemplate val3 = template.ConfigTemplates[Random.Range(0, template.ConfigTemplates.Count)];
					if ((Object)(object)val3 != (Object)null)
					{
						componentInChildren.Configure(val3);
					}
				}
				componentInChildren.E.IFFCode = IFF;
				if (IFF < componentInChildren.Priority.IFFChart.Length)
				{
					componentInChildren.Priority.IFFChart[IFF] = true;
				}
				int armorLevel = ((IFF == 0) ? SosigCustomizationUI.AllyArmor.Value : SosigCustomizationUI.EnemyArmor.Value);
				SosigArmorManager.ApplyArmorToSosig(componentInChildren, armorLevel);
				EquipWeapons(componentInChildren, template, pos, rot);
				if (template.OutfitConfig != null && template.OutfitConfig.Count > 0)
				{
					ApplyOutfit(componentInChildren, template.OutfitConfig[Random.Range(0, template.OutfitConfig.Count)]);
				}
				return componentInChildren;
			}
			catch (Exception ex)
			{
				ManualLogSource obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogError((object)("Legacy sosig spawn failed: " + ex.Message));
				}
				return null;
			}
		}

		private void EquipWeapons(Sosig sosig, SosigEnemyTemplate template, Vector3 pos, Quaternion rot)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (!SosigCustomizationUI.EnableGuns.Value)
			{
				return;
			}
			try
			{
				if (template.WeaponOptions != null && template.WeaponOptions.Count > 0)
				{
					EquipWeapon(sosig, template.WeaponOptions[Random.Range(0, template.WeaponOptions.Count)], pos, rot);
				}
				if (template.WeaponOptions_Secondary != null && template.WeaponOptions_Secondary.Count > 0)
				{
					EquipWeapon(sosig, template.WeaponOptions_Secondary[Random.Range(0, template.WeaponOptions_Secondary.Count)], pos, rot);
				}
				if (template.WeaponOptions_Tertiary != null && template.WeaponOptions_Tertiary.Count > 0)
				{
					EquipWeapon(sosig, template.WeaponOptions_Tertiary[Random.Range(0, template.WeaponOptions_Tertiary.Count)], pos, rot);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Weapon equip failed: " + ex.Message));
				}
			}
		}

		private void EquipWeapon(Sosig sosig, FVRObject weaponObj, Vector3 pos, Quaternion rot)
		{
			//IL_0023: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)((weaponObj != null) ? ((AnvilAsset)weaponObj).GetGameObject() : null) == (Object)null)
				{
					return;
				}
				GameObject val = Object.Instantiate<GameObject>(((AnvilAsset)weaponObj).GetGameObject(), pos + Vector3.up * 0.1f, rot);
				SosigWeapon component = val.GetComponent<SosigWeapon>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetAutoDestroy(true);
					component.O.SpawnLockable = false;
					component.SetAmmoClamping(true);
					component.IsShakeReloadable = false;
					if ((int)component.Type == 0)
					{
						sosig.Inventory.FillAmmoWithType(component.AmmoType);
					}
					sosig.Inventory.Init();
					sosig.Inventory.FillAllAmmo();
					sosig.InitHands();
					sosig.ForceEquip(component);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Weapon equip error: " + ex.Message));
				}
			}
		}

		private void ApplyOutfit(Sosig sosig, SosigOutfitConfig outfit)
		{
			try
			{
				if (!((Object)(object)outfit == (Object)null) && sosig.Links.Count >= 4)
				{
					if (Random.value < outfit.Chance_Headwear)
					{
						SpawnAccessory(outfit.Headwear, sosig.Links[0]);
					}
					if (Random.value < outfit.Chance_Facewear)
					{
						SpawnAccessory(outfit.Facewear, sosig.Links[0]);
					}
					if (Random.value < outfit.Chance_Eyewear)
					{
						SpawnAccessory(outfit.Eyewear, sosig.Links[0]);
					}
					if (Random.value < outfit.Chance_Torsowear)
					{
						SpawnAccessory(outfit.Torsowear, sosig.Links[1]);
					}
					if (Random.value < outfit.Chance_Pantswear)
					{
						SpawnAccessory(outfit.Pantswear, sosig.Links[2]);
					}
					if (sosig.Links.Count > 3 && Random.value < outfit.Chance_Pantswear_Lower)
					{
						SpawnAccessory(outfit.Pantswear_Lower, sosig.Links[3]);
					}
					if (Random.value < outfit.Chance_Backpacks)
					{
						SpawnAccessory(outfit.Backpacks, sosig.Links[1]);
					}
					if (Random.value < outfit.Chance_TorosDecoration)
					{
						SpawnAccessory(outfit.TorosDecoration, sosig.Links[1]);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Outfit apply failed: " + ex.Message));
				}
			}
		}

		private void SpawnAccessory(List<FVRObject> accessories, SosigLink link)
		{
			//IL_005a: 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)
			if (accessories == null || accessories.Count == 0 || (Object)(object)link == (Object)null)
			{
				return;
			}
			try
			{
				FVRObject val = accessories[Random.Range(0, accessories.Count)];
				if (!((Object)(object)((val != null) ? ((AnvilAsset)val).GetGameObject() : null) == (Object)null))
				{
					GameObject val2 = Object.Instantiate<GameObject>(((AnvilAsset)val).GetGameObject(), ((Component)link).transform.position, ((Component)link).transform.rotation);
					val2.transform.SetParent(((Component)link).transform);
					SosigWearable component = val2.GetComponent<SosigWearable>();
					if ((Object)(object)component != (Object)null)
					{
						component.RegisterWearable(link);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Accessory spawn failed: " + ex.Message));
				}
			}
		}
	}
	public class SosigSpawnPositionCalculator
	{
		public Vector3 CalculateAllySpawnPoint()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_002d: 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)
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			object obj;
			if (currentPlayerBody == null)
			{
				obj = null;
			}
			else
			{
				Transform head = currentPlayerBody.Head;
				obj = ((head != null) ? ((Component)head).transform : null);
			}
			if ((Object)obj == (Object)null)
			{
				return Vector3.zero;
			}
			Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position;
			float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f);
			float num2 = Random.Range(2f, 4f);
			return new Vector3(position.x + Mathf.Cos(num) * num2, position.y, position.z + Mathf.Sin(num) * num2);
		}

		public Vector3 CalculateEnemySpawnPoint()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_002d: 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)
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			object obj;
			if (currentPlayerBody == null)
			{
				obj = null;
			}
			else
			{
				Transform head = currentPlayerBody.Head;
				obj = ((head != null) ? ((Component)head).transform : null);
			}
			if ((Object)obj == (Object)null)
			{
				return Vector3.zero;
			}
			Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position;
			float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f);
			float num2 = Random.Range(8f, 15f);
			return new Vector3(position.x + Mathf.Cos(num) * num2, position.y, position.z + Mathf.Sin(num) * num2);
		}

		public Vector3 CalculateBossSpawnPoint()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_002d: 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)
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			object obj;
			if (currentPlayerBody == null)
			{
				obj = null;
			}
			else
			{
				Transform head = currentPlayerBody.Head;
				obj = ((head != null) ? ((Component)head).transform : null);
			}
			if ((Object)obj == (Object)null)
			{
				return Vector3.zero;
			}
			Vector3 position = ((Component)GM.CurrentPlayerBody.Head).transform.position;
			float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f);
			float num2 = Random.Range(20f, 30f);
			return new Vector3(position.x + Mathf.Cos(num) * num2, position.y, position.z + Mathf.Sin(num) * num2);
		}
	}
	public class SosigTemplateCache
	{
		private Dictionary<SosigEnemyID, SosigEnemyTemplate> templateCache = new Dictionary<SosigEnemyID, SosigEnemyTemplate>();

		private ManualLogSource logger;

		public void Initialize(ManualLogSource logSource)
		{
			logger = logSource;
		}

		public void BuildCache(List<SosigEnemyID> allyPoolIDs, List<SosigEnemyID> enemyPoolIDs)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)ManagerSingleton<IM>.Instance == (Object)null)
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogWarning((object)"Cannot build template cache - IM.Instance is null");
					}
					return;
				}
				if (ManagerSingleton<IM>.Instance.odicSosigObjsByID == null)
				{
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogWarning((object)"Cannot build template cache - odicSosigObjsByID is null");
					}
					return;
				}
				int num = 0;
				ManualLogSource obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogInfo((object)"Building template cache from IM.Instance...");
				}
				foreach (SosigEnemyID item in allyPoolIDs.Concat(enemyPoolIDs).Distinct())
				{
					if (ManagerSingleton<IM>.Instance.odicSosigObjsByID.ContainsKey(item))
					{
						SosigEnemyTemplate val = ManagerSingleton<IM>.Instance.odicSosigObjsByID[item];
						if ((Object)(object)val != (Object)null)
						{
							templateCache[item] = val;
							num++;
							ManualLogSource obj4 = logger;
							if (obj4 != null)
							{
								obj4.LogDebug((object)$"  Cached: {item}");
							}
						}
						else
						{
							ManualLogSource obj5 = logger;
							if (obj5 != null)
							{
								obj5.LogWarning((object)$"  Template null for {item}");
							}
						}
					}
					else
					{
						ManualLogSource obj6 = logger;
						if (obj6 != null)
						{
							obj6.LogWarning((object)$"  ID not found in IM: {item}");
						}
					}
				}
				ManualLogSource obj7 = logger;
				if (obj7 != null)
				{
					obj7.LogInfo((object)$"Template cache built: {num}/{allyPoolIDs.Count + enemyPoolIDs.Count} templates loaded");
				}
				ManualLogSource obj8 = logger;
				if (obj8 != null)
				{
					obj8.LogInfo((object)$"Template cache status: {templateCache.Count} total templates");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj9 = logger;
				if (obj9 != null)
				{
					obj9.LogWarning((object)("Failed to build template cache: " + ex.Message));
				}
			}
		}

		public SosigEnemyTemplate GetTemplate(SosigEnemyID enemyID)
		{
			//IL_0007: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			if (templateCache.ContainsKey(enemyID))
			{
				return templateCache[enemyID];
			}
			if ((Object)(object)ManagerSingleton<IM>.Instance != (Object)null && ManagerSingleton<IM>.Instance.odicSosigObjsByID != null && ManagerSingleton<IM>.Instance.odicSosigObjsByID.ContainsKey(enemyID))
			{
				SosigEnemyTemplate val = ManagerSingleton<IM>.Instance.odicSosigObjsByID[enemyID];
				templateCache[enemyID] = val;
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)$"Cached template for {enemyID} from IM.Instance");
				}
				return val;
			}
			ManualLogSource obj2 = logger;
			if (obj2 != null)
			{
				obj2.LogWarning((object)$"Template not in cache for {enemyID}, searching Resources...");
			}
			SosigEnemyTemplate[] array = Resources.FindObjectsOfTypeAll<SosigEnemyTemplate>();
			SosigEnemyTemplate[] array2 = array;
			foreach (SosigEnemyTemplate val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null && val2.SosigEnemyID == enemyID)
				{
					templateCache[enemyID] = val2;
					ManualLogSource obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogInfo((object)$"Found and cached template for {enemyID}");
					}
					return val2;
				}
			}
			ManualLogSource obj4 = logger;
			if (obj4 != null)
			{
				obj4.LogError((object)$"Could not find template for SosigEnemyID: {enemyID}");
			}
			return null;
		}

		public bool HasTemplate(SosigEnemyID enemyID)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return templateCache.ContainsKey(enemyID);
		}

		public int GetCacheSize()
		{
			return templateCache.Count;
		}
	}
	public enum SpawnPriority
	{
		Low,
		Normal,
		High,
		Immediate
	}
	public class ChatWatcher : MonoBehaviour
	{
		private struct ParsedContentResult
		{
			public List<string> Usernames;

			public List<KeyValuePair<string, int>> ArmorCommands;

			public List<UserArmorCommand> UserArmorCommands;
		}

		private struct UserArmorCommand
		{
			public string Username;

			public int ArmorLevel;

			public string ArmorName;
		}

		public struct ChatWatcherStats
		{
			public bool FileWatchingActive;

			public int ProcessedUsernames;

			public int ActiveAllies;

			public int ActiveEnemies;

			public int TotalActiveSosigs;
		}

		private H3TVRImproved plugin;

		private ManualLogSource logger;

		private AdvancedChatSosigSpawner sosigSpawner;

		private ConfigEntry<bool> enableFileWatching;

		private ConfigEntry<string> allyChatFilePath;

		private ConfigEntry<string> enemyChatFilePath;

		private ConfigEntry<float> fileCheckInterval;

		private ConfigEntry<bool> clearFileAfterRead;

		private ConfigEntry<KeyCode> manualAllySpawnKey;

		private ConfigEntry<KeyCode> manualEnemySpawnKey;

		private ConfigEntry<KeyCode> clearAllSosigsKey;

		private float lastFileCheckTime;

		private string lastAllyFileContent = "";

		private string lastEnemyFileContent = "";

		private HashSet<string> processedUsernames = new HashSet<string>();

		public static ChatWatcher Instance { get; private set; }

		public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource, AdvancedChatSosigSpawner spawner)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			plugin = pluginInstance;
			logger = logSource;
			sosigSpawner = spawner;
			InitializeConfiguration();
			if (enableFileWatching.Value)
			{
				InitializeFileWatching();
			}
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)"Chat Watcher initialized (H3TwitchTools compatible file mode - Channel Points ready)");
			}
		}

		private void InitializeConfiguration()
		{
			H3TVRImproved h3TVRImproved = plugin;
			if (((h3TVRImproved != null) ? ((BaseUnityPlugin)h3TVRImproved).Config : null) == null)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)"Plugin config is null");
				}
				return;
			}
			try
			{
				enableFileWatching = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Chat Watcher - File Mode", "EnableFileWatching", true, "Enable file watching mode for chat integration (H3TwitchTools style)");
				allyChatFilePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Chat Watcher - File Mode", "AllyChatFilePath", "BepInEx/config/H3TVR_AllyChat.txt", "Path to ally chat file\nSUPPORTED FORMATS:\n  - Plain username: ViewerName\n  - Key=Value: username=ViewerName\n  - Key=Value: user=ViewerName\n  - Key=Value: redeemer=ViewerName\nSUPPORTS ABSOLUTE PATHS: C:\\StreamFiles\\ally_chat.txt\nOr relative: BepInEx/config/H3TVR_AllyChat.txt");
				enemyChatFilePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Chat Watcher - File Mode", "EnemyChatFilePath", "BepInEx/config/H3TVR_EnemyChat.txt", "Path to enemy chat file\nSUPPORTED FORMATS:\n  - Plain username: ViewerName\n  - Key=Value: username=ViewerName\n  - Key=Value: user=ViewerName\n  - Key=Value: redeemer=ViewerName\nSUPPORTS ABSOLUTE PATHS: C:\\StreamFiles\\enemy_chat.txt\nOr relative: BepInEx/config/H3TVR_EnemyChat.txt");
				fileCheckInterval = ((BaseUnityPlugin)plugin).Config.Bind<float>("Chat Watcher - File Mode", "FileCheckInterval", 0.5f, "How often to check files for changes (seconds)");
				clearFileAfterRead = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Chat Watcher - File Mode", "ClearFileAfterRead", true, "Clear chat file after reading usernames (recommended for channel points)");
				manualAllySpawnKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Chat Watcher - Keys", "ManualAllySpawnKey", (KeyCode)112, "Key to manually spawn ally sosig");
				manualEnemySpawnKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Chat Watcher - Keys", "ManualEnemySpawnKey", (KeyCode)111, "Key to manually spawn enemy sosig");
				clearAllSosigsKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Chat Watcher - Keys", "ClearAllSosigsKey", (KeyCode)127, "Key to clear all chat sosigs");
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogInfo((object)"Chat Watcher configuration initialized (Channel Points format supported)");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogError((object)("Chat Watcher config init failed: " + ex.Message));
				}
			}
		}

		private void InitializeFileWatching()
		{
			try
			{
				string text = ResolveFilePath(allyChatFilePath.Value);
				CreateFileIfNotExists(text, isAlly: true);
				string text2 = ResolveFilePath(enemyChatFilePath.Value);
				CreateFileIfNotExists(text2, isAlly: false);
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)"File watching initialized (Channel Points ready)");
				}
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogInfo((object)("  Ally file: " + text));
				}
				ManualLogSource obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogInfo((object)("  Enemy file: " + text2));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj4 = logger;
				if (obj4 != null)
				{
					obj4.LogError((object)("File watching init failed: " + ex.Message));
				}
			}
		}

		private void CreateFileIfNotExists(string filePath, bool isAlly)
		{
			try
			{
				if (!File.Exists(filePath))
				{
					string directoryName = Path.GetDirectoryName(filePath);
					if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
					{
						Directory.CreateDirectory(directoryName);
					}
					string contents = "# H3TVR " + (isAlly ? "Ally" : "Enemy") + " Chat File (Channel Points Compatible)\n# SUPPORTED FORMATS:\n#   Plain username: ViewerName\n#   Key=Value: username=ViewerName\n#   Key=Value: user=ViewerName\n#   Key=Value: redeemer=ViewerName\n# File will be cleared after reading if ClearFileAfterRead is enabled\n# Perfect for Twitch Channel Points redemptions!\n";
					File.WriteAllText(filePath, contents);
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogInfo((object)("Created chat file: " + filePath));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Failed to create file " + filePath + ": " + ex.Message));
				}
			}
		}

		private void Update()
		{
			try
			{
				HandleManualInput();
				if (enableFileWatching.Value && Time.time - lastFileCheckTime >= fileCheckInterval.Value)
				{
					CheckChatFiles();
					lastFileCheckTime = Time.time;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Update loop error: " + ex.Message));
				}
			}
		}

		private void HandleManualInput()
		{
			//IL_0007: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(manualAllySpawnKey.Value))
			{
				SpawnManualAlly();
			}
			if (Input.GetKeyDown(manualEnemySpawnKey.Value))
			{
				SpawnManualEnemy();
			}
			if (Input.GetKeyDown(clearAllSosigsKey.Value))
			{
				ClearAllSosigs();
			}
		}

		private void SpawnManualAlly()
		{
			try
			{
				string text = "Player_" + Random.Range(1000, 9999);
				sosigSpawner?.SpawningSequence(text);
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)("Manually spawned ally: " + text));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Manual ally spawn failed: " + ex.Message));
				}
			}
		}

		private void SpawnManualEnemy()
		{
			try
			{
				string text = "Enemy_" + Random.Range(1000, 9999);
				sosigSpawner?.SpawningSequenceEnemy(1, text);
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)("Manually spawned enemy: " + text));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Manual enemy spawn failed: " + ex.Message));
				}
			}
		}

		private void ClearAllSosigs()
		{
			try
			{
				sosigSpawner?.ClearSosigs();
				processedUsernames.Clear();
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)"Cleared all chat sosigs");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Clear sosigs failed: " + ex.Message));
				}
			}
		}

		private void CheckChatFiles()
		{
			string text = ResolveFilePath(allyChatFilePath.Value);
			if (File.Exists(text))
			{
				ProcessChatFile(text, isAlly: true);
			}
			string text2 = ResolveFilePath(enemyChatFilePath.Value);
			if (File.Exists(text2))
			{
				ProcessChatFile(text2, isAlly: false);
			}
		}

		private void ProcessChatFile(string filePath, bool isAlly)
		{
			try
			{
				string text = File.ReadAllText(filePath);
				string text2 = (isAlly ? lastAllyFileContent : lastEnemyFileContent);
				if (text == text2)
				{
					return;
				}
				if (isAlly)
				{
					lastAllyFileContent = text;
				}
				else
				{
					lastEnemyFileContent = text;
				}
				if (string.IsNullOrEmpty(text) || text.Trim().Length == 0)
				{
					return;
				}
				ParsedContentResult parsedContentResult = ParseContent(text);
				if (parsedContentResult.ArmorCommands.Count > 0)
				{
					foreach (KeyValuePair<string, int> armorCommand in parsedContentResult.ArmorCommands)
					{
						if (armorCommand.Key == "ally_armor")
						{
							SosigCustomizationUI.AllyArmor.Value = armorCommand.Value;
							SosigArmorManager.SetGlobalDefaults(armorCommand.Value, SosigCustomizationUI.EnemyArmor.Value);
							ManualLogSource obj = logger;
							if (obj != null)
							{
								obj.LogInfo((object)("Set ally armor to " + SosigArmorManager.GetArmorName(armorCommand.Value)));
							}
						}
						else if (armorCommand.Key == "enemy_armor")
						{
							SosigCustomizationUI.EnemyArmor.Value = armorCommand.Value;
							SosigArmorManager.SetGlobalDefaults(SosigCustomizationUI.AllyArmor.Value, armorCommand.Value);
							ManualLogSource obj2 = logger;
							if (obj2 != null)
							{
								obj2.LogInfo((object)("Set enemy armor to " + SosigArmorManager.GetArmorName(armorCommand.Value)));
							}
						}
					}
				}
				foreach (UserArmorCommand userArmorCommand in parsedContentResult.UserArmorCommands)
				{
					if (!string.IsNullOrEmpty(userArmorCommand.Username))
					{
						SosigArmorManager.SetUserArmorPreference(userArmorCommand.Username, userArmorCommand.ArmorLevel);
						ManualLogSource obj3 = logger;
						if (obj3 != null)
						{
							obj3.LogInfo((object)("[ARMOR] " + userArmorCommand.Username + " set armor to " + userArmorCommand.ArmorName));
						}
						continue;
					}
					SosigCustomizationUI.SetAllyArmor(userArmorCommand.ArmorLevel);
					SosigCustomizationUI.SetEnemyArmor(userArmorCommand.ArmorLevel);
					SosigArmorManager.SetGlobalDefaults(userArmorCommand.ArmorLevel, userArmorCommand.ArmorLevel);
					ManualLogSource obj4 = logger;
					if (obj4 != null)
					{
						obj4.LogInfo((object)("[ARMOR] Global armor set to " + userArmorCommand.ArmorName));
					}
				}
				foreach (string username in parsedContentResult.Usernames)
				{
					if (processedUsernames.Contains(username))
					{
						continue;
					}
					if (isAlly)
					{
						sosigSpawner?.SpawningSequence(username);
						ManualLogSource obj5 = logger;
						if (obj5 != null)
						{
							obj5.LogInfo((object)("Channel Point: Spawned ally for " + username + " (Armor: " + SosigArmorManager.GetArmorName(SosigArmorManager.GetUserArmorPreference(username, isAlly: true)) + ")"));
						}
					}
					else
					{
						sosigSpawner?.SpawningSequenceEnemy(1, username);
						ManualLogSource obj6 = logger;
						if (obj6 != null)
						{
							obj6.LogInfo((object)("Channel Point: Spawned enemy for " + username + " (Armor: " + SosigArmorManager.GetArmorName(SosigArmorManager.GetUserArmorPreference(username, isAlly: false)) + ")"));
						}
					}
					processedUsernames.Add(username);
				}
				if (clearFileAfterRead.Value && (parsedContentResult.Usernames.Count > 0 || parsedContentResult.ArmorCommands.Count > 0))
				{
					ClearChatFile(filePath, isAlly);
				}
				if (processedUsernames.Count > 1000)
				{
					processedUsernames.Clear();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj7 = logger;
				if (obj7 != null)
				{
					obj7.LogError((object)("Failed to process chat file " + filePath + ": " + ex.Message));
				}
			}
		}

		private ParsedContentResult ParseContent(string content)
		{
			ParsedContentResult parsedContentResult = default(ParsedContentResult);
			parsedContentResult.Usernames = new List<string>();
			parsedContentResult.ArmorCommands = new List<KeyValuePair<string, int>>();
			parsedContentResult.UserArmorCommands = new List<UserArmorCommand>();
			ParsedContentResult result = parsedContentResult;
			try
			{
				string[] array = content.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array2 = array;
				foreach (string text in array2)
				{
					string text2 = text.Trim();
					if (string.IsNullOrEmpty(text2) || text2.StartsWith("#") || text2.StartsWith(";"))
					{
						continue;
					}
					if (TryParseUserArmorCommand(text2, out var cmd))
					{
						result.UserArmorCommands.Add(cmd);
						ManualLogSource obj = logger;
						if (obj != null)
						{
							obj.LogDebug((object)("User armor command: " + cmd.Username + " -> " + cmd.ArmorName));
						}
						continue;
					}
					if (TryParseArmorCommand(text2, out KeyValuePair<string, int> command))
					{
						result.ArmorCommands.Add(command);
						ManualLogSource obj2 = logger;
						if (obj2 != null)
						{
							obj2.LogDebug((object)$"Parsed armor command: '{command.Key}={command.Value}'");
						}
						continue;
					}
					if (TryParseAirdropCommand(text2, out string username))
					{
						plugin.GetAirdropManager()?.CallAirdrop(username);
						continue;
					}
					string text3 = ExtractUsername(text2);
					if (!string.IsNullOrEmpty(text3))
					{
						result.Usernames.Add(text3);
						ManualLogSource obj3 = logger;
						if (obj3 != null)
						{
							obj3.LogDebug((object)("Extracted username: '" + text3 + "' from line: '" + text2 + "'"));
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj4 = logger;
				if (obj4 != null)
				{
					obj4.LogError((object)("Failed to parse content: " + ex.Message));
				}
			}
			return result;
		}

		private bool TryParseUserArmorCommand(string line, out UserArmorCommand cmd)
		{
			cmd = default(UserArmorCommand);
			string text = line.ToLower();
			if (text.Contains(":!armor"))
			{
				int num = line.IndexOf(':');
				if (num > 0)
				{
					string username = line.Substring(0, num).Trim();
					string message = line.Substring(num + 1).Trim();
					if (SosigArmorManager.TryParseArmorCommand(message, username, out int armorLevel, out string armorName))
					{
						cmd = new UserArmorCommand
						{
							Username = username,
							ArmorLevel = armorLevel,
							ArmorName = armorName
						};
						return true;
					}
				}
			}
			if (text.StartsWith("!armor") && SosigArmorManager.TryParseArmorCommand(line, null, out int armorLevel2, out string armorName2))
			{
				cmd = new UserArmorCommand
				{
					Username = null,
					ArmorLevel = armorLevel2,
					ArmorName = armorName2
				};
				return true;
			}
			if (text.Contains("armor=") && (text.Contains("user=") || text.Contains("username=")))
			{
				string text2 = null;
				int level = 0;
				string[] array = line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
				string[] array2 = array;
				foreach (string text3 in array2)
				{
					if (text3.ToLower().StartsWith("user=") || text3.ToLower().StartsWith("username="))
					{
						text2 = text3.Substring(text3.IndexOf('=') + 1).Trim();
					}
					else if (text3.ToLower().StartsWith("armor="))
					{
						string value = text3.Substring(6).Trim();
						ParseArmorValue(value, out level);
					}
				}
				if (!string.IsNullOrEmpty(text2))
				{
					SosigArmorManager.SetUserArmorPreference(text2, level);
					cmd = new UserArmorCommand
					{
						Username = text2,
						ArmorLevel = level,
						ArmorName = SosigArmorManager.GetArmorName(level)
					};
					return true;
				}
			}
			return false;
		}

		private bool ParseArmorValue(string value, out int level)
		{
			level = 0;
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			if (int.TryParse(value, out level))
			{
				level = Mathf.Clamp(level, 0, 5);
				return true;
			}
			switch (value.ToLower())
			{
			case "none":
			case "off":
				level = 0;
				return true;
			case "light":
			case "l":
				level = 1;
				return true;
			case "medium":
			case "med":
			case "m":
				level = 2;
				return true;
			case "heavy":
			case "h":
				level = 3;
				return true;
			case "tank":
			case "juggernaut":
			case "jug":
			case "t":
				level = 4;
				return true;
			case "god":
			case "godmode":
			case "g":
				level = 5;
				return true;
			default:
				return false;
			}
		}

		private bool TryParseArmorCommand(string line, out KeyValuePair<string, int> command)
		{
			command = default(KeyValuePair<string, int>);
			if (!line.Contains("="))
			{
				return false;
			}
			string[] array = line.Split(new char[1] { '=' });
			if (array.Length < 2)
			{
				return false;
			}
			string text = array[0].Trim().ToLower();
			if ((text == "ally_armor" || text == "enemy_armor") && int.TryParse(array[1].Trim(), out var result))
			{
				command = new KeyValuePair<string, int>(text, Mathf.Clamp(result, 0, 5));
				return true;
			}
			return false;
		}

		private bool TryParseAirdropCommand(string line, out string username)
		{
			username = null;
			if (!line.Contains("="))
			{
				return false;
			}
			string[] array = line.Split(new char[1] { '=' });
			if (array.Length < 2)
			{
				return false;
			}
			string text = array[0].Trim().ToLower();
			if (text == "airdrop")
			{
				username = array[1].Trim();
				return true;
			}
			return false;
		}

		private List<string> ParseUsernames(string content)
		{
			return ParseContent(content).Usernames;
		}

		private string ExtractUsername(string line)
		{
			if (string.IsNullOrEmpty(line))
			{
				return null;
			}
			string text = line.Trim();
			if (text.Contains("="))
			{
				string[] array = text.Split(new char[1] { '=' });
				if (array.Length >= 2)
				{
					string text2 = array[0].Trim().ToLower();
					string text3 = array[1].Trim();
					switch (text2)
					{
					default:
						if (!(text2 == "name"))
						{
							break;
						}
						goto case "username";
					case "username":
					case "user":
					case "redeemer":
					{
						int num = text3.IndexOf('#');
						if (num > 0)
						{
							text3 = text3.Substring(0, num).Trim();
						}
						int num2 = text3.IndexOf(' ');
						if (num2 > 0)
						{
							text3 = text3.Substring(0, num2).Trim();
						}
						if (!string.IsNullOrEmpty(text3))
						{
							return text3;
						}
						break;
					}
					}
				}
			}
			if (text.Contains(" "))
			{
				string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
				if (array2.Length != 0)
				{
					string text4 = array2[0].Trim();
					if (!text4.StartsWith("[") && !text4.StartsWith("<") && !text4.EndsWith(":") && text4.Length > 0)
					{
						return text4;
					}
				}
			}
			if (text.Length > 0 && !text.StartsWith("[") && !text.StartsWith("<"))
			{
				return text;
			}
			return null;
		}

		private void ClearChatFile(string filePath, bool isAlly)
		{
			try
			{
				string contents = "# H3TVR " + (isAlly ? "Ally" : "Enemy") + " Chat File (Channel Points Compatible)\n# SUPPORTED FORMATS:\n#   Plain username: ViewerName\n#   Key=Value: username=ViewerName\n#   Key=Value: user=ViewerName\n#   Key=Value: redeemer=ViewerName\n";
				File.WriteAllText(filePath, contents);
				if (isAlly)
				{
					lastAllyFileContent = "";
				}
				else
				{
					lastEnemyFileContent = "";
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Failed to clear file " + filePath + ": " + ex.Message));
				}
			}
		}

		public void TriggerSpawn(string username, bool isAlly)
		{
			try
			{
				if (string.IsNullOrEmpty(username))
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogWarning((object)"Cannot spawn sosig - username is null or empty");
					}
					return;
				}
				if (isAlly)
				{
					sosigSpawner?.SpawningSequence(username);
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogInfo((object)("API trigger: Spawned ally for " + username));
					}
				}
				else
				{
					sosigSpawner?.SpawningSequenceEnemy(1, username);
					ManualLogSource obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogInfo((object)("API trigger: Spawned enemy for " + username));
					}
				}
				processedUsernames.Add(username);
			}
			catch (Exception ex)
			{
				ManualLogSource obj4 = logger;
				if (obj4 != null)
				{
					obj4.LogError((object)("API spawn trigger failed: " + ex.Message));
				}
			}
		}

		public ChatWatcherStats GetStats()
		{
			AdvancedChatSosigSpawner.SosigStats sosigStats = sosigSpawner?.GetStats() ?? default(AdvancedChatSosigSpawner.SosigStats);
			ChatWatcherStats result = default(ChatWatcherStats);
			result.FileWatchingActive = enableFileWatching.Value;
			result.ProcessedUsernames = processedUsernames.Count;
			result.ActiveAllies = sosigStats.Allies;
			result.ActiveEnemies = sosigStats.Enemies;
			result.TotalActiveSosigs = sosigStats.TotalActive;
			return result;
		}

		public void ClearCache()
		{
			processedUsernames.Clear();
			lastAllyFileContent = "";
			lastEnemyFileContent = "";
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)"Cleared chat watcher cache");
			}
		}

		private string ResolveFilePath(string configuredPath)
		{
			if (string.IsNullOrEmpty(configuredPath))
			{
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)plugin).Info.Location);
				string path = Path.Combine(directoryName, "..");
				string path2 = Path.Combine(path, "config");
				return Path.Combine(path2, "H3TVR_Chat.txt");
			}
			if (Path.IsPathRooted(configuredPath))
			{
				return configuredPath;
			}
			string directoryName2 = Path.GetDirectoryName(((BaseUnityPlugin)plugin).Info.Location);
			string text = Path.Combine(directoryName2, configuredPath);
			if (File.Exists(text))
			{
				return text;
			}
			string directoryName3 = Path.GetDirectoryName(directoryName2);
			string text2 = Path.Combine(directoryName3, configuredPath);
			if (File.Exists(text2))
			{
				return text2;
			}
			return text;
		}

		private void OnDestroy()
		{
			try
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogInfo((object)"Chat Watcher cleaned up");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Chat Watcher cleanup failed: " + ex.Message));
				}
			}
		}
	}
	[BepInPlugin("com.MrBeam.h3tvr", "H3TVR", "1.1.4")]
	[BepInProcess("h3vr.exe")]
	public class H3TVRImproved : BaseUnityPlugin
	{
		private enum EncryptionType
		{
			Unknown,
			Pattern,
			Sequence,
			Timed
		}

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

			private object <>2__current;

			public TNH_HoldPointSystemNode encryptionNode;

			public float delay;

			public H3TVRImproved <>4__this;

			private Exception <ex>5__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					try
					{
						if ((Object)(object)encryptionNode != (Object)null && (Object)(object)((Component)encryptionNode).gameObject != (Object)null && ((Component)encryptionNode).gameObject.activeSelf)
						{
							<>4__this.CompleteEncryptionNode(encryptionNode);
							((BaseUnityPlugin)<>4__this).Logger.LogDebug((object)$"[TNH] Auto-completed encryption after {delay}s delay");
						}
					}
					catch (Exception ex)
					{
						<ex>5__1 = ex;
						((BaseUnityPlugin)<>4__this).Logger.LogDebug((object)("[TNH] Error auto-completing encryption: " + <ex>5__1.Message));
					}
					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();
			}
		}

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

			private object <>2__current;

			public H3TVRImproved <>4__this;

			private MethodInfo <method>5__1;

			private Exception <ex>5__2;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<method>5__1 = null;
				<ex>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Expected O, but got Unknown
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(3f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Delayed armor system initialization completed");
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					if ((Object)(object)<>4__this.advancedChatSpawner != (Object)null)
					{
						((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Retrying template cache build after H3VR initialization...");
						<method>5__1 = ((object)<>4__this.advancedChatSpawner).GetType().GetMethod("BuildTemplateCache", BindingFlags.Instance | BindingFlags.NonPublic);
						if ((object)<method>5__1 != null)
						{
							try
							{
								<method>5__1.Invoke(<>4__this.advancedChatSpawner, null);
								((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Template cache rebuild completed");
							}
							catch (Exception ex)
							{
								<ex>5__2 = ex;
								((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("Template cache rebuild warning: " + <ex>5__2.Message));
							}
						}
						<method>5__1 = 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();
			}
		}

		private const float SlowdownFactor = 0.001f;

		private const float SlowdownLength = 6f;

		private const float ZeroGWaitTime = 6f;

		private const float RealisticFallTime = 1f;

		private const float MalfunctionBoostDuration = 120f;

		private const float ForcedMalfunctionChance = 0.75f;

		private string slomoStatus = "Off";

		private string zeroGStatus = "Off";

		private bool malfunctionBoostActive;

		private float malfunctionBoostEndTime;

		private float slomoRampStartTime;

		private float slomoRampStartValue;

		private bool isRamping;

		private ConfigEntry<float> maxSlomo;

		private ConfigEntry<float> slomoWaitTime;

		private ConfigEntry<float> slomoScaleSpeed;

		private ConfigEntry<float> slomoReturnSpeed;

		private ConfigEntry<bool> slomoVRControllerEnabled;

		private ConfigEntry<string> slomoVRButton;

		private ConfigEntry<bool> slomoAffectsMovement;

		private ConfigEntry<float> slomoMovementScale;

		private ConfigEntry<bool> slomoUseRampSpeed;

		private ConfigEntry<string> slomoRampCurve;

		private ConfigEntry<float> slomoRampDuration;

		private ConfigEntry<float> slomoReturnRampDuration;

		private ConfigEntry<bool> enableKillSlomo;

		private ConfigEntry<bool> slomoAffectsAudio;

		private ConfigEntry<float> slomoAudioPitchScale;

		private ConfigEntry<bool> slomoAudioPreservePitch;

		private ConfigEntry<bool> slomoAffectsAudioSpeed;

		private ConfigEntry<float> slomoAudioSpeedScale;

		private ConfigEntry<string> slomoAudioMode;

		private ConfigEntry<bool> useItemManagerForGunRandomization;

		private ConfigEntry<string> gunList;

		private ConfigEntry<string> magazineList;

		private ConfigEntry<float> shurikenScale;

		private ConfigEntry<int> shurikenMinCount;

		private ConfigEntry<int> shurikenMaxCount;

		private ConfigEntry<int> pillowMinCount;

		private ConfigEntry<int> pillowMaxCount;

		private ConfigEntry<bool> pillowGrenadeEnabled;

		private ConfigEntry<float> pillowGrenadeChance;

		private ConfigEntry<float> pillowGrenadeArmedChance;

		private ConfigEntry<bool> pillowZeroGravityEnabled;

		private ConfigEntry<float> pillowZeroGravityChance;

		private ConfigEntry<float> pillowZeroGravityDuration;

		private ConfigEntry<bool> pillowSlomoEnabled;

		private ConfigEntry<float> pillowSlomoChance;

		private ConfigEntry<float> pillowSlomoDuration;

		private ConfigEntry<int> dangerCloseMinCount;

		private ConfigEntry<int> dangerCloseMaxCount;

		private readonly Dictionary<string, ConfigEntry<KeyCode>> keyBindings = new Dictionary<string, ConfigEntry<KeyCode>>();

		private ConfigEntry<bool> enableTwitchChatSosigs;

		private ConfigEntry<bool> enableLegacyFileMode;

		private ConfigEntry<string> twitchChatFilePath;

		private ConfigEntry<string> twitchEnemyChatFilePath;

		private ConfigEntry<int> maxChatSosigs;

		private ConfigEntry<bool> enableSteamFriends;

		private ConfigEntry<bool> steamFriendsRandomNames;

		private ConfigEntry<float> steamFriendsRefreshInterval;

		private ConfigEntry<bool> enableInfiniteTokens;

		private ConfigEntry<bool> disableEncryptionNodes;

		private ConfigEntry<bool> disableAllEncryptions;

		private ConfigEntry<bool> disableEncryptionType1;

		private ConfigEntry<bool> disableEncryptionType2;

		private ConfigEntry<bool> disableEncryptionType3;

		private ConfigEntry<bool> autoCompleteEncryption;

		private ConfigEntry<float> encryptionCompletionDelay;

		private SlomoMovementController slomoMovementController;

		private readonly Hooks hooks = new Hooks();

		private InputHandler inputHandler;

		private SpawnManager spawnManager;

		private EffectsManager effectsManager;

		private WeaponManager weaponManager;

		private AudioManager audioManager;

		private AdvancedChatSosigSpawner advancedChatSpawner;

		private SosigArmorWristMenuIntegration sosigArmorWristMenu;

		private SteamFriendsIntegration steamFriendsIntegration;

		private SosigCustomizationUI sosigCustomizationUI;

		private AirdropManager airdropManager;

		private LioranBoardIntegration lioranBoardIntegration;

		private static Dictionary<AudioSource, float> originalAudioSpeeds = new Dictionary<AudioSource, float>();

		public H3TVRImproved()
		{
			hooks.Hook();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading H3TVR Enhanced Edition (Standalone Mode)");
		}

		private void Awake()
		{
			try
			{
				OptionalDependencyManager.Initialize(((BaseUnityPlugin)this).Logger);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR Enhanced Edition (Standalone Mode) is loading...");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 1: Initializing configuration...");
				InitializeConfiguration();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 2: Initializing optional dependencies...");
				InitializeOptionalDependencies();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3: Initializing components...");
				InitializeComponents();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3.5: Initializing UI...");
				InitializeUI();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 3.6: Initializing Airdrop Manager...");
				InitializeAirdropManager();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 4: Initializing Sosig Spawner...");
				InitializeSosigSpawner();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 5: Initializing SpawnManager...");
				if ((Object)(object)spawnManager != (Object)null && (Object)(object)advancedChatSpawner != (Object)null)
				{
					spawnManager.Initialize(this, ((BaseUnityPlugin)this).Logger, advancedChatSpawner, audioManager);
					((BaseUnityPlugin)this).Logger.LogInfo((object)"SpawnManager initialized successfully");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)$"Cannot initialize SpawnManager - spawnManager: {(Object)(object)spawnManager != (Object)null}, advancedChatSpawner: {(Object)(object)advancedChatSpawner != (Object)null}");
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6: Initializing Twitch integration...");
				InitializeTwitchIntegration();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6.5: Initializing Steam Friends integration...");
				InitializeSteamFriendsIntegration();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 6.6: Initializing LioranBoard 2 integration...");
				InitializeLioranBoardIntegration();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Step 7: Initializing wrist menu...");
				try
				{
					InitializeSosigArmorWristMenuIntegration();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Non-critical error in wrist menu integration: " + ex.Message));
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR Enhanced Edition loaded successfully!");
				((BaseUnityPlugin)this).Logger.LogInfo((object)OptionalDependencyManager.GetDependencyStatusReport());
				if (MeatyceiverIntegrationManager.IsIntegrationEnabled())
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Meatyceiver 2 Integration: ACTIVE");
					((BaseUnityPlugin)this).Logger.LogInfo((object)MeatyceiverIntegrationManager.GetTransformationStats());
				}
				if (enableTwitchChatSosigs != null && enableTwitchChatSosigs.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat Sosig System: ENABLED");
					((BaseUnityPlugin)this).Logger.LogInfo((object)"  - Standalone mode (no Twitch integration)");
					((BaseUnityPlugin)this).Logger.LogInfo((object)"  - Use keyboard: P (ally), O (enemy), Delete (clear)");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat Sosig System: DISABLED");
				}
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Error during H3TVR initialization: " + ex2.Message));
				((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex2.StackTrace));
				try
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Attempting fallback initialization...");
					InitializeConfiguration();
					((BaseUnityPlugin)this).Logger.LogInfo((object)"H3TVR running in fallback mode with basic functionality");
				}
				catch (Exception ex3)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Critical error - H3TVR cannot initialize: " + ex3.Message));
				}
			}
		}

		private void InitializeConfiguration()
		{
			maxSlomo = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "MaxSlowmoScale", 0.1f, "Maximum slomo scale (0.01 = 1% speed, 0.1 = 10% speed)");
			slomoWaitTime = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "WaitTime", 2f, "Time to wait at max slomo before returning to normal speed");
			slomoScaleSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "ScaleDownSpeed", 1f, "Speed at which time slows down (higher = faster transition)");
			slomoReturnSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "ReturnSpeed", 0.33f, "Speed at which time returns to normal (higher = faster return)");
			slomoVRControllerEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo", "VRControllerEnabled", true, "Enable VR controller button to trigger slomo");
			slomoVRButton = ((BaseUnityPlugin)this).Config.Bind<string>("Slomo", "VRButton", "LeftX", "VR button to trigger slomo");
			slomoAffectsMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo", "AffectsMovement", true, "Whether slomo affects player movement speed");
			slomoMovementScale = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo", "MovementScale", 0.3f, "Movement speed multiplier during slomo");
			slomoUseRampSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo.Ramp", "UseRampSpeed", true, "Enable smooth ramp speed transitions for slomo (more cinematic)");
			slomoRampCurve = ((BaseUnityPlugin)this).Config.Bind<string>("Slomo.Ramp", "RampCurve", "EaseInOut", "Curve type for slomo ramp: Linear, EaseIn, EaseOut, EaseInOut, Smooth, Cinematic");
			slomoRampDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo.Ramp", "RampDuration", 0.5f, "Duration in seconds for slomo to ramp down to max slow speed");
			slomoReturnRampDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Slomo.Ramp", "ReturnRampDuration", 0.8f, "Duration in seconds for slomo to ramp back to normal speed");
			enableKillSlomo = ((BaseUnityPlugin)this).Config.Bind<bool>("Slomo", "EnableKillSlomo", true, "Enable slow motion effect on enemy kill.");
			slomoAffectsAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "SlomoAffectsAudio", true, "Whether slomo affects audio pitch");
			slomoAudioPitchScale = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "SlomoAudioPitchScale", 1f, "Audio pitch multiplier during slomo (1.0 = normal pitch, 0.5 = half pitch)");
			slomoAudioPreservePitch = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "SlomoPreservePitch", false, "If true, audio pitch is preserved (no pitch change). If false, uses pitch scaling.");
			slomoAffectsAudioSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "SlomoAffectsAudioSpeed", false, "Whether slomo affects audio speed (time stretching)");
			slomoAudioSpeedScale = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "SlomoAudioSpeedScale", 1f, "Audio speed multiplier during slomo (1.0 = normal speed, 0.5 = half speed)");
			slomoAudioMode = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "SlomoAudioMode", "Both", "Audio adjustment mode during slomo: 'PitchOnly', 'SpeedOnly', 'Both', 'Independent'");
			useItemManagerForGunRandomization = ((BaseUnityPlugin)this).Config.Bind<bool>("GunRandomization", "UseItemManager", true, "Use ItemManager for gun randomization (includes all H3VR and modded guns). If false, uses GunList/MagazineList config files.");
			gunList = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GunList", "DefaultGunList", "List of guns");
			magazineList = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MagazineList", "DefaultMagazineList", "List of magazines");
			InitializeSpawnConfigurations();
			InitializeKeyBindings();
		}

		private void InitializeSpawnConfigurations()
		{
			shurikenScale = ((BaseUnityPlugin)this).Config.Bind<float>("Shuriken", "Scale", 1f, "Scale multiplier for spawned shuriken");
			shurikenMinCount = ((BaseUnityPlugin)this).Config.Bind<int>("Shuriken", "MinCount", 1, "Minimum number of shuriken to spawn");
			shurikenMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("Shuriken", "MaxCount", 3, "Maximum number of shuriken to spawn");
			pillowMinCount = ((BaseUnityPlugin)this).Config.Bind<int>("Pillow", "MinCount", 1, "Minimum number of pillows to spawn");
			pillowMaxCount = ((BaseUnityPlugin)this).Config.Bind<int>("Pillow", "MaxCount", 3, "Maximum number of pillows to spawn");
			pillowGrenadeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pillow", "GrenadeEnabled", true, "Enable pillow grenade effect");
			pillowGrenadeChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "GrenadeChance", 0.1f, "Chance for pillow to spawn grenade");
			pillowGrenadeArmedChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "GrenadeArmedChance", 0.3f, "Chance for pillow grenade to be armed");
			pillowZeroGravityEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pillow", "ZeroGEnabled", true, "Enable pillow zero gravity effect");
			pillowZeroGravityChance = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "ZeroGChance", 0.15f, "Chance for pillow to trigger zero gravity");
			pillowZeroGravityDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Pillow", "ZeroGDuration", 10f, "Duration of pillow zero gravity effect");
			pillowSlomoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Pillow", "SlomoEnabled", true, "Enable pillow slow motion effect");
			pillowSlomoChance =