Decompiled source of OptimizedSkinwalkers v2.3.0

plugins/lynxdev.OptimizedSkinwalkers.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dissonance;
using Dissonance.Config;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("lynxdev.OptimizedSkinwalkers")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Attempt to optimize Skinwalkers")]
[assembly: AssemblyFileVersion("2.1.1.0")]
[assembly: AssemblyInformationalVersion("2.1.1")]
[assembly: AssemblyProduct("lynxdev.OptimizedSkinwalkers")]
[assembly: AssemblyTitle("lynxdev.OptimizedSkinwalkers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace OptimizedSkinwalkers
{
	[BepInPlugin("lynxdev.OptimizedSkinwalkers", "lynxdev.OptimizedSkinwalkers", "2.1.1")]
	public class OptimizedSkinwalkersPlugin : BaseUnityPlugin
	{
		private readonly Harmony harmony = new Harmony("lynxdev.OptimizedSkinwalkers");

		public static OptimizedSkinwalkersPlugin Instance;

		private void Awake()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			else if ((Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			InvokeAssemblyMethods();
			SkinwalkerLogger.Initialize("lynxdev.OptimizedSkinwalkers");
			SkinwalkerLogger.Log("SKINWALKER MOD STARTING UP 2.1.1");
			SkinwalkerConfig.InitConfig(((BaseUnityPlugin)this).Config);
			if (SkinwalkerConfig.VoiceLineFrequency.Value == 0f)
			{
				SkinwalkerLogger.LogWarning("VoiceLineFrequency set to 0. Aborting mod initialization");
				return;
			}
			InitializeNetworkVariableSerializationTypes();
			CreateSkinwalkerModPersistent();
			SetDissonanceLogLevel();
			GameObject val = new GameObject("SceneLoadingHandler");
			val.AddComponent<SceneLoadingHandler>();
			((Object)val).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val);
		}

		private void InvokeAssemblyMethods()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo[] array2 = methods;
				foreach (MethodInfo methodInfo in array2)
				{
					object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
					if (customAttributes.Length != 0)
					{
						methodInfo.Invoke(null, null);
					}
				}
			}
		}

		private void InitializeNetworkVariableSerializationTypes()
		{
			NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy<bool>();
			NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<bool>();
			NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy<float>();
			NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<float>();
		}

		private void SetDissonanceLogLevel()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			foreach (LogCategory value in Enum.GetValues(typeof(LogCategory)))
			{
				if ((int)value != 0)
				{
					Logs.SetLogLevel(value, (LogLevel)4);
				}
			}
		}

		private void CreateSkinwalkerModPersistent()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("Skinwalker Mod");
			val.AddComponent<SkinwalkerModPersistent>();
			((Object)val).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)val);
		}
	}
	public class EnemyConfigEntry
	{
		public Type EnemyType;

		public ConfigEntry<bool> configEntry;

		public string cleanedName;

		private readonly bool defaultValue;

		public EnemyConfigEntry(Type type)
		{
			EnemyType = type;
			cleanedName = GetNameForType(type);
			defaultValue = GetDefaultValue(type);
		}

		public void SetConfigEntry(ConfigFile configFile, string sectionName, string description = "")
		{
			configEntry = configFile.Bind<bool>(sectionName, cleanedName, defaultValue, "");
		}

		private string GetNameForType(Type type)
		{
			string name = type.Name;
			if (1 == 0)
			{
			}
			string result = name switch
			{
				"BaboonBirdAI" => "Baboon Hawk", 
				"ClaySurgeonAI" => "Barber", 
				"FlowermanAI" => "Bracken", 
				"SandSpiderAI" => "Bunker Spider", 
				"ButlerEnemyAI" => "Butler", 
				"ButlerBeesEnemyAI" => "Butler Bees", 
				"SpringManAI" => "Coil-Head", 
				"RedLocustBees" => "Circuit Bees", 
				"SandWormAI" => "Earth Leviathan", 
				"MouthDogAI" => "Eyeless Dog", 
				"ForestGiantAI" => "Forest Keeper", 
				"DressGirlAI" => "Ghost Girl", 
				"HoarderBugAI" => "Hoarding Bug", 
				"BlobAI" => "Hydrogere", 
				"JesterAI" => "Jester", 
				"BushWolfEnemy" => "Kidnapper Fox", 
				"DoublewingAI" => "Manticoil", 
				"MaskedPlayerEnemy" => "Masked", 
				"NutcrackerEnemyAI" => "Nutcracker", 
				"RadMechAI" => "Old Bird", 
				"DocileLocustBeesAI" => "Roaming Locusts", 
				"CentipedeAI" => "Snare Flea", 
				"PufferAI" => "Spore Lizard", 
				"CrawlerAI" => "Thumper", 
				"FlowerSnakeEnemy" => "Tulip Snake", 
				_ => GetFixedEnemyName(type.Name), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		private string GetFixedEnemyName(string name)
		{
			StringBuilder stringBuilder = new StringBuilder(name);
			stringBuilder.Replace("AI", "");
			stringBuilder.Replace("Enemy", "");
			string text = stringBuilder.ToString();
			stringBuilder = new StringBuilder();
			stringBuilder.Append(text[0]);
			for (int i = 1; i < text.Length; i++)
			{
				if (char.IsUpper(text[i]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(text[i]);
			}
			return stringBuilder.ToString();
		}

		private bool GetDefaultValue(Type type)
		{
			string name = type.Name;
			string text = name;
			if (text == "DoublewingAI" || text == "DocileLocustBeesAI")
			{
				return false;
			}
			return true;
		}
	}
	public class SceneLoadingHandler : MonoBehaviour
	{
		private int internalSceneCount;

		private bool destroyHandler;

		private void Awake()
		{
			SkinwalkerLogger.Log("SceneLoadingHandler Awake");
			internalSceneCount = SceneManager.sceneCount;
		}

		private void Update()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (SceneManager.sceneCount == internalSceneCount)
			{
				return;
			}
			internalSceneCount = SceneManager.sceneCount;
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				if (SkinwalkerNetworkManagerHandler.TryClientConnectInitializer(sceneAt))
				{
					destroyHandler = true;
					break;
				}
			}
			if (destroyHandler)
			{
				SkinwalkerLogger.Log("Destroying SceneLoadingHandler...");
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	public class SkinwalkerBehaviour : MonoBehaviour
	{
		private AudioSource audioSource;

		public const float PLAY_INTERVAL_MIN = 15f;

		public const float PLAY_INTERVAL_MAX = 40f;

		private const float MAX_DIST = 100f;

		private float nextTimeToPlayAudio;

		private EnemyAI ai;

		public void Initialize(EnemyAI ai)
		{
			this.ai = ai;
			audioSource = ai.creatureVoice;
			SetNextTime();
		}

		private void Update()
		{
			if (Time.time > nextTimeToPlayAudio)
			{
				AttemptPlaySound();
				SetNextTime();
			}
		}

		private void AttemptPlaySound()
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.localPlayerController == (Object)null || (Object)(object)StartOfRound.Instance.spectateCamera == (Object)null || (Object)(object)ai == (Object)null || ai.isEnemyDead || (Object)(object)audioSource == (Object)null)
			{
				return;
			}
			EnemyAI obj = ai;
			DressGirlAI val = (DressGirlAI)(object)((obj is DressGirlAI) ? obj : null);
			if (val == null || (!((Object)(object)val.hauntingPlayer != (Object)(object)StartOfRound.Instance.localPlayerController) && (val.staringInHaunt || ((EnemyAI)val).moveTowardsDestination)))
			{
				Vector3 val2 = (StartOfRound.Instance.localPlayerController.isPlayerDead ? ((Component)StartOfRound.Instance.spectateCamera).transform.position : ((Component)StartOfRound.Instance.localPlayerController).transform.position);
				if (Vector3.Distance(val2, ((Component)this).transform.position) < 100f && SkinwalkerModPersistent.Instance.TryGetSample(out var audioClip))
				{
					audioSource.PlayOneShot(audioClip);
				}
			}
		}

		private void SetNextTime()
		{
			float num = Random.Range(15f, 40f);
			nextTimeToPlayAudio = Time.time + num / SkinwalkerNetworkManager.Instance.VoiceLineFrequency.Value;
		}

		private T CopyComponent<T>(T original, GameObject destination) where T : Component
		{
			Type type = ((object)original).GetType();
			Component val = destination.AddComponent(type);
			FieldInfo[] fields = type.GetFields();
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				fieldInfo.SetValue(val, fieldInfo.GetValue(original));
			}
			T val2 = (T)(object)((val is T) ? val : null);
			return (val2 != null) ? val2 : default(T);
		}
	}
	public static class SkinwalkerConfig
	{
		public const float DEFAULT_FOLDER_SCAN_INTERVAL = 8f;

		public const int CUSTOM_SOUND_FREQUENCY_MIN = 0;

		public const int CUSTOM_SOUND_FREQUENCY_MAX = 100;

		public const float DEFAULT_VOICE_FREQUENCY = 1f;

		public const bool DEFAULT_INSIDE_ENEMIES = true;

		public const bool DEFAULT_OUTSIDE_ENEMIES = true;

		public const bool DEFAULT_DAYTIME_ENEMIES = false;

		public const bool DEFAULT_NIGHTTIME_ENEMIES = true;

		public const bool DEFAULT_UNSPECIFIED_ENEMIES = true;

		private const string EXTRA_SETTINGS = "Extra Settings";

		private const string MONSTER_VOICES = "Monster Voices";

		public static ConfigEntry<float> VoiceLineFrequency;

		public static ConfigEntry<bool> KeepFilesBetweenSessions;

		public static ConfigEntry<float> TimeForFileCaching;

		public static ConfigEntry<bool> AddCustomFiles;

		public static ConfigEntry<float> CustomSoundFrequency;

		public static Dictionary<Type, EnemyConfigEntry> EnemyEntries = new Dictionary<Type, EnemyConfigEntry>();

		public static ConfigEntry<bool> InsideModdedEnemies;

		public static ConfigEntry<bool> OutsideModdedEnemies;

		public static ConfigEntry<bool> DayTimeModdedEnemies;

		public static ConfigEntry<bool> NightTimeModdedEnemies;

		public static ConfigEntry<bool> UnspecifiedModdedEnemies;

		public static void InitConfig(ConfigFile configFile)
		{
			BuildEnemyEntries(GetAllEnemyTypes());
			GenerateVoiceLineConfig(configFile);
			GenerateMonsterVoicesConfig(configFile);
			GenerateModdedMonsterConfig(configFile);
			GenerateExtraConfig(configFile);
		}

		private static void GenerateVoiceLineConfig(ConfigFile configFile)
		{
			VoiceLineFrequency = configFile.Bind<float>("Voice Settings", "Voice Line Frequency", 1f, $"{1f} is the default, and voice lines will occur every {15f} to {40f} seconds per enemy." + "\nSetting this to 2 means they will occur twice as often, 0.5 means half as often, etc.\nSetting this to 0 disables the mod.");
			SkinwalkerLogger.Log($"VoiceLineFrequency; VALUE LOADED FROM CONFIG: {VoiceLineFrequency.Value}");
		}

		private static void GenerateMonsterVoicesConfig(ConfigFile configFile)
		{
			foreach (EnemyConfigEntry value in EnemyEntries.Values)
			{
				value.SetConfigEntry(configFile, "Monster Voices");
			}
		}

		private static void GenerateModdedMonsterConfig(ConfigFile configFile)
		{
			InsideModdedEnemies = configFile.Bind<bool>("Monster Voices", "Modded Enemies (Inside)", true, (ConfigDescription)null);
			OutsideModdedEnemies = configFile.Bind<bool>("Monster Voices", "Modded Enemies (Outside)", true, (ConfigDescription)null);
			DayTimeModdedEnemies = configFile.Bind<bool>("Monster Voices", "Modded Enemies (Day Time)", false, (ConfigDescription)null);
			NightTimeModdedEnemies = configFile.Bind<bool>("Monster Voices", "Modded Enemies (Night Time)", true, (ConfigDescription)null);
			UnspecifiedModdedEnemies = configFile.Bind<bool>("Monster Voices", "Modded Enemies (Unspecified)", true, (ConfigDescription)null);
		}

		private static void GenerateExtraConfig(ConfigFile configFile)
		{
			KeepFilesBetweenSessions = configFile.Bind<bool>("Extra Settings", "Keep Files Between Sessions", false, "If set to true, the content of Dissonance_Diagnostics won't be deleted on boot, keeping remaining sound files from previous sessions.");
			SkinwalkerLogger.Log($"KeepFilesBetweenSessions; VALUE LOADED FROM CONFIG: {KeepFilesBetweenSessions.Value}");
			TimeForFileCaching = configFile.Bind<float>("Extra Settings", "Time For File Caching", 8f, "Dictates the interval (in seconds) at which we collect player recordings. Once recordings are collected, they're immediately deleted.\nA higher number would increase the likelyhood of clips remaining for future sessions." + $"\nValues under the default {8f} seconds will be ignored.");
			SkinwalkerLogger.Log($"TimeForFileCaching; VALUE LOADED FROM CONFIG: {TimeForFileCaching.Value}");
			AddCustomFiles = configFile.Bind<bool>("Extra Settings", "Add custom sounds", false, "If set to true, will create a folder Custom_Sounds in which you can put your own audio files.\nNote that other players won't be able to hear these sounds, only you, therefore the folder content should be shared between players.\nUnlike the recorded voice lines, these files won't be deleted.");
			SkinwalkerLogger.Log($"AddCustomFiles; VALUE LOADED FROM CONFIG: {AddCustomFiles.Value}");
			CustomSoundFrequency = configFile.Bind<float>("Extra Settings", "Custom sounds frequency", 50f, $"Value between {0} and {100}. Dictates the frequency at which to play custom sounds vs recorded lines." + $"\nIf set to {0}, only the recorded lines will play, deactivating the previous option." + $"\nIf set to {100}, only the custom sounds will play, disabling the voice line recording.");
			SkinwalkerLogger.Log($"CustomSoundFrequency; VALUE LOADED FROM CONFIG: {CustomSoundFrequency.Value}");
		}

		private static void BuildEnemyEntries(List<Type> enemyTypes)
		{
			foreach (Type enemyType in enemyTypes)
			{
				EnemyEntries.Add(enemyType, new EnemyConfigEntry(enemyType));
			}
		}

		private static List<Type> GetAllEnemyTypes()
		{
			List<Type> list = new List<Type>();
			Assembly assembly;
			try
			{
				assembly = Assembly.Load("Assembly-CSharp");
			}
			catch (Exception ex)
			{
				SkinwalkerLogger.LogError("Couldn't load Assembly-CSharp. Exception:");
				SkinwalkerLogger.LogError(ex.Message);
				return list;
			}
			Type[] types = assembly.GetTypes();
			Type[] array = types;
			foreach (Type type in array)
			{
				if (typeof(EnemyAI).IsAssignableFrom(type) && !(type == typeof(TestEnemy)) && !(type == typeof(EnemyAI)))
				{
					list.Add(type);
				}
			}
			return list;
		}
	}
	public static class SkinwalkerLogger
	{
		internal static ManualLogSource logSource;

		public static void Initialize(string modGUID)
		{
			logSource = Logger.CreateLogSource(modGUID);
		}

		public static void Log(object message)
		{
			logSource.LogInfo(message);
		}

		public static void LogError(object message)
		{
			logSource.LogError(message);
		}

		public static void LogWarning(object message)
		{
			logSource.LogWarning(message);
		}
	}
	public class SkinwalkerModPersistent : MonoBehaviour
	{
		private const int MAX_CACHED_AUDIO = 200;

		private List<AudioClip> cachedRecordedAudio = new List<AudioClip>();

		private List<AudioClip> cachedCustomAudio = new List<AudioClip>();

		private RoundManager roundManager;

		private bool isCleaningAudioCache;

		private string recordedAudioFolderPath;

		private string customAudioFolderPath;

		private bool recordedFolderCreated;

		private bool customFolderCreated;

		private int skinwalkerCheckedCount;

		private float folderScanRate;

		private float nextTimeToCheckFolder;

		public static SkinwalkerModPersistent Instance { get; private set; }

		private bool IsVoiceRecordingEnabled => !SkinwalkerConfig.AddCustomFiles.Value || !(SkinwalkerConfig.CustomSoundFrequency.Value >= 100f);

		private bool AreCustomSoundsEnabled => SkinwalkerConfig.AddCustomFiles.Value && SkinwalkerConfig.CustomSoundFrequency.Value > 0f;

		private void Awake()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			else if ((Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
			}
			SkinwalkerLogger.Log("SkinwalkerModPersistent Initialized");
			SkinwalkerLogger.Log($"IsVoiceRecordingEnabled {IsVoiceRecordingEnabled}");
			SkinwalkerLogger.Log($"AreCustomSoundsEnabled {AreCustomSoundsEnabled}");
			((Component)this).transform.position = Vector3.zero;
			recordedAudioFolderPath = Path.Combine(Application.dataPath, "..", "Dissonance_Diagnostics");
			customAudioFolderPath = Path.Combine(Application.dataPath, "..", "Custom_Sounds");
			InitializeAudioFolders();
			folderScanRate = Mathf.Max(8f, SkinwalkerConfig.TimeForFileCaching.Value);
			if (IsVoiceRecordingEnabled)
			{
				EnableRecording();
			}
		}

		private void Update()
		{
			if ((!IsVoiceRecordingEnabled || recordedFolderCreated) && (!AreCustomSoundsEnabled || customFolderCreated))
			{
				if (IsVoiceRecordingEnabled && Time.realtimeSinceStartup > nextTimeToCheckFolder)
				{
					nextTimeToCheckFolder = Time.realtimeSinceStartup + folderScanRate;
					ScanThenCacheWavFiles(recordedAudioFolderPath, cachedRecordedAudio, deleteAfterCaching: true);
				}
				HandleRoundManagerState();
				HandleSkinwalkerBehaviour();
			}
		}

		private void OnApplicationQuit()
		{
			DisableRecording();
			if (!SkinwalkerConfig.KeepFilesBetweenSessions.Value && Directory.Exists(recordedAudioFolderPath))
			{
				Directory.Delete(recordedAudioFolderPath, recursive: true);
			}
		}

		private void HandleRoundManagerState()
		{
			if ((Object)(object)roundManager == (Object)null && (Object)(object)RoundManager.Instance != (Object)null)
			{
				roundManager = RoundManager.Instance;
				skinwalkerCheckedCount = RoundManager.Instance.SpawnedEnemies.Count;
			}
		}

		private void HandleSkinwalkerBehaviour()
		{
			if ((Object)(object)RoundManager.Instance == (Object)null)
			{
				return;
			}
			int count = RoundManager.Instance.SpawnedEnemies.Count;
			if (skinwalkerCheckedCount == count)
			{
				return;
			}
			if (skinwalkerCheckedCount < count)
			{
				SkinwalkerBehaviour skinwalkerBehaviour = default(SkinwalkerBehaviour);
				foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies)
				{
					if (IsEnemyEnabled(spawnedEnemy) && !((Component)spawnedEnemy).TryGetComponent<SkinwalkerBehaviour>(ref skinwalkerBehaviour))
					{
						((Component)spawnedEnemy).gameObject.AddComponent<SkinwalkerBehaviour>().Initialize(spawnedEnemy);
					}
				}
			}
			skinwalkerCheckedCount = count;
		}

		private void InitializeAudioFolders()
		{
			if (IsVoiceRecordingEnabled)
			{
				if (!Directory.Exists(recordedAudioFolderPath))
				{
					Directory.CreateDirectory(recordedAudioFolderPath);
				}
				else if (!SkinwalkerConfig.KeepFilesBetweenSessions.Value)
				{
					Directory.Delete(recordedAudioFolderPath, recursive: true);
					Directory.CreateDirectory(recordedAudioFolderPath);
				}
			}
			if (AreCustomSoundsEnabled && !Directory.Exists(customAudioFolderPath))
			{
				Directory.CreateDirectory(customAudioFolderPath);
			}
			((MonoBehaviour)this).StartCoroutine(CheckForFolderCreation());
		}

		private IEnumerator CheckForFolderCreation()
		{
			while (IsVoiceRecordingEnabled && !recordedFolderCreated)
			{
				recordedFolderCreated = Directory.Exists(recordedAudioFolderPath);
				if (!recordedFolderCreated)
				{
					yield return (object)new WaitForSecondsRealtime(1f);
				}
			}
			while (AreCustomSoundsEnabled && !customFolderCreated)
			{
				customFolderCreated = Directory.Exists(customAudioFolderPath);
				if (customFolderCreated)
				{
					ScanThenCacheWavFiles(customAudioFolderPath, cachedCustomAudio, deleteAfterCaching: false);
				}
				else
				{
					yield return (object)new WaitForSecondsRealtime(1f);
				}
			}
		}

		private void EnableRecording()
		{
			DebugSettings.Instance.EnablePlaybackDiagnostics = true;
			DebugSettings.Instance.RecordFinalAudio = true;
		}

		private void ScanThenCacheWavFiles(string path, List<AudioClip> cacheList, bool deleteAfterCaching)
		{
			string[] files = Directory.GetFiles(path);
			if (files.Length != 0)
			{
				((MonoBehaviour)this).StartCoroutine(CacheWavFile(files, cacheList, deleteAfterCaching));
			}
		}

		private bool IsEnemyEnabled(EnemyAI enemy)
		{
			if ((Object)(object)enemy == (Object)null)
			{
				SkinwalkerLogger.LogError("enemy was null");
				return false;
			}
			if (SkinwalkerNetworkManager.Instance.NetworkVariablesDict.TryGetValue(((object)enemy).GetType(), out var value))
			{
				return value.Value;
			}
			if ((Object)(object)enemy.enemyType != (Object)null)
			{
				if (enemy.enemyType.isOutsideEnemy && !SkinwalkerNetworkManager.Instance.OutsideModdedEnemies.Value)
				{
					return false;
				}
				if (!enemy.enemyType.isOutsideEnemy && !SkinwalkerNetworkManager.Instance.InsideModdedEnemies.Value)
				{
					return false;
				}
				if (enemy.enemyType.isDaytimeEnemy && !SkinwalkerNetworkManager.Instance.DayTimeModdedEnemies.Value)
				{
					return false;
				}
				if (!enemy.enemyType.isDaytimeEnemy && !SkinwalkerNetworkManager.Instance.NightTimeModdedEnemies.Value)
				{
					return false;
				}
				return true;
			}
			return SkinwalkerNetworkManager.Instance.UnspecifiedModdedEnemies.Value;
		}

		private IEnumerator CacheWavFile(string[] paths, List<AudioClip> referencedList, bool deleteAfterCaching)
		{
			foreach (string path in paths)
			{
				UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, (AudioType)20);
				yield return request.SendWebRequest();
				while ((int)request.result == 0)
				{
					yield return null;
				}
				if ((int)request.result != 1)
				{
					SkinwalkerLogger.LogWarning($"Request failed for file at path: {path}\n Request Result: {request.result}");
					continue;
				}
				AudioClip audioClip = DownloadHandlerAudioClip.GetContent(request);
				if (!deleteAfterCaching || audioClip.length > 0.9f)
				{
					referencedList.Add(audioClip);
				}
				if (deleteAfterCaching)
				{
					File.Delete(path);
				}
				request.Dispose();
			}
			if (!isCleaningAudioCache && cachedRecordedAudio.Count > 200)
			{
				((MonoBehaviour)this).StartCoroutine(CleanAudioCache());
			}
		}

		private void DisableRecording()
		{
			DebugSettings.Instance.EnablePlaybackDiagnostics = false;
			DebugSettings.Instance.RecordFinalAudio = false;
		}

		public bool TryGetSample(out AudioClip audioClip)
		{
			audioClip = null;
			bool flag;
			List<AudioClip> list;
			if (IsVoiceRecordingEnabled && AreCustomSoundsEnabled)
			{
				float num = Random.Range(0, 101);
				flag = num > SkinwalkerConfig.CustomSoundFrequency.Value;
				list = (flag ? cachedRecordedAudio : cachedCustomAudio);
			}
			else if (IsVoiceRecordingEnabled)
			{
				list = cachedRecordedAudio;
				flag = true;
			}
			else
			{
				list = cachedCustomAudio;
				flag = false;
			}
			if (list.Count == 0)
			{
				return false;
			}
			int index = Random.Range(0, list.Count);
			audioClip = list[index];
			if (flag)
			{
				list.RemoveAt(index);
			}
			if ((Object)(object)audioClip == (Object)null)
			{
				SkinwalkerLogger.LogWarning("TryGetSample.audioClip was null");
				return false;
			}
			return true;
		}

		private IEnumerator CleanAudioCache()
		{
			isCleaningAudioCache = true;
			while (cachedRecordedAudio.Count > 200)
			{
				cachedRecordedAudio.RemoveAt(Random.Range(0, cachedRecordedAudio.Count));
				yield return null;
			}
			isCleaningAudioCache = false;
		}

		public void ClearCache()
		{
			cachedRecordedAudio.Clear();
		}
	}
	public class SkinwalkerNetworkManager : NetworkBehaviour
	{
		public Dictionary<Type, NetworkVariable<bool>> NetworkVariablesDict = new Dictionary<Type, NetworkVariable<bool>>();

		public NetworkVariable<bool> InsideModdedEnemies;

		public NetworkVariable<bool> OutsideModdedEnemies;

		public NetworkVariable<bool> DayTimeModdedEnemies;

		public NetworkVariable<bool> NightTimeModdedEnemies;

		public NetworkVariable<bool> UnspecifiedModdedEnemies;

		public NetworkVariable<float> VoiceLineFrequency;

		private readonly NetworkVariableReadPermission readPermission = (NetworkVariableReadPermission)0;

		private readonly NetworkVariableWritePermission writePermission = (NetworkVariableWritePermission)0;

		public static SkinwalkerNetworkManager Instance { get; private set; }

		private void Awake()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			SkinwalkerLogger.Log("SkinwalkerNetworkManager Awake Called");
			if ((Object)(object)Instance == (Object)null)
			{
				SkinwalkerLogger.Log("SkinwalkerNetworkManager Instance set");
				Instance = this;
			}
			else if ((Object)(object)Instance != (Object)(object)this)
			{
				SkinwalkerLogger.Log("SkinwalkerNetworkManager Destroying duplicate NetworkManager...");
				Object.Destroy((Object)(object)this);
				return;
			}
			InsideModdedEnemies = new NetworkVariable<bool>(true, readPermission, writePermission);
			OutsideModdedEnemies = new NetworkVariable<bool>(true, readPermission, writePermission);
			DayTimeModdedEnemies = new NetworkVariable<bool>(false, readPermission, writePermission);
			NightTimeModdedEnemies = new NetworkVariable<bool>(true, readPermission, writePermission);
			UnspecifiedModdedEnemies = new NetworkVariable<bool>(true, readPermission, writePermission);
			VoiceLineFrequency = new NetworkVariable<float>(1f, readPermission, writePermission);
			BuildNetworkVariableDict();
		}

		public override void OnDestroy()
		{
			SkinwalkerLogger.Log("SkinwalkerNetworkManager OnDestroy");
			if ((Object)(object)SkinwalkerModPersistent.Instance != (Object)null)
			{
				SkinwalkerModPersistent.Instance.ClearCache();
			}
			Instance = null;
			((NetworkBehaviour)this).OnDestroy();
		}

		public override void OnNetworkSpawn()
		{
			SkinwalkerLogger.Log("OnNetworkSpawn");
			SetupConfig();
		}

		protected override void __initializeVariables()
		{
			SkinwalkerLogger.Log("called __initializeVariables");
			if (!TryInitializeNetworkVariables() || !TryInitializeEnemyNetworkVariables())
			{
				SkinwalkerLogger.LogError("NetworkManager Initialization failed");
			}
		}

		protected override string __getTypeName()
		{
			return "SkinwalkerNetworkManager";
		}

		private void BuildNetworkVariableDict()
		{
			foreach (EnemyConfigEntry value2 in SkinwalkerConfig.EnemyEntries.Values)
			{
				NetworkVariable<bool> value = new NetworkVariable<bool>(true, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);
				NetworkVariablesDict.Add(value2.EnemyType, value);
			}
		}

		private bool TryInitializeNetworkVariables()
		{
			if (VoiceLineFrequency == null)
			{
				SkinwalkerLogger.LogError("SkinwalkerNetworkManager.VoiceLineFrequency cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			if (InsideModdedEnemies == null)
			{
				SkinwalkerLogger.LogError("SkinwalkerNetworkManager.InsideModdedEnemies cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			if (OutsideModdedEnemies == null)
			{
				SkinwalkerLogger.LogError("SkinwalkerNetworkManager.OutsideModdedEnemies cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			if (DayTimeModdedEnemies == null)
			{
				SkinwalkerLogger.LogError("SkinwalkerNetworkManager.DayTimeModdedEnemies cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			if (NightTimeModdedEnemies == null)
			{
				SkinwalkerLogger.LogError("SkinwalkerNetworkManager.NightTimeModdedEnemies cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			if (UnspecifiedModdedEnemies == null)
			{
				SkinwalkerLogger.LogError("SkinwalkerNetworkManager.UnspecifiedModdedEnemies cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			if (VoiceLineFrequency == null || InsideModdedEnemies == null || OutsideModdedEnemies == null || DayTimeModdedEnemies == null || NightTimeModdedEnemies == null || UnspecifiedModdedEnemies == null)
			{
				return false;
			}
			((NetworkVariableBase)VoiceLineFrequency).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)VoiceLineFrequency, "VoiceLineFrequency");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)VoiceLineFrequency);
			((NetworkVariableBase)InsideModdedEnemies).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)InsideModdedEnemies, "VoiceEnabled_InsideModdedEnemies");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)InsideModdedEnemies);
			((NetworkVariableBase)OutsideModdedEnemies).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)OutsideModdedEnemies, "VoiceEnabled_OutsideModdedEnemies");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)OutsideModdedEnemies);
			((NetworkVariableBase)DayTimeModdedEnemies).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)DayTimeModdedEnemies, "VoiceEnabled_DayTimeModdedEnemies");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)DayTimeModdedEnemies);
			((NetworkVariableBase)NightTimeModdedEnemies).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)NightTimeModdedEnemies, "VoiceEnabled_NightTimeModdedEnemies");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)NightTimeModdedEnemies);
			((NetworkVariableBase)UnspecifiedModdedEnemies).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)UnspecifiedModdedEnemies, "VoiceEnabled_UnspecifiedModdedEnemies");
			base.NetworkVariableFields.Add((NetworkVariableBase)(object)UnspecifiedModdedEnemies);
			return true;
		}

		private bool TryInitializeEnemyNetworkVariables()
		{
			foreach (EnemyConfigEntry value in SkinwalkerConfig.EnemyEntries.Values)
			{
				if (NetworkVariablesDict[value.EnemyType] == null)
				{
					SkinwalkerLogger.LogError("SkinwalkerNetworkManager.NetworkVariables.Key:" + value.EnemyType.Name + " cannot be null. All NetworkVariableBase instances must be initialized.");
					return false;
				}
				((NetworkVariableBase)NetworkVariablesDict[value.EnemyType]).Initialize((NetworkBehaviour)(object)this);
				((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)NetworkVariablesDict[value.EnemyType], "VoiceEnabled_" + value.cleanedName);
				base.NetworkVariableFields.Add((NetworkVariableBase)(object)NetworkVariablesDict[value.EnemyType]);
			}
			return true;
		}

		private void SetupConfig()
		{
			SkinwalkerLogger.Log("SetupConfig");
			if (GameNetworkManager.Instance.isHostingGame)
			{
				SkinwalkerLogger.Log("HOST SENDING CONFIG TO CLIENTS...");
				VoiceLineFrequency.Value = SkinwalkerConfig.VoiceLineFrequency.Value;
				InsideModdedEnemies.Value = SkinwalkerConfig.InsideModdedEnemies.Value;
				OutsideModdedEnemies.Value = SkinwalkerConfig.OutsideModdedEnemies.Value;
				DayTimeModdedEnemies.Value = SkinwalkerConfig.DayTimeModdedEnemies.Value;
				NightTimeModdedEnemies.Value = SkinwalkerConfig.NightTimeModdedEnemies.Value;
				UnspecifiedModdedEnemies.Value = SkinwalkerConfig.UnspecifiedModdedEnemies.Value;
				SkinwalkerLogger.Log("Entering foreach");
				foreach (EnemyConfigEntry value in SkinwalkerConfig.EnemyEntries.Values)
				{
					if (NetworkVariablesDict[value.EnemyType] == null)
					{
						SkinwalkerLogger.LogError("SkinwalkerNetworkManager.NetworkVariables.Key:" + value.EnemyType.Name + " was null");
						return;
					}
					NetworkVariablesDict[value.EnemyType].Value = value.configEntry.Value;
				}
				SkinwalkerLogger.Log("CONFIG SENT...");
			}
			else
			{
				SkinwalkerLogger.Log("Not the host, no config to send");
			}
		}
	}
	public class SkinwalkerNetworkManagerHandler
	{
		private static GameObject networkManagerInstance;

		private static bool initializationSuccessful;

		public static bool TryClientConnectInitializer(Scene sceneName)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			initializationSuccessful = false;
			ClientConnectInitializer(sceneName, (LoadSceneMode)0);
			return initializationSuccessful;
		}

		public static void ClientConnectInitializer(Scene sceneName, LoadSceneMode _)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (((Scene)(ref sceneName)).name == "SampleSceneRelay")
			{
				networkManagerInstance = new GameObject("SkinwalkerNetworkManager");
				networkManagerInstance.AddComponent<NetworkObject>();
				networkManagerInstance.AddComponent<SkinwalkerNetworkManager>();
				((Object)networkManagerInstance).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)networkManagerInstance);
				initializationSuccessful = true;
				SkinwalkerLogger.Log("Initialized SkinwalkerNetworkManager");
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "lynxdev.OptimizedSkinwalkers";

		public const string PLUGIN_NAME = "lynxdev.OptimizedSkinwalkers";

		public const string PLUGIN_VERSION = "2.1.1";
	}
}