Decompiled source of H3TVR v1.1.5

H3TVR.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
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 UnityEngine;
using UnityEngine.UI;
using Valve.Newtonsoft.Json;
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 AudioManager : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <CleanupAudioSource>d__104 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string sourceKey;

			public float delay;

			public AudioManager <>4__this;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>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;
					if (<>4__this.activeSources.ContainsKey(sourceKey))
					{
						if ((Object)(object)<>4__this.activeSources[sourceKey] != (Object)null && (Object)(object)((Component)<>4__this.activeSources[sourceKey]).gameObject != (Object)null)
						{
							Object.Destroy((Object)(object)((Component)<>4__this.activeSources[sourceKey]).gameObject);
						}
						<>4__this.activeSources.Remove(sourceKey);
					}
					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 <LoadAudioClipCoroutine>d__76 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string filePath;

			public string effectKey;

			public AudioManager <>4__this;

			private string <url>5__1;

			private WWW <www>5__2;

			private AudioClip <clip>5__3;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<url>5__1 = null;
				<www>5__2 = null;
				<clip>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Expected O, but got Unknown
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<url>5__1 = "file://" + filePath;
						<www>5__2 = new WWW(<url>5__1);
						<>1__state = -3;
						<>2__current = <www>5__2;
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -3;
						if (string.IsNullOrEmpty(<www>5__2.error))
						{
							<clip>5__3 = WWWAudioExtensions.GetAudioClip(<www>5__2, false, false, <>4__this.GetAudioType(filePath));
							if ((Object)(object)<clip>5__3 != (Object)null)
							{
								((Object)<clip>5__3).name = effectKey;
								<>4__this.audioClips[effectKey] = <clip>5__3;
								<>4__this.logger.LogDebug((object)("[AudioManager] Loaded: " + effectKey + " from " + filePath));
							}
							<clip>5__3 = null;
						}
						else
						{
							<>4__this.logger.LogWarning((object)("[AudioManager] Failed to load " + Path.GetFileName(filePath) + ": " + <www>5__2.error));
						}
						<>m__Finally1();
						<www>5__2 = null;
						return false;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<www>5__2 != null)
				{
					((IDisposable)<www>5__2).Dispose();
				}
			}

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

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

			private object <>2__current;

			public string filePath;

			public string effectKey;

			public AudioManager <>4__this;

			private string <url>5__1;

			private WWW <www>5__2;

			private AudioClip <clip>5__3;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<url>5__1 = null;
				<www>5__2 = null;
				<clip>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Expected O, but got Unknown
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<url>5__1 = "file://" + filePath;
						<www>5__2 = new WWW(<url>5__1);
						<>1__state = -3;
						<>2__current = <www>5__2;
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -3;
						if (string.IsNullOrEmpty(<www>5__2.error))
						{
							<clip>5__3 = WWWAudioExtensions.GetAudioClip(<www>5__2, false, false, <>4__this.GetAudioType(filePath));
							if ((Object)(object)<clip>5__3 != (Object)null)
							{
								((Object)<clip>5__3).name = effectKey;
								<>4__this.audioClips[effectKey] = <clip>5__3;
								<>4__this.effectNameToFile[effectKey] = filePath;
								<>4__this.logger.LogInfo((object)("[AudioManager] Loaded custom: " + effectKey));
							}
							<clip>5__3 = null;
						}
						<>m__Finally1();
						<www>5__2 = null;
						return false;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<www>5__2 != null)
				{
					((IDisposable)<www>5__2).Dispose();
				}
			}

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

		private const string AUDIO_FOLDER = "H3TVR_Audio";

		private const string AUDIO_PATHS_CONFIG = "H3TVR_AudioPaths.ini";

		private const float DEFAULT_VOLUME = 0.7f;

		private const float DEFAULT_PITCH = 1f;

		private const float SPATIAL_BLEND_2D = 0f;

		private const float SPATIAL_BLEND_3D = 1f;

		private const int CLEANUP_FRAME_THRESHOLD = 5;

		private const float SYNC_LOAD_TIMEOUT = 30f;

		private H3TVRImproved plugin;

		private ManualLogSource logger;

		private bool isInitialized = false;

		private string audioFolderPath;

		private string audioPathsConfigFile;

		private Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();

		private Dictionary<string, AudioSource> activeSources = new Dictionary<string, AudioSource>();

		private Dictionary<string, string> effectNameToFile = new Dictionary<string, string>();

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

		private ConfigEntry<bool> enableAudioEffects;

		private ConfigEntry<float> masterVolume;

		private ConfigEntry<float> effectsVolume;

		private ConfigEntry<float> weaponSoundsVolume;

		private ConfigEntry<float> ambientSoundsVolume;

		private ConfigEntry<bool> enableSpatialAudio;

		private ConfigEntry<bool> enable3DAudio;

		private ConfigEntry<float> maxAudioDistance;

		private ConfigEntry<int> maxSimultaneousSounds;

		private ConfigEntry<float> shurikenVolume;

		private ConfigEntry<float> hydrationVolume;

		private ConfigEntry<float> slomoVolume;

		private ConfigEntry<float> dangerCloseVolume;

		private ConfigEntry<float> skittySubGunVolume;

		private ConfigEntry<float> destroyQuickbeltVolume;

		private ConfigEntry<float> wondertoyVolume;

		private ConfigEntry<string> customAudioDirectory1;

		private ConfigEntry<string> customAudioDirectory2;

		private ConfigEntry<string> customAudioDirectory3;

		private ConfigEntry<string> shurikenThrowPath;

		private ConfigEntry<string> shurikenSpawnPath;

		private ConfigEntry<string> hydrationDrinkPath;

		private ConfigEntry<string> hydrationSpawnPath;

		private ConfigEntry<string> slomoStartPath;

		private ConfigEntry<string> slomoEndPath;

		private ConfigEntry<string> slomoActivePath;

		private ConfigEntry<string> dangerClosePath;

		private ConfigEntry<string> explosionPath;

		private ConfigEntry<string> gunSpawnPath;

		private ConfigEntry<string> destroyQuickbeltPath;

		private ConfigEntry<string> itemDestroyPath;

		private ConfigEntry<string> wondertoySpawnPath;

		private ConfigEntry<string> wondertoyActivatePath;

		private ConfigEntry<string> uiConfirmPath;

		private ConfigEntry<string> uiErrorPath;

		private ConfigEntry<string> systemReadyPath;

		private ConfigEntry<string> stovepipeJamPath;

		private ConfigEntry<string> stovepipeDoubleFeedPath;

		private ConfigEntry<string> stovepipeFailureToFeedPath;

		private ConfigEntry<string> stovepipeFailureToEjectPath;

		private ConfigEntry<string> stovepipeFailureToFirePath;

		private ConfigEntry<string> stovepipeHangFirePath;

		private ConfigEntry<string> stovepipeClearJamPath;

		private ConfigEntry<string> stovepipeCyclingPath;

		private ConfigEntry<string> stovepipeGenericPath;

		public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			if (isInitialized)
			{
				return;
			}
			plugin = pluginInstance;
			logger = logSource;
			try
			{
				SetupConfiguration();
				SetupAudioFolders();
				LoadCustomPathsConfig();
				LoadConfiguredPaths();
				ScanForAudioFiles();
				LoadAudioClips();
				isInitialized = true;
				logger.LogInfo((object)$"[AudioManager] Initialized - Found {effectNameToFile.Count} audio files across {audioSearchPaths.Count} locations");
				PlayEffect("system_ready", Vector3.zero, is3D: false);
			}
			catch (Exception ex)
			{
				logger.LogError((object)("[AudioManager] Init failed: " + ex.Message));
			}
		}

		private void SetupConfiguration()
		{
			enableAudioEffects = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Audio", "EnableAudioEffects", true, "Enable all audio effects");
			masterVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio", "MasterVolume", 1f, "Master volume (0.0-1.0)");
			effectsVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio", "EffectsVolume", 0.8f, "Effects volume (0.0-1.0)");
			weaponSoundsVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio", "WeaponSoundsVolume", 0.9f, "Weapon sounds volume (0.0-1.0)");
			ambientSoundsVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio", "AmbientSoundsVolume", 0.6f, "Ambient sounds volume (0.0-1.0)");
			enableSpatialAudio = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Audio", "EnableSpatialAudio", true, "Enable 3D positional audio");
			enable3DAudio = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Audio", "Enable3DAudio", true, "Enable full 3D audio processing");
			maxAudioDistance = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio", "MaxAudioDistance", 50f, "Max distance for 3D audio");
			maxSimultaneousSounds = ((BaseUnityPlugin)plugin).Config.Bind<int>("Audio", "MaxSimultaneousSounds", 10, "Max simultaneous sounds");
			shurikenVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "ShurikenVolume", 0.8f, "Shuriken sounds volume");
			hydrationVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "HydrationVolume", 0.7f, "Hydration sounds volume");
			slomoVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "SlomoVolume", 0.9f, "Slomo effects volume");
			dangerCloseVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "DangerCloseVolume", 1f, "Danger close volume");
			skittySubGunVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "SkittySubGunVolume", 0.8f, "Weapon spawn volume");
			destroyQuickbeltVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "DestroyQuickbeltVolume", 0.6f, "Destruction volume");
			wondertoyVolume = ((BaseUnityPlugin)plugin).Config.Bind<float>("Audio.Effects", "WondertoyVolume", 0.7f, "Wondertoy volume");
			customAudioDirectory1 = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.CustomPaths", "CustomDirectory1", "", "Additional audio directory (can be anywhere on your computer, e.g., C:\\My Sounds\\Game Audio)");
			customAudioDirectory2 = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.CustomPaths", "CustomDirectory2", "", "Additional audio directory (can be anywhere on your computer)");
			customAudioDirectory3 = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.CustomPaths", "CustomDirectory3", "", "Additional audio directory (can be anywhere on your computer)");
			shurikenThrowPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "ShurikenThrow", "", "Full path to shuriken throw sound (e.g., C:\\My Audio\\shuriken.wav). Leave empty for auto-detection.");
			shurikenSpawnPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "ShurikenSpawn", "", "Full path to shuriken spawn sound. Leave empty for auto-detection.");
			hydrationDrinkPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "HydrationDrink", "", "Full path to hydration drink sound. Leave empty for auto-detection.");
			hydrationSpawnPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "HydrationSpawn", "", "Full path to hydration spawn sound. Leave empty for auto-detection.");
			slomoStartPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "SlomoStart", "", "Full path to slomo start sound. Leave empty for auto-detection.");
			slomoEndPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "SlomoEnd", "", "Full path to slomo end sound. Leave empty for auto-detection.");
			slomoActivePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "SlomoActive", "", "Full path to slomo active loop sound. Leave empty for auto-detection.");
			dangerClosePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "DangerClose", "", "Full path to danger close sound. Leave empty for auto-detection.");
			explosionPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "Explosion", "", "Full path to explosion sound. Leave empty for auto-detection.");
			gunSpawnPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "GunSpawn", "", "Full path to gun spawn sound. Leave empty for auto-detection.");
			destroyQuickbeltPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "DestroyQuickbelt", "", "Full path to destroy quickbelt sound. Leave empty for auto-detection.");
			itemDestroyPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "ItemDestroy", "", "Full path to item destroy sound. Leave empty for auto-detection.");
			wondertoySpawnPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "WondertoySpawn", "", "Full path to wondertoy spawn sound. Leave empty for auto-detection.");
			wondertoyActivatePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "WondertoyActivate", "", "Full path to wondertoy activate sound. Leave empty for auto-detection.");
			uiConfirmPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "UIConfirm", "", "Full path to UI confirm sound. Leave empty for auto-detection.");
			uiErrorPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "UIError", "", "Full path to UI error sound. Leave empty for auto-detection.");
			systemReadyPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths", "SystemReady", "", "Full path to system ready sound. Leave empty for auto-detection.");
			stovepipeJamPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "WeaponJam", "", "Full path to weapon jam sound. Leave empty for auto-detection.");
			stovepipeDoubleFeedPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "DoubleFeed", "", "Full path to double feed sound. Leave empty for auto-detection.");
			stovepipeFailureToFeedPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "FailureToFeed", "", "Full path to failure to feed sound. Leave empty for auto-detection.");
			stovepipeFailureToEjectPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "FailureToEject", "", "Full path to failure to eject sound. Leave empty for auto-detection.");
			stovepipeFailureToFirePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "FailureToFire", "", "Full path to failure to fire sound. Leave empty for auto-detection.");
			stovepipeHangFirePath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "HangFire", "", "Full path to hang fire sound. Leave empty for auto-detection.");
			stovepipeClearJamPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "ClearJam", "", "Full path to clear jam sound. Leave empty for auto-detection.");
			stovepipeCyclingPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "Cycling", "", "Full path to cycling sound. Leave empty for auto-detection.");
			stovepipeGenericPath = ((BaseUnityPlugin)plugin).Config.Bind<string>("Audio.FilePaths.Stovepipe", "GenericMalfunction", "", "Full path to generic malfunction sound. Leave empty for auto-detection.");
		}

		private void LoadConfiguredPaths()
		{
			RegisterConfigPath("shuriken", shurikenThrowPath.Value);
			RegisterConfigPath("shuriken_spawn", shurikenSpawnPath.Value);
			RegisterConfigPath("hydration", hydrationDrinkPath.Value);
			RegisterConfigPath("hydration_spawn", hydrationSpawnPath.Value);
			RegisterConfigPath("slomo_start", slomoStartPath.Value);
			RegisterConfigPath("slomo_end", slomoEndPath.Value);
			RegisterConfigPath("slomo_active", slomoActivePath.Value);
			RegisterConfigPath("danger_close", dangerClosePath.Value);
			RegisterConfigPath("explosion", explosionPath.Value);
			RegisterConfigPath("gun_spawn", gunSpawnPath.Value);
			RegisterConfigPath("skitty_sub_gun", gunSpawnPath.Value);
			RegisterConfigPath("destroy_quickbelt", destroyQuickbeltPath.Value);
			RegisterConfigPath("item_destroy", itemDestroyPath.Value);
			RegisterConfigPath("wondertoy", wondertoySpawnPath.Value);
			RegisterConfigPath("wondertoy_activate", wondertoyActivatePath.Value);
			RegisterConfigPath("ui_confirm", uiConfirmPath.Value);
			RegisterConfigPath("ui_error", uiErrorPath.Value);
			RegisterConfigPath("system_ready", systemReadyPath.Value);
			RegisterConfigPath("stovepipe_jam", stovepipeJamPath.Value);
			RegisterConfigPath("stovepipe_malfunction", stovepipeJamPath.Value);
			RegisterConfigPath("stovepipe_double_feed", stovepipeDoubleFeedPath.Value);
			RegisterConfigPath("stovepipe_failure_to_feed", stovepipeFailureToFeedPath.Value);
			RegisterConfigPath("stovepipe_failure_to_eject", stovepipeFailureToEjectPath.Value);
			RegisterConfigPath("stovepipe_failure_to_fire", stovepipeFailureToFirePath.Value);
			RegisterConfigPath("stovepipe_hang_fire", stovepipeHangFirePath.Value);
			RegisterConfigPath("stovepipe_clear_jam", stovepipeClearJamPath.Value);
			RegisterConfigPath("stovepipe_cycling", stovepipeCyclingPath.Value);
			RegisterConfigPath("stovepipe_generic", stovepipeGenericPath.Value);
		}

		private void RegisterConfigPath(string effectKey, string filePath)
		{
			if (!string.IsNullOrEmpty(filePath))
			{
				if (File.Exists(filePath))
				{
					effectNameToFile[effectKey] = filePath;
					logger.LogInfo((object)("[AudioManager] Config path registered: " + effectKey + " -> " + filePath));
				}
				else
				{
					logger.LogWarning((object)("[AudioManager] Config path not found for " + effectKey + ": " + filePath));
				}
			}
		}

		private void SetupAudioFolders()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)plugin).Info.Location);
				audioFolderPath = Path.Combine(directoryName, "H3TVR_Audio");
				audioPathsConfigFile = Path.Combine(directoryName, "H3TVR_AudioPaths.ini");
				if (!Directory.Exists(audioFolderPath))
				{
					Directory.CreateDirectory(audioFolderPath);
					CreateReadme();
				}
				audioSearchPaths.Add(audioFolderPath);
				AddSubdirectoriesRecursive(audioFolderPath);
				AddCustomDirectories();
				logger.LogInfo((object)$"[AudioManager] Scanning {audioSearchPaths.Count} directories for audio files");
			}
			catch (Exception ex)
			{
				logger.LogError((object)("[AudioManager] Folder setup failed: " + ex.Message));
			}
		}

		private void AddCustomDirectories()
		{
			AddCustomDirectory(customAudioDirectory1.Value);
			AddCustomDirectory(customAudioDirectory2.Value);
			AddCustomDirectory(customAudioDirectory3.Value);
		}

		private void AddCustomDirectory(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return;
			}
			try
			{
				if (Directory.Exists(path))
				{
					if (!audioSearchPaths.Contains(path))
					{
						audioSearchPaths.Add(path);
						AddSubdirectoriesRecursive(path);
						logger.LogInfo((object)("[AudioManager] Added custom directory: " + path));
					}
				}
				else
				{
					logger.LogWarning((object)("[AudioManager] Custom directory not found: " + path));
				}
			}
			catch (Exception ex)
			{
				logger.LogWarning((object)("[AudioManager] Error adding custom directory " + path + ": " + ex.Message));
			}
		}

		private void AddSubdirectoriesRecursive(string directory)
		{
			try
			{
				string[] directories = Directory.GetDirectories(directory);
				string[] array = directories;
				foreach (string text in array)
				{
					if (!audioSearchPaths.Contains(text))
					{
						audioSearchPaths.Add(text);
					}
					AddSubdirectoriesRecursive(text);
				}
			}
			catch (Exception ex)
			{
				logger.LogWarning((object)("[AudioManager] Could not scan subdirectory: " + ex.Message));
			}
		}

		private void LoadCustomPathsConfig()
		{
			if (!File.Exists(audioPathsConfigFile))
			{
				CreatePathsConfigTemplate();
				return;
			}
			try
			{
				string[] array = File.ReadAllLines(audioPathsConfigFile);
				int num = 0;
				string[] array2 = array;
				foreach (string text in array2)
				{
					if (text == null || text.Trim().Length == 0 || text.TrimStart(new char[0]).StartsWith("#") || text.TrimStart(new char[0]).StartsWith(";"))
					{
						continue;
					}
					string[] array3 = text.Split(new char[1] { '=' }, 2);
					if (array3.Length != 2)
					{
						continue;
					}
					string text2 = array3[0].Trim();
					string text3 = array3[1].Trim();
					if (File.Exists(text3))
					{
						if (!effectNameToFile.ContainsKey(text2))
						{
							effectNameToFile[text2] = text3;
							num++;
							logger.LogDebug((object)("[AudioManager] INI path loaded: " + text2 + " -> " + text3));
						}
					}
					else
					{
						logger.LogWarning((object)("[AudioManager] File not found for " + text2 + ": " + text3));
					}
				}
				if (num > 0)
				{
					logger.LogInfo((object)$"[AudioManager] Loaded {num} custom audio paths from INI config");
				}
			}
			catch (Exception ex)
			{
				logger.LogError((object)("[AudioManager] Error loading custom paths config: " + ex.Message));
			}
		}

		private void CreatePathsConfigTemplate()
		{
			string contents = "# H3TVR Enhanced Edition - Custom Audio Paths Configuration\r\n# ============================================================\r\n# \r\n# NOTE: You can now configure audio paths directly in BepInEx config!\r\n# This INI file is still supported for backwards compatibility.\r\n# BepInEx config paths take priority over this file.\r\n#\r\n# Use this file to point to audio files ANYWHERE on your computer!\r\n# Format: effectName=C:\\Full\\Path\\To\\Your\\Audio\\File.wav\r\n#\r\n# Supported formats: .wav, .ogg, .mp3, .aif, .aiff\r\n#\r\n# EXAMPLES:\r\n# shuriken=C:\\Users\\YourName\\Music\\Sound Effects\\shuriken_throw.wav\r\n# slomo_start=D:\\Game Audio\\slomo_start.ogg\r\n# explosion=E:\\Downloads\\explosion.mp3\r\n#\r\n# Available effect names:\r\n# -----------------------\r\n# Shuriken: shuriken, shuriken_spawn\r\n# Hydration: hydration, hydration_spawn\r\n# Slomo: slomo_start, slomo_end, slomo_active\r\n# Danger Close: danger_close, explosion\r\n# Weapons: gun_spawn, skitty_sub_gun\r\n# Destruction: destroy_quickbelt, item_destroy\r\n# Wondertoy: wondertoy, wondertoy_activate\r\n# UI: ui_confirm, ui_error\r\n# System: system_ready\r\n# Stovepipe: stovepipe_jam, stovepipe_malfunction, stovepipe_double_feed,\r\n#            stovepipe_failure_to_feed, stovepipe_failure_to_eject,\r\n#            stovepipe_failure_to_fire, stovepipe_hang_fire,\r\n#            stovepipe_clear_jam, stovepipe_cycling, stovepipe_generic\r\n#\r\n# YOUR CUSTOM PATHS (uncomment and edit):\r\n# ========================================\r\n\r\n# shuriken=C:\\Path\\To\\Your\\shuriken_throw.wav\r\n# explosion=C:\\Path\\To\\Your\\explosion.wav\r\n# slomo_start=C:\\Path\\To\\Your\\slomo_start.ogg\r\n\r\n";
			try
			{
				File.WriteAllText(audioPathsConfigFile, contents);
				logger.LogInfo((object)("[AudioManager] Created custom paths config template: " + audioPathsConfigFile));
			}
			catch (Exception ex)
			{
				logger.LogWarning((object)("[AudioManager] Could not create paths config template: " + ex.Message));
			}
		}

		private void CreateReadme()
		{
			string contents = "H3TVR Enhanced Edition - Audio Files\r\n====================================\r\n\r\nULTIMATE FLEXIBILITY - Configure audio files DIRECTLY in BepInEx config!\r\n\r\nMETHOD 1: BepInEx Config (RECOMMENDED - easiest!)\r\n  Open BepInEx\\config\\com.h3tvr.improved.cfg\r\n  Find [Audio.FilePaths] section\r\n  Set full paths for each effect:\r\n    ShurikenThrow = C:\\My Sounds\\shuriken.wav\r\n    Explosion = D:\\Downloads\\boom.mp3\r\n\r\nMETHOD 2: Use H3TVR_AudioPaths.ini to point to files anywhere\r\n\r\nMETHOD 3: Place files in this folder (auto-detected by name)\r\n\r\nMETHOD 4: Add custom directories in BepInEx config\r\n\r\nSUPPORTED FORMATS: .wav, .ogg, .mp3, .aif, .aiff\r\n\r\nEFFECT FILE NAMES (case-insensitive, auto-detected):\r\n----------------------------------------------------\r\n\r\nSHURIKEN:\r\n  - shuriken_throw.*\r\n  - shuriken_spawn.*\r\n\r\nHYDRATION:\r\n  - hydration_drink.*\r\n  - hydration_spawn.*\r\n\r\nSLOMO:\r\n  - slomo_start.*\r\n  - slomo_end.*\r\n  - slomo_active.*\r\n\r\nDANGER CLOSE:\r\n  - danger_close.*\r\n  - explosion.*\r\n\r\nWEAPONS:\r\n  - gun_spawn.*\r\n\r\nDESTRUCTION:\r\n  - destroy_quickbelt.*\r\n  - item_destroy.*\r\n\r\nWONDERTOY:\r\n  - wondertoy_spawn.*\r\n  - wondertoy_activate.*\r\n\r\nUI SOUNDS:\r\n  - ui_confirm.*\r\n  - ui_error.*\r\n\r\nSYSTEM:\r\n  - system_ready.*\r\n\r\nSTOVEPIPE (weapon malfunctions):\r\n  - weapon_jam.*\r\n  - double_feed.*\r\n  - failure_to_feed.*\r\n  - failure_to_eject.*\r\n  - failure_to_fire.*\r\n  - hang_fire.*\r\n  - clear_jam.*\r\n  - cycling.*\r\n  - generic_malfunction.*\r\n\r\nPRIORITY ORDER:\r\n--------------\r\n1. BepInEx config paths (highest priority)\r\n2. H3TVR_AudioPaths.ini\r\n3. Auto-detected files in folders\r\n";
			try
			{
				File.WriteAllText(Path.Combine(audioFolderPath, "README.txt"), contents);
			}
			catch
			{
			}
		}

		private void ScanForAudioFiles()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "shuriken", "shuriken_throw" },
				{ "shuriken_spawn", "shuriken_spawn" },
				{ "hydration", "hydration_drink" },
				{ "hydration_spawn", "hydration_spawn" },
				{ "slomo_start", "slomo_start" },
				{ "slomo_end", "slomo_end" },
				{ "slomo_active", "slomo_active" },
				{ "danger_close", "danger_close" },
				{ "explosion", "explosion" },
				{ "skitty_sub_gun", "gun_spawn" },
				{ "gun_spawn", "gun_spawn" },
				{ "destroy_quickbelt", "destroy_quickbelt" },
				{ "item_destroy", "item_destroy" },
				{ "wondertoy", "wondertoy_spawn" },
				{ "wondertoy_activate", "wondertoy_activate" },
				{ "ui_confirm", "ui_confirm" },
				{ "ui_error", "ui_error" },
				{ "system_ready", "system_ready" },
				{ "stovepipe_jam", "weapon_jam" },
				{ "stovepipe_malfunction", "weapon_jam" },
				{ "stovepipe_double_feed", "double_feed" },
				{ "stovepipe_failure_to_feed", "failure_to_feed" },
				{ "stovepipe_failure_to_eject", "failure_to_eject" },
				{ "stovepipe_failure_to_fire", "failure_to_fire" },
				{ "stovepipe_hang_fire", "hang_fire" },
				{ "stovepipe_clear_jam", "clear_jam" },
				{ "stovepipe_cycling", "cycling" },
				{ "stovepipe_generic", "generic_malfunction" }
			};
			string[] array = new string[5] { ".wav", ".ogg", ".mp3", ".aif", ".aiff" };
			foreach (string audioSearchPath in audioSearchPaths)
			{
				if (!Directory.Exists(audioSearchPath))
				{
					continue;
				}
				try
				{
					string[] files = Directory.GetFiles(audioSearchPath);
					string[] array2 = files;
					foreach (string text in array2)
					{
						string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
						string value = Path.GetExtension(text).ToLower();
						if (Array.IndexOf(array, value) == -1)
						{
							continue;
						}
						foreach (KeyValuePair<string, string> item in dictionary)
						{
							if (fileNameWithoutExtension.Equals(item.Value, StringComparison.OrdinalIgnoreCase))
							{
								if (!effectNameToFile.ContainsKey(item.Key))
								{
									effectNameToFile[item.Key] = text;
									logger.LogDebug((object)("[AudioManager] Auto-detected: " + item.Key + " -> " + Path.GetFileName(text)));
								}
								break;
							}
						}
					}
				}
				catch (Exception ex)
				{
					logger.LogWarning((object)("[AudioManager] Error scanning " + audioSearchPath + ": " + ex.Message));
				}
			}
			logger.LogInfo((object)$"[AudioManager] Discovered {effectNameToFile.Count} audio files");
		}

		private void LoadAudioClips()
		{
			foreach (KeyValuePair<string, string> item in effectNameToFile)
			{
				LoadAudioClip(item.Value, item.Key);
			}
		}

		private void LoadAudioClip(string filePath, string effectKey)
		{
			if (File.Exists(filePath))
			{
				((MonoBehaviour)this).StartCoroutine(LoadAudioClipCoroutine(filePath, effectKey));
			}
		}

		private IEnumerator LoadAudioClipCoroutine(string filePath, string effectKey)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAudioClipCoroutine>d__76(0)
			{
				<>4__this = this,
				filePath = filePath,
				effectKey = effectKey
			};
		}

		private AudioType GetAudioType(string filePath)
		{
			//IL_0056: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			switch (Path.GetExtension(filePath).ToLower())
			{
			case ".wav":
				return (AudioType)20;
			case ".ogg":
				return (AudioType)14;
			case ".mp3":
				return (AudioType)13;
			case ".aif":
			case ".aiff":
				return (AudioType)2;
			default:
				return (AudioType)20;
			}
		}

		public void PlayShurikenSound(string action = "throw", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				string effectKey = ((action == "throw") ? "shuriken" : ("shuriken_" + action));
				float volume = ((customVolume >= 0f) ? customVolume : (shurikenVolume.Value * effectsVolume.Value * masterVolume.Value));
				PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath);
			}
		}

		public void PlayHydrationSound(string action = "drink", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				string effectKey = ((action == "drink") ? "hydration" : ("hydration_" + action));
				float volume = ((customVolume >= 0f) ? customVolume : (hydrationVolume.Value * effectsVolume.Value * masterVolume.Value));
				PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath);
			}
		}

		public void PlaySlomoSound(string phase = "start", Vector3 position = default(Vector3), bool is3D = false, string customFilePath = null, float customVolume = -1f)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				string effectKey = "slomo_" + phase;
				float volume = ((customVolume >= 0f) ? customVolume : (slomoVolume.Value * ambientSoundsVolume.Value * masterVolume.Value));
				float pitch = ((phase == "active") ? Time.timeScale : 1f);
				PlayEffect(effectKey, position, is3D, volume, pitch, customFilePath);
			}
		}

		public void PlayDangerCloseSound(string type = "danger_close", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				float volume = ((customVolume >= 0f) ? customVolume : (dangerCloseVolume.Value * effectsVolume.Value * masterVolume.Value));
				PlayEffect(type, position, is3D, volume, 1f, customFilePath);
			}
		}

		public void PlayWeaponSpawnSound(string type = "skitty_sub_gun", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				float volume = ((customVolume >= 0f) ? customVolume : (skittySubGunVolume.Value * weaponSoundsVolume.Value * masterVolume.Value));
				PlayEffect(type, position, is3D, volume, 1f, customFilePath);
			}
		}

		public void PlayDestructionSound(string type = "destroy_quickbelt", Vector3 position = default(Vector3), bool is3D = false, string customFilePath = null, float customVolume = -1f)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				float volume = ((customVolume >= 0f) ? customVolume : (destroyQuickbeltVolume.Value * effectsVolume.Value * masterVolume.Value));
				PlayEffect(type, position, is3D, volume, 1f, customFilePath);
			}
		}

		public void PlayWondertoySound(string action = "spawn", Vector3 position = default(Vector3), bool is3D = true, string customFilePath = null, float customVolume = -1f)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				string effectKey = ((action == "spawn") ? "wondertoy" : ("wondertoy_" + action));
				float volume = ((customVolume >= 0f) ? customVolume : (wondertoyVolume.Value * effectsVolume.Value * masterVolume.Value));
				PlayEffect(effectKey, position, is3D, volume, 1f, customFilePath);
			}
		}

		public void PlayUISound(string type = "confirm", Vector3 position = default(Vector3), string customFilePath = null, float customVolume = -1f)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (enableAudioEffects.Value)
			{
				string effectKey = "ui_" + type;
				float volume = ((customVolume >= 0f) ? customVolume : (effectsVolume.Value * masterVolume.Value * 0.5f));
				PlayEffect(effectKey, position, is3D: false, volume, 1f, customFilePath);
			}
		}

		public void PlayStovepipeSound(string action, Vector3 position, bool is3D = true, string customSound = null, float volume = 1f)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (isInitialized && enableAudioEffects.Value)
			{
				string stovepipeSoundKey = GetStovepipeSoundKey(action);
				PlayEffect(stovepipeSoundKey, position, is3D, volume, 1f, customSound);
			}
		}

		public void PlayStovepipeEffect(Vector3 position, string effectType)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			PlayStovepipeSound(effectType, position);
		}

		public void RescanAudioFiles()
		{
			logger.LogInfo((object)"[AudioManager] Rescanning for audio files...");
			LoadConfiguredPaths();
			LoadCustomPathsConfig();
			ScanForAudioFiles();
			LoadAudioClips();
		}

		public bool RegisterCustomAudioFile(string effectKey, string absoluteFilePath)
		{
			if (string.IsNullOrEmpty(effectKey) || string.IsNullOrEmpty(absoluteFilePath))
			{
				logger.LogWarning((object)"[AudioManager] Cannot register: empty key or path");
				return false;
			}
			if (!File.Exists(absoluteFilePath))
			{
				logger.LogWarning((object)("[AudioManager] File not found: " + absoluteFilePath));
				return false;
			}
			effectNameToFile[effectKey] = absoluteFilePath;
			LoadAudioClip(absoluteFilePath, effectKey);
			logger.LogInfo((object)("[AudioManager] Registered custom audio: " + effectKey + " -> " + absoluteFilePath));
			return true;
		}

		private void PlayEffect(string effectKey, Vector3 position, bool is3D, float volume = 0.7f, float pitch = 1f, string customFilePath = null)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (!enableAudioEffects.Value || !isInitialized || string.IsNullOrEmpty(effectKey))
			{
				return;
			}
			volume = Mathf.Clamp(volume, 0f, 2f);
			pitch = Mathf.Clamp(pitch, 0.1f, 10f);
			if (activeSources.Count >= maxSimultaneousSounds.Value)
			{
				CleanupFinishedSources();
				if (activeSources.Count >= maxSimultaneousSounds.Value)
				{
					return;
				}
			}
			AudioClip audioClip = GetAudioClip(effectKey, customFilePath);
			if (!((Object)(object)audioClip == (Object)null))
			{
				CreateAndPlayAudioSource(effectKey, audioClip, position, is3D, volume, pitch);
			}
		}

		private AudioClip GetAudioClip(string effectKey, string customFilePath)
		{
			if (!string.IsNullOrEmpty(customFilePath))
			{
				AudioClip val = LoadCustomAudioFileSync(customFilePath);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			if (audioClips.ContainsKey(effectKey))
			{
				return audioClips[effectKey];
			}
			return null;
		}

		private void CreateAndPlayAudioSource(string effectKey, AudioClip clip, Vector3 position, bool is3D, float volume, float pitch)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("H3TVR_Audio_" + effectKey);
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.clip = clip;
			val2.volume = Mathf.Clamp01(volume);
			val2.pitch = Mathf.Clamp(pitch, 0.1f, 3f);
			val2.playOnAwake = false;
			val2.loop = false;
			if (is3D && enableSpatialAudio.Value)
			{
				val2.spatialBlend = (enable3DAudio.Value ? 1f : 0.5f);
				val2.maxDistance = maxAudioDistance.Value;
				val2.rolloffMode = (AudioRolloffMode)0;
				val2.dopplerLevel = 0.1f;
				((Component)val2).transform.position = position;
			}
			else
			{
				val2.spatialBlend = 0f;
			}
			string text = $"{effectKey}_{Time.time}_{Random.Range(1000, 9999)}";
			activeSources[text] = val2;
			val2.Play();
			((MonoBehaviour)this).StartCoroutine(CleanupAudioSource(text, clip.length + 0.1f));
		}

		public void StopEffectSounds(string effectKey)
		{
			if (string.IsNullOrEmpty(effectKey))
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, AudioSource> activeSource in activeSources)
			{
				if (!activeSource.Key.StartsWith(effectKey + "_"))
				{
					continue;
				}
				if ((Object)(object)activeSource.Value != (Object)null)
				{
					activeSource.Value.Stop();
					if ((Object)(object)((Component)activeSource.Value).gameObject != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)activeSource.Value).gameObject);
					}
				}
				list.Add(activeSource.Key);
			}
			foreach (string item in list)
			{
				activeSources.Remove(item);
			}
		}

		public void StopAllAudio()
		{
			foreach (KeyValuePair<string, AudioSource> activeSource in activeSources)
			{
				if ((Object)(object)activeSource.Value != (Object)null)
				{
					activeSource.Value.Stop();
					if ((Object)(object)((Component)activeSource.Value).gameObject != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)activeSource.Value).gameObject);
					}
				}
			}
			activeSources.Clear();
		}

		public bool LoadCustomAudioFile(string filePath, string effectKey, bool replaceExisting = true)
		{
			if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(effectKey))
			{
				return false;
			}
			if (!File.Exists(filePath))
			{
				return false;
			}
			if (effectNameToFile.ContainsKey(effectKey) && !replaceExisting)
			{
				return false;
			}
			((MonoBehaviour)this).StartCoroutine(LoadCustomAudioFileCoroutine(filePath, effectKey));
			return true;
		}

		private IEnumerator LoadCustomAudioFileCoroutine(string filePath, string effectKey)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadCustomAudioFileCoroutine>d__96(0)
			{
				<>4__this = this,
				filePath = filePath,
				effectKey = effectKey
			};
		}

		private AudioClip LoadCustomAudioFileSync(string filePath)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = filePath;
				if (!Path.IsPathRooted(filePath))
				{
					text = null;
					foreach (string audioSearchPath in audioSearchPaths)
					{
						string text2 = Path.Combine(audioSearchPath, filePath);
						if (File.Exists(text2))
						{
							text = text2;
							break;
						}
					}
					if (text == null)
					{
						return null;
					}
				}
				if (!File.Exists(text))
				{
					return null;
				}
				string text3 = $"temp_{Path.GetFileName(text)}_{text.GetHashCode()}";
				if (audioClips.ContainsKey(text3))
				{
					return audioClips[text3];
				}
				string text4 = "file://" + text;
				WWW val = new WWW(text4);
				try
				{
					float num = Time.realtimeSinceStartup + 30f;
					while (!val.isDone && string.IsNullOrEmpty(val.error))
					{
						if (Time.realtimeSinceStartup > num)
						{
							return null;
						}
						Thread.Sleep(10);
					}
					if (string.IsNullOrEmpty(val.error))
					{
						AudioClip audioClip = WWWAudioExtensions.GetAudioClip(val, false, false, GetAudioType(text));
						if ((Object)(object)audioClip != (Object)null)
						{
							((Object)audioClip).name = text3;
							audioClips[text3] = audioClip;
							return audioClip;
						}
					}
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch
			{
			}
			return null;
		}

		public bool PlayLoadedEffect(string effectName, Vector3 position = default(Vector3), bool is3D = true, float volume = 0.8f, float pitch = 1f)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!enableAudioEffects.Value || !isInitialized)
			{
				return false;
			}
			if (!HasEffect(effectName))
			{
				return false;
			}
			float volume2 = volume * effectsVolume.Value * masterVolume.Value;
			PlayEffect(effectName, position, is3D, volume2, pitch);
			return true;
		}

		public bool HasEffect(string effectName)
		{
			return !string.IsNullOrEmpty(effectName) && audioClips.ContainsKey(effectName);
		}

		public bool IsInitialized()
		{
			return isInitialized;
		}

		public void LogConfiguration()
		{
			logger.LogInfo((object)"[AudioManager] Configuration:");
			logger.LogInfo((object)$"  Enabled: {enableAudioEffects.Value}");
			logger.LogInfo((object)$"  Master Volume: {masterVolume.Value}");
			logger.LogInfo((object)$"  Loaded Clips: {audioClips.Count}");
			logger.LogInfo((object)$"  Active Sources: {activeSources.Count}");
			logger.LogInfo((object)$"  Search Paths: {audioSearchPaths.Count}");
			logger.LogInfo((object)"  Loaded Effects:");
			foreach (KeyValuePair<string, string> item in effectNameToFile)
			{
				logger.LogInfo((object)("    " + item.Key + " -> " + item.Value));
			}
		}

		private string GetStovepipeSoundKey(string action)
		{
			string text = action.ToLower().Replace(" ", "_");
			if (text == "jam" || text == "malfunction")
			{
				return "stovepipe_jam";
			}
			return "stovepipe_" + text;
		}

		private void CleanupFinishedSources()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, AudioSource> activeSource in activeSources)
			{
				if (!((Object)(object)activeSource.Value == (Object)null) && activeSource.Value.isPlaying)
				{
					continue;
				}
				list.Add(activeSource.Key);
				if ((Object)(object)activeSource.Value != (Object)null && (Object)(object)((Component)activeSource.Value).gameObject != (Object)null)
				{
					try
					{
						Object.Destroy((Object)(object)((Component)activeSource.Value).gameObject);
					}
					catch
					{
					}
				}
			}
			foreach (string item in list)
			{
				activeSources.Remove(item);
			}
		}

		private IEnumerator CleanupAudioSource(string sourceKey, float delay)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CleanupAudioSource>d__104(0)
			{
				<>4__this = this,
				sourceKey = sourceKey,
				delay = delay
			};
		}

		private void OnDestroy()
		{
			StopAllAudio();
			foreach (AudioClip value in audioClips.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			audioClips.Clear();
			effectNameToFile.Clear();
			audioSearchPaths.Clear();
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)"[AudioManager] Destroyed and cleaned up");
			}
		}
	}
	public class EffectsManager : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <ActivatePillowSlomo>d__9 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			public EffectsManager <>4__this;

			private float <maxSlomoValue>5__1;

			private float <waitTime>5__2;

			private float <scaleSpeed>5__3;

			private float <returnSpeed>5__4;

			private float <originalTimeScale>5__5;

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

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

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

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

			private bool MoveNext()
			{
				//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this.plugin.GetSlomoConfig(out <maxSlomoValue>5__1, out <waitTime>5__2, out <scaleSpeed>5__3, out <returnSpeed>5__4);
					<originalTimeScale>5__5 = Time.timeScale;
					Time.timeScale = <maxSlomoValue>5__1;
					Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency;
					<>4__this.slomoController?.UpdateMovementScale(Time.timeScale);
					<>4__this.logger.LogInfo((object)$"Pillow slow motion activated for {duration} seconds (scale: {<maxSlomoValue>5__1})");
					<>2__current = (object)new WaitForSecondsRealtime(duration);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					Time.timeScale = <originalTimeScale>5__5;
					Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency;
					<>4__this.slomoController?.UpdateMovementScale(Time.timeScale);
					<>4__this.logger.LogInfo((object)"Pillow slow motion effect ended");
					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 <ActivatePillowZeroGravity>d__15 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float duration;

			public EffectsManager <>4__this;

			private GravityMode <originalGravityMode>5__1;

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

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

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

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

			private bool MoveNext()
			{
				//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_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Expected O, but got Unknown
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<originalGravityMode>5__1 = GM.Options.SimulationOptions.ObjectGravityMode;
					GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)3;
					GM.CurrentSceneSettings.RefreshGravity();
					<>4__this.logger.LogInfo((object)$"Pillow zero gravity activated for {duration} seconds");
					<>2__current = (object)new WaitForSecondsRealtime(duration);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					GM.Options.SimulationOptions.ObjectGravityMode = <originalGravityMode>5__1;
					GM.CurrentSceneSettings.RefreshGravity();
					<>4__this.logger.LogInfo((object)"Pillow zero gravity effect ended");
					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 <RealisticFallWait>d__14 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Action onComplete;

			public EffectsManager <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSecondsRealtime(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					onComplete?.Invoke();
					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 <SlomoWait>d__8 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Action onComplete;

			public EffectsManager <>4__this;

			private float <maxSlomoValue>5__1;

			private float <waitTime>5__2;

			private float <scaleSpeed>5__3;

			private float <returnSpeed>5__4;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this.plugin.GetSlomoConfig(out <maxSlomoValue>5__1, out <waitTime>5__2, out <scaleSpeed>5__3, out <returnSpeed>5__4);
					<>2__current = (object)new WaitForSecondsRealtime(<waitTime>5__2);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					onComplete?.Invoke();
					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 <ZeroGWait>d__13 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Action onComplete;

			public EffectsManager <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(6f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					onComplete?.Invoke();
					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 SlomoMovementController slomoController;

		private ManualLogSource logger;

		private static EffectsManager instance;

		public void Initialize(H3TVRImproved pluginInstance, SlomoMovementController controller, ManualLogSource logSource)
		{
			plugin = pluginInstance;
			slomoController = controller;
			logger = logSource;
			instance = this;
		}

		public static bool IsInitialized()
		{
			return (Object)(object)instance != (Object)null;
		}

		public void SlomoScaleDown()
		{
			plugin.GetSlomoConfig(out var maxSlomoValue, out var _, out var scaleSpeed, out var _);
			if (Time.timeScale > maxSlomoValue)
			{
				Time.timeScale -= scaleSpeed * Time.unscaledDeltaTime;
				Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency;
				Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f);
				slomoController?.UpdateMovementScale(Time.timeScale);
			}
			if (Time.timeScale <= maxSlomoValue)
			{
				plugin.SetSlomoStatus("Wait");
			}
		}

		public void SlomoReturn()
		{
			plugin.GetSlomoConfig(out var _, out var _, out var _, out var returnSpeed);
			if (Time.timeScale != 1f)
			{
				Time.timeScale += returnSpeed * Time.unscaledDeltaTime;
				Time.fixedDeltaTime = Time.timeScale / SteamVR.instance.hmd_DisplayFrequency;
				Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f);
				slomoController?.UpdateMovementScale(Time.timeScale);
			}
		}

		public IEnumerator SlomoWait(Action onComplete)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SlomoWait>d__8(0)
			{
				<>4__this = this,
				onComplete = onComplete
			};
		}

		public IEnumerator ActivatePillowSlomo(float duration)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ActivatePillowSlomo>d__9(0)
			{
				<>4__this = this,
				duration = duration
			};
		}

		public void ZeroGravityBumpDown()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)3;
				GM.CurrentSceneSettings.RefreshGravity();
			}
			catch (Exception ex)
			{
				logger.LogError((object)("ZeroGravityBumpDown failed: " + ex.Message));
			}
		}

		public void ZeroGravityBumpUp()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)1;
				GM.CurrentSceneSettings.RefreshGravity();
			}
			catch (Exception ex)
			{
				logger.LogError((object)("ZeroGravityBumpUp failed: " + ex.Message));
			}
		}

		public void RealisticFall()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GM.Options.SimulationOptions.ObjectGravityMode = (GravityMode)0;
				GM.CurrentSceneSettings.RefreshGravity();
			}
			catch (Exception ex)
			{
				logger.LogError((object)("RealisticFall failed: " + ex.Message));
			}
		}

		public IEnumerator ZeroGWait(Action onComplete)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ZeroGWait>d__13(0)
			{
				<>4__this = this,
				onComplete = onComplete
			};
		}

		public IEnumerator RealisticFallWait(Action onComplete)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RealisticFallWait>d__14(0)
			{
				<>4__this = this,
				onComplete = onComplete
			};
		}

		public IEnumerator ActivatePillowZeroGravity(float duration)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ActivatePillowZeroGravity>d__15(0)
			{
				<>4__this = this,
				duration = duration
			};
		}

		public bool CheckVRButtonPress(string buttonName)
		{
			try
			{
				FVRViveHand[] array = GM.CurrentMovementManager?.Hands;
				if (array == null || array.Length == 0)
				{
					return false;
				}
				switch (buttonName.ToLower())
				{
				case "leftx":
					return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.AXButtonDown;
				case "rightx":
					return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.AXButtonDown;
				case "lefty":
					return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.BYButtonDown;
				case "righty":
					return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.BYButtonDown;
				case "leftgrip":
					return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.GripDown;
				case "rightgrip":
					return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.GripDown;
				case "lefttrigger":
					return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.TriggerDown;
				case "righttrigger":
					return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.TriggerDown;
				case "lefttouchpad":
					return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.TouchpadDown;
				case "righttouchpad":
					return array.Length > 1 && (Object)(object)array[1] != (Object)null && array[1].Input.TouchpadDown;
				default:
					logger.LogWarning((object)("Unknown VR button configuration: " + buttonName + ". Using default LeftX."));
					return array.Length != 0 && (Object)(object)array[0] != (Object)null && array[0].Input.AXButtonDown;
				}
			}
			catch (Exception ex)
			{
				logger.LogError((object)("CheckVRButtonPress failed for button " + buttonName + ": " + ex.Message));
				return false;
			}
		}

		public void EnableMeatHands()
		{
			try
			{
				FVRViveHand[] array = GM.CurrentMovementManager?.Hands;
				if (array == null || array.Length < 2)
				{
					logger.LogWarning((object)"Cannot enable meat hands: Hand references not available");
					return;
				}
				array[0].SpawnSausageFingers();
				array[1].SpawnSausageFingers();
				logger.LogInfo((object)"Meat hands enabled");
			}
			catch (Exception ex)
			{
				logger.LogError((object)("EnableMeatHands failed: " + ex.Message));
			}
		}

		public static void PlayStovepipeParticles(Vector3 position, StovepipeIntegrationManager.MalfunctionType malfunctionType)
		{
			//IL_0038: 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)
			try
			{
				if ((Object)(object)instance == (Object)null)
				{
					EffectsManager effectsManager = instance;
					if (effectsManager != null)
					{
						ManualLogSource obj = effectsManager.logger;
						if (obj != null)
						{
							obj.LogWarning((object)"EffectsManager not initialized for Stovepipe particles");
						}
					}
					return;
				}
				GameObject val = CreateStovepipeParticleEffect(position, malfunctionType);
				if ((Object)(object)val != (Object)null)
				{
					ManualLogSource obj2 = instance.logger;
					if (obj2 != null)
					{
						obj2.LogDebug((object)$"Playing Stovepipe particle effect for {malfunctionType} at {position}");
					}
					Object.Destroy((Object)(object)val, 3f);
				}
			}
			catch (Exception ex)
			{
				EffectsManager effectsManager2 = instance;
				if (effectsManager2 != null)
				{
					ManualLogSource obj3 = effectsManager2.logger;
					if (obj3 != null)
					{
						obj3.LogError((object)("PlayStovepipeParticles failed: " + ex.Message));
					}
				}
			}
		}

		private static GameObject CreateStovepipeParticleEffect(Vector3 position, StovepipeIntegrationManager.MalfunctionType malfunctionType)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_001e: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_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_00a7: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject($"StovepipeEffect_{malfunctionType}");
				val.transform.position = position;
				ParticleSystem val2 = val.AddComponent<ParticleSystem>();
				MainModule main = val2.main;
				EmissionModule emission = val2.emission;
				ShapeModule shape = val2.shape;
				VelocityOverLifetimeModule velocityOverLifetime = val2.velocityOverLifetime;
				switch (malfunctionType)
				{
				case StovepipeIntegrationManager.MalfunctionType.Stovepipe:
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.6f, 0.2f, 0.8f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.02f);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(2f);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(20f);
					break;
				case StovepipeIntegrationManager.MalfunctionType.DoubleFeed:
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.7f, 0.7f, 0.2f, 0.9f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.015f);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1.5f);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(30f);
					break;
				case StovepipeIntegrationManager.MalfunctionType.FailureToEject:
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.6f, 0.4f, 0.2f, 0.7f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.018f);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(2.5f);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(15f);
					break;
				case StovepipeIntegrationManager.MalfunctionType.FailureToFeed:
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.8f, 0.3f, 0.6f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.012f);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1f);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(25f);
					break;
				case StovepipeIntegrationManager.MalfunctionType.DirtyGun:
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.3f, 0.3f, 0.3f, 0.8f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.008f);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(3f);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(40f);
					break;
				default:
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.5f, 0.5f, 0.5f, 0.6f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.01f);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1.5f);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(20f);
					break;
				}
				((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.5f);
				((MainModule)(ref main)).maxParticles = 50;
				((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4;
				((ShapeModule)(ref shape)).angle = 15f;
				((ShapeModule)(ref shape)).radius = 0.05f;
				((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true;
				((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)0;
				return val;
			}
			catch (Exception ex)
			{
				EffectsManager effectsManager = instance;
				if (effectsManager != null)
				{
					ManualLogSource obj = effectsManager.logger;
					if (obj != null)
					{
						obj.LogError((object)("CreateStovepipeParticleEffect failed: " + ex.Message));
					}
				}
				return null;
			}
		}

		public static void CreateMalfunctionSmokeEffect(Vector3 position, float intensity = 1f)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_00c4: 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
			{
				if (!((Object)(object)instance == (Object)null))
				{
					GameObject val = new GameObject("MalfunctionSmoke");
					val.transform.position = position;
					ParticleSystem val2 = val.AddComponent<ParticleSystem>();
					MainModule main = val2.main;
					EmissionModule emission = val2.emission;
					ShapeModule shape = val2.shape;
					((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.2f, 0.2f, 0.2f, 0.6f));
					((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.1f * intensity);
					((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(5f);
					((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.2f);
					((MainModule)(ref main)).maxParticles = (int)(30f * intensity);
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(10f * intensity);
					((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)10;
					((ShapeModule)(ref shape)).radius = 0.03f;
					Object.Destroy((Object)(object)val, 6f);
					ManualLogSource obj = instance.logger;
					if (obj != null)
					{
						obj.LogDebug((object)$"Created malfunction smoke effect at {position} with intensity {intensity}");
					}
				}
			}
			catch (Exception ex)
			{
				EffectsManager effectsManager = instance;
				if (effectsManager != null)
				{
					ManualLogSource obj2 = effectsManager.logger;
					if (obj2 != null)
					{
						obj2.LogError((object)("CreateMalfunctionSmokeEffect failed: " + ex.Message));
					}
				}
			}
		}
	}
	public class EnhancedChatSpawner : MonoBehaviour
	{
		public struct ChatSosigStats
		{
			public int ActiveAllies;

			public int ActiveEnemies;

			public int QueueLength;

			public int TotalSpawned;
		}

		public enum SpawnPriority
		{
			Low,
			Normal,
			High,
			Immediate
		}

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

			private object <>2__current;

			public EnhancedChatSpawner <>4__this;

			private WaitForSeconds <wait>5__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<wait>5__1 = new WaitForSeconds(10f);
					break;
				case 1:
					<>1__state = -1;
					<>4__this.CleanupDeadSosigs();
					break;
				}
				<>2__current = <wait>5__1;
				<>1__state = 1;
				return true;
			}

			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 <LoadTemplatesDelayed>d__33 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public EnhancedChatSpawner <>4__this;

			private SosigEnemyTemplate[] <sosigObjects>5__1;

			private SosigEnemyTemplate[] <>s__2;

			private int <>s__3;

			private SosigEnemyTemplate <template>5__4;

			private Exception <ex>5__5;

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

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

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

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					try
					{
						<sosigObjects>5__1 = Resources.FindObjectsOfTypeAll<SosigEnemyTemplate>();
						if (<sosigObjects>5__1 != null && <sosigObjects>5__1.Length != 0)
						{
							<>4__this.cachedSosigTemplates = <sosigObjects>5__1;
							<>s__2 = <>4__this.cachedSosigTemplates;
							for (<>s__3 = 0; <>s__3 < <>s__2.Length; <>s__3++)
							{
								<template>5__4 = <>s__2[<>s__3];
								if ((Object)(object)<template>5__4 != (Object)null)
								{
									<>4__this.allyTemplates.Add(<template>5__4);
									<>4__this.enemyTemplates.Add(<template>5__4);
								}
								<template>5__4 = null;
							}
							<>s__2 = null;
							if (<>4__this.cachedSosigTemplates.Length != 0)
							{
								<>4__this.defaultAllyTemplate = <>4__this.cachedSosigTemplates[0];
							}
							ManualLogSource logger = <>4__this.logger;
							if (logger != null)
							{
								logger.LogInfo((object)$"Loaded {<>4__this.allyTemplates.Count} sosig templates");
							}
						}
						else
						{
							ManualLogSource logger2 = <>4__this.logger;
							if (logger2 != null)
							{
								logger2.LogWarning((object)"No sosig templates found - spawning may be limited");
							}
						}
						<sosigObjects>5__1 = null;
					}
					catch (Exception ex)
					{
						<ex>5__5 = ex;
						ManualLogSource logger3 = <>4__this.logger;
						if (logger3 != null)
						{
							logger3.LogError((object)("Template loading failed: " + <ex>5__5.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 <UpdateSosigsCoroutine>d__46 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public EnhancedChatSpawner <>4__this;

			private WaitForSeconds <wait>5__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<wait>5__1 = new WaitForSeconds(1f);
					break;
				case 1:
					<>1__state = -1;
					<>4__this.UpdateAllySosigs();
					<>4__this.UpdateEnemySosigs();
					break;
				}
				<>2__current = <wait>5__1;
				<>1__state = 1;
				return true;
			}

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

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

		public static List<Sosig> spawnedChatters = new List<Sosig>();

		public static List<Sosig> spawnedEnemyChatters = new List<Sosig>();

		private H3TVRImproved plugin;

		private ManualLogSource logger;

		private TwitchChatManager twitchManager;

		[Header("Sosig Templates")]
		public SosigEnemyTemplate defaultAllyTemplate;

		public List<SosigEnemyTemplate> allyTemplates = new List<SosigEnemyTemplate>();

		public List<SosigEnemyTemplate> enemyTemplates = new List<SosigEnemyTemplate>();

		private SosigEnemyTemplate[] cachedSosigTemplates;

		public GameObject nameplateAlly;

		public GameObject nameplateEnemy;

		public string SpawnerName = "ChatUser";

		private ConfigEntry<int> maxAllySosigs;

		private ConfigEntry<int> maxEnemySosigs;

		private ConfigEntry<float> spawnCooldown;

		private ConfigEntry<bool> enableNameplates;

		private ConfigEntry<float> sosigLifetime;

		private ConfigEntry<bool> enableAutoCleanup;

		private ConfigEntry<float> enemyIFF;

		private ConfigEntry<KeyCode> spawnAllyKey;

		private ConfigEntry<KeyCode> spawnEnemyKey;

		private ConfigEntry<KeyCode> clearSosigsKey;

		private ConfigEntry<float> followDistance;

		private ConfigEntry<float> enemyAggressionDistance;

		private float lastSpawnTime;

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

		public static EnhancedChatSpawner Instance { get; private set; }

		public void Initialize(H3TVRImproved pluginInstance, ManualLogSource logSource)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			plugin = pluginInstance;
			logger = logSource;
			InitializeConfiguration();
			InitializeSosigTemplates();
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)"Enhanced Chat Spawner initialized (H3TwitchTools style)");
			}
			((MonoBehaviour)this).StartCoroutine(UpdateSosigsCoroutine());
			((MonoBehaviour)this).StartCoroutine(CleanupCoroutine());
		}

		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
			{
				maxAllySosigs = ((BaseUnityPlugin)plugin).Config.Bind<int>("Chat Spawner", "MaxAllySosigs", 8, "Maximum ally sosigs");
				maxEnemySosigs = ((BaseUnityPlugin)plugin).Config.Bind<int>("Chat Spawner", "MaxEnemySosigs", 8, "Maximum enemy sosigs");
				spawnCooldown = ((BaseUnityPlugin)plugin).Config.Bind<float>("Chat Spawner", "SpawnCooldown", 2f, "Cooldown between spawns");
				enableNameplates = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Chat Spawner", "EnableNameplates", true, "Show nameplates above sosigs");
				sosigLifetime = ((BaseUnityPlugin)plugin).Config.Bind<float>("Chat Spawner", "SosigLifetime", 300f, "Sosig lifetime in seconds (0 = infinite)");
				enableAutoCleanup = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Chat Spawner", "EnableAutoCleanup", true, "Auto cleanup dead sosigs");
				enemyIFF = ((BaseUnityPlugin)plugin).Config.Bind<float>("Chat Spawner", "EnemyIFF", 1f, "Enemy IFF code");
				followDistance = ((BaseUnityPlugin)plugin).Config.Bind<float>("Chat Spawner", "FollowDistance", 6f, "Distance for allies to follow player");
				enemyAggressionDistance = ((BaseUnityPlugin)plugin).Config.Bind<float>("Chat Spawner", "EnemyAggressionDistance", 20f, "Distance at which enemies become aggressive");
				spawnAllyKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Chat Spawner Keys", "SpawnAllyKey", (KeyCode)112, "Spawn ally key");
				spawnEnemyKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Chat Spawner Keys", "SpawnEnemyKey", (KeyCode)111, "Spawn enemy key");
				clearSosigsKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Chat Spawner Keys", "ClearSosigsKey", (KeyCode)127, "Clear sosigs key");
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogInfo((object)"Configuration initialized successfully");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj3 = logger;
				if (obj3 != null)
				{
					obj3.LogError((object)("Config init failed: " + ex.Message));
				}
			}
		}

		private void InitializeSosigTemplates()
		{
			try
			{
				((MonoBehaviour)this).StartCoroutine(LoadTemplatesDelayed());
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogError((object)("Template initialization failed: " + ex.Message));
				}
			}
		}

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

		public void SpawningSequence(string username)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (spawnedChatters.Count >= maxAllySosigs.Value)
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogWarning((object)"Max ally sosigs reached");
					}
					return;
				}
				if (Time.time - lastSpawnTime < spawnCooldown.Value)
				{
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogWarning((object)"Spawn cooldown active");
					}
					return;
				}
				SosigEnemyTemplate randomTemplate = GetRandomTemplate(isFriendly: true);
				if ((Object)(object)randomTemplate == (Object)null)
				{
					ManualLogSource obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogError((object)"No ally template available");
					}
					return;
				}
				Vector3 pos = CalculateAllySpawnPoint();
				Quaternion identity = Quaternion.identity;
				Sosig val = SpawnSosig(randomTemplate, pos, identity, 0);
				if ((Object)(object)val != (Object)null)
				{
					SetupAllyBehavior(val);
					if (enableNameplates.Value && (Object)(object)nameplateAlly != (Object)null)
					{
						AttachNameplate(val, username ?? "Ally", nameplateAlly, isEnemy: false);
					}
					spawnedChatters.Add(val);
					lastSpawnTime = Time.time;
					ManualLogSource obj4 = logger;
					if (obj4 != null)
					{
						obj4.LogInfo((object)("Spawned ally sosig for " + username));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj5 = logger;
				if (obj5 != null)
				{
					obj5.LogError((object)("Ally spawn failed: " + ex.Message));
				}
			}
		}

		public void SpawningSequenceEnemy(int IFF, string username)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (spawnedEnemyChatters.Count >= maxEnemySosigs.Value)
				{
					ManualLogSource obj = logger;
					if (obj != null)
					{
						obj.LogWarning((object)"Max enemy sosigs reached");
					}
					return;
				}
				if (Time.time - lastSpawnTime < spawnCooldown.Value)
				{
					ManualLogSource obj2 = logger;
					if (obj2 != null)
					{
						obj2.LogWarning((object)"Spawn cooldown active");
					}
					return;
				}
				SosigEnemyTemplate randomTemplate = GetRandomTemplate(isFriendly: false);
				if ((Object)(object)randomTemplate == (Object)null)
				{
					ManualLogSource obj3 = logger;
					if (obj3 != null)
					{
						obj3.LogError((object)"No enemy template available");
					}
					return;
				}
				Vector3 pos = CalculateEnemySpawnPoint();
				Quaternion identity = Quaternion.identity;
				int iFF = ((IFF > 0) ? IFF : Mathf.Max(1, (int)enemyIFF.Value));
				Sosig val = SpawnSosig(randomTemplate, pos, identity, iFF);
				if ((Object)(object)val != (Object)null)
				{
					SetupEnemyBehavior(val);
					if (enableNameplates.Value && (Object)(object)nameplateEnemy != (Object)null)
					{
						AttachNameplate(val, username ?? "Enemy", nameplateEnemy, isEnemy: true);
					}
					spawnedEnemyChatters.Add(val);
					lastSpawnTime = Time.time;
					ManualLogSource obj4 = logger;
					if (obj4 != null)
					{
						obj4.LogInfo((object)("Spawned enemy sosig for " + username));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj5 = logger;
				if (obj5 != null)
				{
					obj5.LogError((object)("Enemy spawn failed: " + ex.Message));
				}
			}
		}

		private Sosig SpawnSosig(SosigEnemyTemplate template, Vector3 pos, Quaternion rot, int IFF)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			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;
				}
				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)("Sosig spawn failed: " + ex.Message));
				}
				return null;
			}
		}

		private void EquipWeapons(Sosig sosig, SosigEnemyTemplate template, Vector3 pos, Quaternion rot)
		{
			//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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			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));
				}
			}
		}

		private void SetupAllyBehavior(Sosig sosig)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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))
				{
					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;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)("Ally behavior setup failed: " + ex.Message));
				}
			}
		}

		private void SetupEnemyBehavior(Sosig sosig)
		{
			//IL_002a: 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
			{
				FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
				if (!((Object)(object)((currentPlayerBody != null) ? ((Component)currentPlayerBody).transform : null) == (Object)null))
				{
					sosig.CommandAssaultPoint(((Component)GM.CurrentPlayerBody).transform.position);
					sosig.FallbackOrder = (SosigOrder)4;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = logger;
				if (ob