Decompiled source of RavenwoodColosseum v1.0.1

plugins/RavenwoodColosseum/RavenwoodColosseum.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
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: AssemblyTitle("BalrondRavenwoodRome")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BalrondRavenwoodRome")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("cde312a0-cf19-4264-8616-e1c74774beed")]
[assembly: AssemblyFileVersion("1.1.9.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.9.0")]
[module: UnverifiableCode]
namespace BalrondRavenwoodRome
{
	internal static class BuildPieceList
	{
		public static readonly string[] buildPieces = PieceCatalog.GetPrefabNames();
	}
	internal static class ServerSyncBridge
	{
		private static object _syncObject;

		internal static void Initialize(string pluginGuid, string displayName, string version)
		{
			ConfigSync syncObject = new ConfigSync(pluginGuid)
			{
				DisplayName = displayName,
				CurrentVersion = version,
				MinimumRequiredVersion = version
			};
			_syncObject = syncObject;
		}

		internal static void AddLockingConfigEntry(ConfigEntry<bool> entry)
		{
			GetSync().AddLockingConfigEntry<bool>(entry);
		}

		internal static void AddConfigEntry<T>(ConfigEntry<T> entry)
		{
			SyncedConfigEntry<T> syncedConfigEntry = GetSync().AddConfigEntry<T>(entry);
			syncedConfigEntry.SynchronizedConfig = true;
		}

		internal static void Reset()
		{
			_syncObject = null;
		}

		private static ConfigSync GetSync()
		{
			if (!(_syncObject is ConfigSync result))
			{
				throw new InvalidOperationException("ServerSyncBridge was used before successful initialization.");
			}
			return result;
		}
	}
	internal static class BalrondHashCompat
	{
		public static int StableHash(string value)
		{
			if (value == null)
			{
				return 0;
			}
			return StringExtensionMethods.GetStableHashCode(value);
		}
	}
	public sealed class FxReplacment
	{
		private readonly Dictionary<string, GameObject> _prefabsByName = new Dictionary<string, GameObject>(StringComparer.Ordinal);

		public void SetInstance(List<GameObject> prefabs)
		{
			_prefabsByName.Clear();
			if (prefabs == null)
			{
				return;
			}
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i];
				if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name) && !_prefabsByName.ContainsKey(((Object)val).name))
				{
					_prefabsByName.Add(((Object)val).name, val);
				}
			}
		}

		public void ReplaceOnPiece(GameObject gameObject)
		{
			if (!((Object)(object)gameObject == (Object)null))
			{
				Piece component = gameObject.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					ReplaceEffectList(component.m_placeEffect);
				}
				WearNTear component2 = gameObject.GetComponent<WearNTear>();
				if ((Object)(object)component2 != (Object)null)
				{
					ReplaceEffectList(component2.m_hitEffect);
					ReplaceEffectList(component2.m_destroyedEffect);
					ReplaceEffectList(component2.m_switchEffect);
				}
				Destructible component3 = gameObject.GetComponent<Destructible>();
				if ((Object)(object)component3 != (Object)null)
				{
					ReplaceEffectList(component3.m_hitEffect);
					ReplaceEffectList(component3.m_destroyedEffect);
				}
				SpawnArea component4 = gameObject.GetComponent<SpawnArea>();
				if ((Object)(object)component4 != (Object)null)
				{
					ReplaceEffectList(component4.m_spawnEffects);
				}
				CraftingStation component5 = gameObject.GetComponent<CraftingStation>();
				if ((Object)(object)component5 != (Object)null)
				{
					ReplaceEffectList(component5.m_craftItemEffects);
					ReplaceEffectList(component5.m_craftItemDoneEffects);
					ReplaceEffectList(component5.m_repairItemDoneEffects);
				}
			}
		}

		private void ReplaceEffectList(EffectList effectList)
		{
			if (effectList != null)
			{
				ReplaceEffects(effectList.m_effectPrefabs);
			}
		}

		private void ReplaceEffects(EffectData[] effects)
		{
			if (effects == null || effects.Length == 0)
			{
				return;
			}
			foreach (EffectData val in effects)
			{
				if (val != null && !((Object)(object)val.m_prefab == (Object)null) && !string.IsNullOrEmpty(((Object)val.m_prefab).name) && _prefabsByName.TryGetValue(((Object)val.m_prefab).name, out var value) && (Object)(object)value != (Object)null && value != val.m_prefab)
				{
					val.m_prefab = value;
				}
			}
		}
	}
	public sealed class ModResourceLoader
	{
		private static readonly FieldInfo ObjectDbBuildPiecesField = typeof(ObjectDB).GetField("m_buildPieces", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static bool _loggedMissingObjectDbBuildPiecesField;

		private static readonly string[] HammerNames = new string[4] { "Hammer", "HammerIron", "HammerDverger", "HammerBlackmetal" };

		private readonly PrefabLookupCache _scenePrefabCache = new PrefabLookupCache();

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

		private readonly Dictionary<string, string> _bundlePrefabPaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private bool _sceneRegistrationCompleted;

		public readonly List<GameObject> BuildPrefabs = new List<GameObject>();

		public readonly List<GameObject> RegisteredBuildPrefabs = new List<GameObject>();

		public AssetBundle AssetBundle { get; private set; }

		public void LoadAssets()
		{
			BuildPrefabs.Clear();
			RegisteredBuildPrefabs.Clear();
			_bundlePrefabPaths.Clear();
			_sceneRegistrationCompleted = false;
			AssetBundle = GetAssetBundleFromResources("balrondrome");
			if ((Object)(object)AssetBundle == (Object)null)
			{
				return;
			}
			CacheBundlePrefabPaths();
			string[] prefabNames = PieceCatalog.GetPrefabNames();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			List<string> list = new List<string>();
			foreach (string text in prefabNames)
			{
				if (string.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				if (!hashSet.Add(text))
				{
					if (Launch.Log != null)
					{
						Launch.Log.LogWarning((object)("Duplicate piece catalog entry ignored: " + text));
					}
					continue;
				}
				GameObject val = LoadPiecePrefab(text);
				if ((Object)(object)val == (Object)null)
				{
					list.Add(text);
					continue;
				}
				ShaderReplacment.Replace(val);
				BuildPrefabs.Add(val);
			}
			if (Launch.Log != null)
			{
				Launch.Log.LogInfo((object)("Asset loading finished: requested=" + prefabNames.Length + ", loaded=" + BuildPrefabs.Count + ", missing=" + list.Count + "."));
				if (list.Count > 0)
				{
					Launch.Log.LogWarning((object)("AssetBundle is missing build prefab(s): " + string.Join(", ", list.ToArray())));
				}
			}
		}

		public void AddPrefabsToZNetScene(ZNetScene scene)
		{
			if ((Object)(object)scene == (Object)null || scene.m_prefabs == null)
			{
				return;
			}
			RegisteredBuildPrefabs.Clear();
			_scenePrefabCache.Rebuild(scene.m_prefabs);
			RebuildSceneHashCache(scene.m_prefabs);
			for (int i = 0; i < BuildPrefabs.Count; i++)
			{
				GameObject val = BuildPrefabs[i];
				if (RegisterPrefab(val, scene))
				{
					RegisteredBuildPrefabs.Add(val);
				}
			}
			_sceneRegistrationCompleted = true;
		}

		public void FinalizeZNetSceneSetup(ZNetScene scene)
		{
			if (!((Object)(object)scene == (Object)null) && scene.m_prefabs != null)
			{
				_scenePrefabCache.Rebuild(scene.m_prefabs);
				RefreshRegisteredBuildPrefabs(scene.m_prefabs);
				SetupBuildPiecesList(scene);
				SetupBuildPiecesListDB();
				SetupRavenGuides(scene.m_prefabs);
			}
		}

		public void SetupBuildPiecesListDB()
		{
			ObjectDB instance = ObjectDB.instance;
			if (_sceneRegistrationCompleted && !((Object)(object)instance == (Object)null) && instance.m_items != null)
			{
				GameObject tool = ObjectDbCompat.FindItemPrefab(instance, "Hammer");
				if (TryGetPieceTable(tool, out var pieceTable))
				{
					AddBuildPrefabsToPieceTable(pieceTable, RegisteredBuildPrefabs);
					RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0);
					InvalidateObjectDbBuildPieceCache(instance);
				}
			}
		}

		public bool IsHammerPieceTable(PieceTable pieceTable)
		{
			if ((Object)(object)pieceTable == (Object)null)
			{
				return false;
			}
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			GameObject tool = ObjectDbCompat.FindItemPrefab(instance, "Hammer");
			if (!TryGetPieceTable(tool, out var pieceTable2))
			{
				return false;
			}
			return pieceTable == pieceTable2 || (!string.IsNullOrEmpty(((Object)pieceTable).name) && string.Equals(((Object)pieceTable).name, ((Object)pieceTable2).name, StringComparison.Ordinal));
		}

		public int EnsureRuntimeHammerPieces(PieceTable pieceTable)
		{
			if (!IsHammerPieceTable(pieceTable) || pieceTable.m_pieces == null)
			{
				return 0;
			}
			int count = pieceTable.m_pieces.Count;
			AddBuildPrefabsToPieceTable(pieceTable, RegisteredBuildPrefabs);
			RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0);
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				InvalidateObjectDbBuildPieceCache(ObjectDB.instance);
			}
			return pieceTable.m_pieces.Count - count;
		}

		public IEnumerable<GameObject> EnumerateAudioPrefabs()
		{
			for (int i = 0; i < BuildPrefabs.Count; i++)
			{
				if ((Object)(object)BuildPrefabs[i] != (Object)null)
				{
					yield return BuildPrefabs[i];
				}
			}
		}

		private void CacheBundlePrefabPaths()
		{
			_bundlePrefabPaths.Clear();
			if ((Object)(object)AssetBundle == (Object)null)
			{
				return;
			}
			string[] allAssetNames;
			try
			{
				allAssetNames = AssetBundle.GetAllAssetNames();
			}
			catch (Exception ex)
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogWarning((object)("Could not enumerate AssetBundle paths: " + ex));
				}
				return;
			}
			if (allAssetNames == null)
			{
				return;
			}
			foreach (string text in allAssetNames)
			{
				if (!string.IsNullOrEmpty(text) && text.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
					if (!string.IsNullOrEmpty(fileNameWithoutExtension) && !_bundlePrefabPaths.ContainsKey(fileNameWithoutExtension))
					{
						_bundlePrefabPaths.Add(fileNameWithoutExtension, text);
					}
				}
			}
		}

		private GameObject LoadPiecePrefab(string prefabName)
		{
			if ((Object)(object)AssetBundle == (Object)null || string.IsNullOrWhiteSpace(prefabName))
			{
				return null;
			}
			string assetName = "Assets/Custom/Comission/Rome/Pieces/" + prefabName + ".prefab";
			GameObject val = TryLoadGameObject(assetName);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = TryLoadGameObject(prefabName);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			if (_bundlePrefabPaths.TryGetValue(prefabName, out var value))
			{
				return TryLoadGameObject(value);
			}
			return null;
		}

		private GameObject TryLoadGameObject(string assetName)
		{
			if ((Object)(object)AssetBundle == (Object)null || string.IsNullOrEmpty(assetName))
			{
				return null;
			}
			try
			{
				return AssetBundle.LoadAsset<GameObject>(assetName);
			}
			catch
			{
				return null;
			}
		}

		private AssetBundle GetAssetBundleFromResources(string filename)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			string text = null;
			for (int i = 0; i < manifestResourceNames.Length; i++)
			{
				if (manifestResourceNames[i].EndsWith(filename, StringComparison.OrdinalIgnoreCase))
				{
					text = manifestResourceNames[i];
					break;
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogError((object)("Embedded AssetBundle resource not found: " + filename));
				}
				return null;
			}
			using Stream stream = executingAssembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				return null;
			}
			AssetBundle val = AssetBundle.LoadFromStream(stream);
			if ((Object)(object)val == (Object)null && Launch.Log != null)
			{
				Launch.Log.LogError((object)("AssetBundle.LoadFromStream returned null for " + text + "."));
			}
			return val;
		}

		private void RebuildSceneHashCache(List<GameObject> prefabs)
		{
			_sceneHashNames.Clear();
			if (prefabs == null)
			{
				return;
			}
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i];
				if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(((Object)val).name))
				{
					continue;
				}
				int key = BalrondHashCompat.StableHash(((Object)val).name);
				if (_sceneHashNames.TryGetValue(key, out var value))
				{
					if (value != ((Object)val).name && Launch.Log != null)
					{
						Launch.Log.LogError((object)("Existing ZNetScene stable-hash collision: '" + value + "' and '" + ((Object)val).name + "'."));
					}
				}
				else
				{
					_sceneHashNames.Add(key, ((Object)val).name);
				}
			}
		}

		private bool RegisterPrefab(GameObject prefab, ZNetScene scene)
		{
			if ((Object)(object)prefab == (Object)null || string.IsNullOrEmpty(((Object)prefab).name) || (Object)(object)scene == (Object)null || scene.m_prefabs == null)
			{
				return false;
			}
			GameObject val = _scenePrefabCache.Find(((Object)prefab).name, scene.m_prefabs);
			if ((Object)(object)val != (Object)null)
			{
				if (val == prefab)
				{
					return true;
				}
				if (Launch.Log != null)
				{
					Launch.Log.LogWarning((object)("Prefab name conflict for '" + ((Object)prefab).name + "'. Existing game/mod prefab wins."));
				}
				return false;
			}
			int key = BalrondHashCompat.StableHash(((Object)prefab).name);
			if (_sceneHashNames.TryGetValue(key, out var value))
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogError((object)("Cannot register prefab '" + ((Object)prefab).name + "': stable hash already belongs to '" + value + "'."));
				}
				return false;
			}
			scene.m_prefabs.Add(prefab);
			_scenePrefabCache.Remember(prefab);
			_sceneHashNames[key] = ((Object)prefab).name;
			return true;
		}

		private void RefreshRegisteredBuildPrefabs(List<GameObject> scenePrefabs)
		{
			RegisteredBuildPrefabs.Clear();
			if (scenePrefabs == null)
			{
				return;
			}
			for (int i = 0; i < BuildPrefabs.Count; i++)
			{
				GameObject val = BuildPrefabs[i];
				if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name))
				{
					GameObject val2 = _scenePrefabCache.Find(((Object)val).name, scenePrefabs);
					if (val2 == val)
					{
						RegisteredBuildPrefabs.Add(val);
					}
				}
			}
		}

		private void SetupBuildPiecesList(ZNetScene scene)
		{
			GameObject tool = _scenePrefabCache.Find("Hammer", scene.m_prefabs);
			if (!TryGetPieceTable(tool, out var pieceTable))
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogError((object)"Hammer PieceTable not found in ZNetScene.");
				}
				return;
			}
			for (int i = 0; i < HammerNames.Length; i++)
			{
				GameObject val = _scenePrefabCache.Find(HammerNames[i], scene.m_prefabs);
				ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
				if (!((Object)(object)val2 == (Object)null) && val2.m_itemData != null && val2.m_itemData.m_shared != null)
				{
					val2.m_itemData.m_shared.m_buildPieces = pieceTable;
				}
			}
			AddBuildPrefabsToPieceTable(pieceTable, RegisteredBuildPrefabs);
			RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0);
		}

		private void SetupRavenGuides(List<GameObject> scenePrefabs)
		{
			if (scenePrefabs == null || RegisteredBuildPrefabs.Count == 0)
			{
				return;
			}
			GameObject val = _scenePrefabCache.Find("piece_workbench", scenePrefabs);
			Transform val2 = (((Object)(object)val != (Object)null) ? val.transform.Find("GuidePoint") : null);
			GuidePoint val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<GuidePoint>() : null);
			GameObject val4 = (((Object)(object)val3 != (Object)null) ? val3.m_ravenPrefab : null);
			if ((Object)(object)val4 == (Object)null)
			{
				return;
			}
			for (int i = 0; i < RegisteredBuildPrefabs.Count; i++)
			{
				GameObject val5 = RegisteredBuildPrefabs[i];
				if (!((Object)(object)val5 == (Object)null))
				{
					Transform val6 = val5.transform.Find("GuidePoint");
					GuidePoint val7 = (((Object)(object)val6 != (Object)null) ? ((Component)val6).GetComponent<GuidePoint>() : null);
					if ((Object)(object)val7 != (Object)null)
					{
						val7.m_ravenPrefab = val4;
					}
				}
			}
		}

		private static bool TryGetPieceTable(GameObject tool, out PieceTable pieceTable)
		{
			pieceTable = null;
			ItemDrop val = (((Object)(object)tool != (Object)null) ? tool.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null)
			{
				return false;
			}
			pieceTable = val.m_itemData.m_shared.m_buildPieces;
			return (Object)(object)pieceTable != (Object)null && pieceTable.m_pieces != null;
		}

		private static void AddBuildPrefabsToPieceTable(PieceTable table, IList<GameObject> prefabs)
		{
			if ((Object)(object)table == (Object)null || table.m_pieces == null || prefabs == null)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			for (int i = 0; i < table.m_pieces.Count; i++)
			{
				GameObject val = table.m_pieces[i];
				if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name))
				{
					hashSet.Add(((Object)val).name);
				}
			}
			for (int j = 0; j < prefabs.Count; j++)
			{
				GameObject val2 = prefabs[j];
				if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(((Object)val2).name) && hashSet.Add(((Object)val2).name))
				{
					table.m_pieces.Add(val2);
				}
			}
		}

		private static void InvalidateObjectDbBuildPieceCache(ObjectDB objectDb)
		{
			if ((Object)(object)objectDb == (Object)null)
			{
				return;
			}
			if (ObjectDbBuildPiecesField == null)
			{
				if (!_loggedMissingObjectDbBuildPiecesField && Launch.Log != null)
				{
					_loggedMissingObjectDbBuildPiecesField = true;
					Launch.Log.LogWarning((object)"ObjectDB.m_buildPieces was not found; build-piece cache invalidation skipped.");
				}
				return;
			}
			try
			{
				ObjectDbBuildPiecesField.SetValue(objectDb, null);
			}
			catch (Exception ex)
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogWarning((object)("Could not invalidate ObjectDB build-piece cache: " + ex));
				}
			}
		}
	}
	internal static class ObjectDbCompat
	{
		public static GameObject FindItemPrefab(ObjectDB objectDb, string prefabName)
		{
			if ((Object)(object)objectDb == (Object)null || objectDb.m_items == null || string.IsNullOrWhiteSpace(prefabName))
			{
				return null;
			}
			string name = prefabName.Trim();
			return objectDb.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && string.Equals(((Object)x).name, name, StringComparison.Ordinal));
		}
	}
	internal static class PieceMetadataCompat
	{
		private const int MaxAuditNames = 24;

		public static void Apply(Piece piece, string prefabName)
		{
			//IL_0029: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null))
			{
				if (piece.m_resources == null)
				{
					piece.m_resources = (Requirement[])(object)new Requirement[0];
				}
				UsageTagFlags val = InferUsageTags(piece, prefabName);
				piece.m_usage |= val;
				RavenwoodBuildMenuCompat.ApplyProviderUsageTag(piece);
				if ((int)piece.m_usage == 0)
				{
					piece.m_usage = (UsageTagFlags)1;
				}
			}
		}

		public static void Audit(IList<GameObject> prefabs)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Invalid comparison between Unknown and I4
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (prefabs == null || Launch.Log == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			List<string> list = new List<string>();
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				num++;
				Piece component = val.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null)
				{
					num2++;
					RememberBadName(list, ((Object)val).name + "[no Piece]");
					continue;
				}
				bool flag = false;
				if (!component.m_enabled)
				{
					num3++;
					flag = true;
				}
				if ((int)component.m_usage == 0)
				{
					num4++;
					flag = true;
				}
				if (!IsValidCategory(component.m_category))
				{
					num5++;
					flag = true;
				}
				if ((Object)(object)component.m_icon == (Object)null)
				{
					num6++;
					flag = true;
				}
				if (flag)
				{
					RememberBadName(list, ((Object)val).name);
				}
			}
			Launch.Log.LogInfo((object)("Build-piece metadata audit: total=" + num + ", noPiece=" + num2 + ", disabled=" + num3 + ", zeroUsage=" + num4 + ", invalidCategory=" + num5 + ", missingIcon=" + num6 + "."));
			if (list.Count > 0)
			{
				Launch.Log.LogWarning((object)("Build-piece metadata requires attention: " + string.Join(", ", list.ToArray())));
			}
		}

		private static UsageTagFlags InferUsageTags(Piece piece, string prefabName)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_01bf: Unknown result type (might be due to invalid IL or missing references)
			UsageTagFlags val = (UsageTagFlags)(UsageFromClassicCategory(piece.m_category) | 4 | 0x40);
			string value = (prefabName ?? ((Object)piece).name ?? string.Empty).ToLowerInvariant();
			if (ContainsAny(value, "wall", "plate_wall"))
			{
				val = (UsageTagFlags)(val | 0x14);
			}
			if (ContainsAny(value, "stair", "step", "ladder", "ramp"))
			{
				val = (UsageTagFlags)(val | 0x20004);
			}
			if (ContainsAny(value, "catwalk", "floor", "platform"))
			{
				val = (UsageTagFlags)(val | 0x4C);
			}
			if (ContainsAny(value, "truss", "column", "beam", "frame", "arch", "colosseum"))
			{
				val = (UsageTagFlags)(val | 0x44);
			}
			if (ContainsAny(value, "door", "gate", "hatch"))
			{
				val = (UsageTagFlags)(val | 0x40044);
			}
			if (ContainsAny(value, "spawner"))
			{
				val = (UsageTagFlags)(val | 0x8001);
			}
			if (ContainsAny(value, "workbench", "forge", "craft", "roller", "smelter", "kiln", "oven", "windmill", "spinning"))
			{
				val = (UsageTagFlags)(val | 2);
			}
			return val;
		}

		private static UsageTagFlags UsageFromClassicCategory(PieceCategory category)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected I4, but got Unknown
			//IL_0061: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			switch ((int)category)
			{
			default:
				if ((int)category == 100)
				{
				}
				break;
			case 1:
				return (UsageTagFlags)2;
			case 2:
			case 3:
				return (UsageTagFlags)4;
			case 4:
				return (UsageTagFlags)128;
			case 6:
				return (UsageTagFlags)16384;
			case 7:
				return (UsageTagFlags)4096;
			case 8:
				return (UsageTagFlags)8192;
			case 0:
				return (UsageTagFlags)1;
			case 5:
				break;
			}
			return (UsageTagFlags)0;
		}

		private static bool IsValidCategory(PieceCategory category)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return RavenwoodBuildMenuCompat.IsKnownCategory(category);
		}

		private static bool ContainsAny(string value, params string[] needles)
		{
			if (string.IsNullOrEmpty(value) || needles == null)
			{
				return false;
			}
			foreach (string value2 in needles)
			{
				if (!string.IsNullOrEmpty(value2) && value.IndexOf(value2, StringComparison.Ordinal) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static void RememberBadName(List<string> names, string name)
		{
			if (names.Count < 24 && !string.IsNullOrEmpty(name))
			{
				names.Add(name);
			}
		}
	}
	internal static class RavenwoodBuildMenuCompat
	{
		internal const string CategoryName = "Ravenwood";

		internal const string CategoryLabelToken = "$jotunn_cat_ravenwood";

		internal const string LegacyBuildMenuGuid = "Azumatt.LegacyBuildMenu";

		internal const string RavenwoodJapanGuid = "JamesJonesTV.RavenwoodJapan";

		internal const string JotunnGuid = "com.jotunn.jotunn";

		internal const string MinimumJotunnVersion = "2.30.1";

		internal const string HammerTimeGuid = "com.maxsch.valheim.HammerTime";

		private static bool _hasCachedCategory;

		private static PieceCategory _cachedCategory;

		private static bool _loggedCategory;

		private static bool _loggedLegacyMirror;

		private static bool _loggedHudExpansion;

		internal static PieceCategory GetOrCreateRavenwoodCategory(PieceCategory fallback)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0034: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PieceCategory? pieceCategory = PieceManager.Instance.GetPieceCategory("Ravenwood");
				PieceCategory val = (pieceCategory.HasValue ? pieceCategory.Value : PieceManager.Instance.AddPieceCategory("Ravenwood"));
				Cache(val);
				return val;
			}
			catch (Exception ex)
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogError((object)("Jotunn Ravenwood category registration failed: " + ex));
				}
				return fallback;
			}
		}

		internal static PieceCategory RefreshRavenwoodCategory(PieceCategory fallback)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			_hasCachedCategory = false;
			return GetOrCreateRavenwoodCategory(fallback);
		}

		internal static bool TryGetResolvedCategory(out PieceCategory category)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected I4, but got Unknown
			category = (PieceCategory)(int)GetOrCreateRavenwoodCategory((PieceCategory)0);
			return _hasCachedCategory;
		}

		internal static void AssignCategory(Piece piece, PieceCategory fallback)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null))
			{
				PieceCategory orCreateRavenwoodCategory = GetOrCreateRavenwoodCategory(fallback);
				piece.m_category = (_hasCachedCategory ? orCreateRavenwoodCategory : fallback);
			}
		}

		internal static void ApplyProviderUsageTag(Piece piece)
		{
		}

		internal static void EnsureCategoryOnPieceTable(PieceTable pieceTable, PieceCategory fallback)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected I4, but got Unknown
			if ((Object)(object)pieceTable == (Object)null)
			{
				return;
			}
			PieceCategory orCreateRavenwoodCategory = GetOrCreateRavenwoodCategory(fallback);
			if (!_hasCachedCategory || pieceTable.m_categories == null || pieceTable.m_categoryLabels == null)
			{
				return;
			}
			int num = pieceTable.m_categories.IndexOf(orCreateRavenwoodCategory);
			if (num < 0)
			{
				pieceTable.m_categories.Add(orCreateRavenwoodCategory);
				pieceTable.m_categoryLabels.Add("$jotunn_cat_ravenwood");
				num = pieceTable.m_categories.Count - 1;
			}
			else
			{
				while (pieceTable.m_categoryLabels.Count <= num)
				{
					pieceTable.m_categoryLabels.Add(string.Empty);
				}
				string text = pieceTable.m_categoryLabels[num];
				if (string.IsNullOrEmpty(text) || string.Equals(text, "Ravenwood", StringComparison.OrdinalIgnoreCase))
				{
					pieceTable.m_categoryLabels[num] = "$jotunn_cat_ravenwood";
				}
			}
			if (!_loggedLegacyMirror && Launch.Log != null)
			{
				_loggedLegacyMirror = true;
				Launch.Log.LogInfo((object)("Ravenwood mirrored into Hammer PieceTable categories (id=" + (int)orCreateRavenwoodCategory + ", index=" + num + ")."));
			}
		}

		internal static void SyncLegacyHudTabs(PieceTable pieceTable)
		{
			if ((Object)(object)pieceTable == (Object)null || (Object)(object)Hud.instance == (Object)null)
			{
				return;
			}
			EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0);
			GameObject[] array = Hud.instance.m_pieceCategoryTabs;
			if (array == null || array.Length == 0)
			{
				return;
			}
			int count = pieceTable.m_categories.Count;
			if (count <= 0)
			{
				return;
			}
			int num = array.Length;
			if (num < count)
			{
				GameObject val = array[0];
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Array.Resize(ref array, count);
				for (int i = num; i < count; i++)
				{
					GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent);
					val2.SetActive(false);
					UIInputHandler val3 = val2.GetComponent<UIInputHandler>();
					if ((Object)(object)val3 == (Object)null)
					{
						val3 = val2.AddComponent<UIInputHandler>();
					}
					UIInputHandler obj = val3;
					obj.m_onLeftDown = (Action<UIInputHandler>)Delegate.Combine(obj.m_onLeftDown, new Action<UIInputHandler>(Hud.instance.OnLeftClickCategory));
					array[i] = val2;
				}
				Hud.instance.m_pieceCategoryTabs = array;
				if (!_loggedHudExpansion && Launch.Log != null)
				{
					_loggedHudExpansion = true;
					Launch.Log.LogInfo((object)("Expanded legacy Hud category tabs from " + num + " to " + count + " for Ravenwood."));
				}
			}
			int num2 = Math.Min(Hud.instance.m_pieceCategoryTabs.Length, Math.Min(pieceTable.m_categories.Count, pieceTable.m_categoryLabels.Count));
			for (int j = 0; j < num2; j++)
			{
				GameObject val4 = Hud.instance.m_pieceCategoryTabs[j];
				if (!((Object)(object)val4 == (Object)null))
				{
					TMP_Text componentInChildren = val4.GetComponentInChildren<TMP_Text>();
					if (!((Object)(object)componentInChildren == (Object)null))
					{
						string text = pieceTable.m_categoryLabels[j];
						componentInChildren.text = ((Localization.instance != null) ? Localization.instance.Localize(text) : ((text == "$jotunn_cat_ravenwood") ? "Ravenwood" : text));
					}
				}
			}
		}

		internal static void RequestCategoryUiRefresh()
		{
			PieceTable val = null;
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				val = Player.m_localPlayer.m_buildPieces;
			}
			if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				try
				{
					val = PieceManager.Instance.GetPieceTable("Hammer");
				}
				catch
				{
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				SyncLegacyHudTabs(val);
			}
		}

		internal unsafe static bool IsKnownCategory(PieceCategory category)
		{
			//IL_000a: 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_0086: Expected I4, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (_hasCachedCategory && ((object)(*(PieceCategory*)(&category))/*cast due to .constrained prefix*/).Equals((object?)_cachedCategory))
			{
				return true;
			}
			try
			{
				PieceCategory? pieceCategory = PieceManager.Instance.GetPieceCategory("Ravenwood");
				if (pieceCategory.HasValue && ((object)pieceCategory.Value/*cast due to .constrained prefix*/).Equals((object?)category))
				{
					Cache(pieceCategory.Value);
					return true;
				}
			}
			catch
			{
			}
			int num = (int)category;
			return num == 100 || (num >= 0 && num < 9);
		}

		internal static string GetProviderDescription()
		{
			return _hasCachedCategory ? "Jotunn PieceManager + legacy PieceTable mirror" : "Jotunn category unresolved";
		}

		private static void Cache(PieceCategory category)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_005d: Expected I4, but got Unknown
			int num;
			if (_hasCachedCategory)
			{
				object obj = category;
				num = ((!((object)Unsafe.As<PieceCategory, PieceCategory>(ref _cachedCategory)/*cast due to .constrained prefix*/).Equals(obj)) ? 1 : 0);
			}
			else
			{
				num = 1;
			}
			bool flag = (byte)num != 0;
			_cachedCategory = category;
			_hasCachedCategory = true;
			if ((flag || !_loggedCategory) && Launch.Log != null)
			{
				_loggedCategory = true;
				Launch.Log.LogInfo((object)("Ravenwood PieceCategory resolved through Jotunn (id=" + (int)category + ")."));
			}
		}
	}
	internal static class RavenwoodJotunnRegistrar
	{
		private static readonly HashSet<string> RegisteredNames = new HashSet<string>(StringComparer.Ordinal);

		internal static void RegisterPieces(IList<GameObject> prefabs)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Expected I4, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			if (prefabs == null)
			{
				return;
			}
			PieceCategory val = PieceManager.Instance.AddPieceCategory("Ravenwood");
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val2 = prefabs[i];
				if ((Object)(object)val2 == (Object)null || string.IsNullOrEmpty(((Object)val2).name))
				{
					num3++;
					continue;
				}
				Piece component = val2.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null)
				{
					num3++;
					if (Launch.Log != null)
					{
						Launch.Log.LogWarning((object)("Jotunn registration skipped prefab without Piece: " + ((Object)val2).name));
					}
					continue;
				}
				component.m_category = val;
				component.m_enabled = true;
				PieceMetadataCompat.Apply(component, ((Object)val2).name);
				if (!RegisteredNames.Add(((Object)val2).name))
				{
					num2++;
					continue;
				}
				CustomPiece piece = PieceManager.Instance.GetPiece(((Object)val2).name);
				if (piece != null)
				{
					if (piece.PiecePrefab == val2)
					{
						piece.PieceTable = PieceTables.Hammer;
						piece.Category = "Ravenwood";
						num2++;
						continue;
					}
					num4++;
					if (Launch.Log != null)
					{
						Launch.Log.LogError((object)("Jotunn already owns a different prefab named '" + ((Object)val2).name + "'. Ravenwood piece was not registered."));
					}
					continue;
				}
				try
				{
					CustomPiece val3 = new CustomPiece(val2, PieceTables.Hammer, false);
					val3.Category = "Ravenwood";
					val3.Usage = null;
					if (PieceManager.Instance.AddPiece(val3))
					{
						num++;
						continue;
					}
					num4++;
					RegisteredNames.Remove(((Object)val2).name);
					if (Launch.Log != null)
					{
						Launch.Log.LogError((object)("Jotunn rejected Ravenwood CustomPiece '" + ((Object)val2).name + "'. Check the preceding Jotunn log for prefab/icon validation details."));
					}
				}
				catch (Exception ex)
				{
					num4++;
					RegisteredNames.Remove(((Object)val2).name);
					if (Launch.Log != null)
					{
						Launch.Log.LogError((object)("Jotunn CustomPiece registration failed for '" + ((Object)val2).name + "': " + ex));
					}
				}
			}
			if (Launch.Log != null)
			{
				Launch.Log.LogInfo((object)("Direct Jotunn Ravenwood registration: categoryId=" + (int)val + ", loaded=" + prefabs.Count + ", added=" + num + ", already=" + num2 + ", skipped=" + num3 + ", failed=" + num4 + "."));
			}
		}
	}
	internal static class RavenwoodCurrencyCompat
	{
		internal const string PluginGuid = "RavenwoodCurrency.rwc";

		private static readonly Dictionary<string, int> CoinValues = new Dictionary<string, int>(StringComparer.Ordinal)
		{
			{ "RWc_Deer", 1 },
			{ "RWc_Bear", 5 },
			{ "RWc_Snake", 10 },
			{ "RWc_Wolf", 25 },
			{ "RWc_Lion", 100 },
			{ "RWc_Raven", 1000 }
		};

		internal static bool TryConvertToVanillaCoins(string prefabName, int amount, out int coinAmount, out string error)
		{
			coinAmount = 0;
			error = null;
			if (string.IsNullOrEmpty(prefabName) || !CoinValues.TryGetValue(prefabName, out var value))
			{
				return false;
			}
			long num = (long)amount * (long)value;
			if (num <= 0 || num > int.MaxValue)
			{
				error = "fallback value for '" + prefabName + "' exceeds Int32.MaxValue";
				return true;
			}
			coinAmount = (int)num;
			return true;
		}

		internal static bool IsKnownCurrencyPrefab(string prefabName)
		{
			return !string.IsNullOrEmpty(prefabName) && CoinValues.ContainsKey(prefabName);
		}

		internal static int GetCoinValue(string prefabName)
		{
			int value;
			return (!string.IsNullOrEmpty(prefabName) && CoinValues.TryGetValue(prefabName, out value)) ? value : 0;
		}
	}
	internal sealed class PrefabLookupCache
	{
		private readonly Dictionary<string, GameObject> _byName = new Dictionary<string, GameObject>(StringComparer.Ordinal);

		private List<GameObject> _source;

		public void Rebuild(List<GameObject> source)
		{
			_source = source;
			_byName.Clear();
			if (source != null)
			{
				for (int i = 0; i < source.Count; i++)
				{
					Remember(source[i]);
				}
			}
		}

		public GameObject Find(string name, List<GameObject> source = null)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			string normalizedName = name.Trim();
			List<GameObject> list = source ?? _source;
			if (source != null && source != _source)
			{
				Rebuild(source);
				list = source;
			}
			if (_byName.TryGetValue(normalizedName, out var value))
			{
				if ((Object)(object)value != (Object)null && ((Object)value).name == normalizedName)
				{
					return value;
				}
				_byName.Remove(normalizedName);
			}
			if (list == null)
			{
				return null;
			}
			GameObject val = list.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == normalizedName);
			if ((Object)(object)val != (Object)null)
			{
				_byName[normalizedName] = val;
			}
			return val;
		}

		public void Remember(GameObject prefab)
		{
			if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrEmpty(((Object)prefab).name) && !_byName.ContainsKey(((Object)prefab).name))
			{
				_byName.Add(((Object)prefab).name, prefab);
			}
		}
	}
	public static class ShaderReplacment
	{
		private sealed class MaterialRegistration
		{
			public string OriginalDummyShaderName;

			public MaterialSnapshot OriginalSnapshot;
		}

		private sealed class MaterialSnapshot
		{
			public string MaterialName;

			public string ShaderName;

			public int RenderQueue;

			public bool HadCustomRenderQueue;

			public MaterialGlobalIlluminationFlags GlobalIlluminationFlags;

			public bool DoubleSidedGI;

			public string[] DiagnosticOriginalKeywords;

			public readonly Dictionary<string, PropertySnapshot> Properties = new Dictionary<string, PropertySnapshot>(StringComparer.Ordinal);
		}

		private sealed class PropertySnapshot
		{
			public string Name;

			public ShaderPropertyType Type;

			public Texture TextureValue;

			public Vector2 TextureScale;

			public Vector2 TextureOffset;

			public float FloatValue;

			public Color ColorValue;

			public Vector4 VectorValue;
		}

		private sealed class ShaderEvidence
		{
			public Shader Shader;

			public int MaterialReferenceCount;

			public int LiveRendererReferenceCount;

			public bool ReturnedByShaderFind;

			public bool IsSupported;

			public int PassCount;

			public int PropertyCount;

			public bool HasRuntimeEvidence => MaterialReferenceCount > 0 || LiveRendererReferenceCount > 0;

			public long Score
			{
				get
				{
					long num = 0L;
					num += (long)LiveRendererReferenceCount * 1000000000L;
					num += (long)MaterialReferenceCount * 1000000L;
					num += (long)PropertyCount * 100L;
					num += (long)PassCount * 10L;
					if (ReturnedByShaderFind)
					{
						num++;
					}
					return num;
				}
			}
		}

		private sealed class ShaderEvidenceSnapshot
		{
			public readonly Dictionary<string, Dictionary<Shader, ShaderEvidence>> ByName = new Dictionary<string, Dictionary<Shader, ShaderEvidence>>(StringComparer.Ordinal);

			public ShaderEvidence GetOrCreate(string shaderName, Shader shader)
			{
				if ((Object)(object)shader == (Object)null || string.IsNullOrEmpty(shaderName))
				{
					return null;
				}
				if (!ByName.TryGetValue(shaderName, out var value))
				{
					value = new Dictionary<Shader, ShaderEvidence>(ShaderReferenceComparer.Instance);
					ByName.Add(shaderName, value);
				}
				if (!value.TryGetValue(shader, out var value2))
				{
					value2 = new ShaderEvidence
					{
						Shader = shader,
						IsSupported = SafeGetIsSupported(shader),
						PassCount = SafeGetPassCount(shader),
						PropertyCount = SafeGetPropertyCount(shader)
					};
					value.Add(shader, value2);
				}
				return value2;
			}
		}

		private sealed class MaterialReferenceComparer : IEqualityComparer<Material>
		{
			public static readonly MaterialReferenceComparer Instance = new MaterialReferenceComparer();

			public bool Equals(Material x, Material y)
			{
				return x == y;
			}

			public int GetHashCode(Material obj)
			{
				return (!((Object)(object)obj == (Object)null)) ? RuntimeHelpers.GetHashCode(obj) : 0;
			}
		}

		private sealed class ShaderReferenceComparer : IEqualityComparer<Shader>
		{
			public static readonly ShaderReferenceComparer Instance = new ShaderReferenceComparer();

			public bool Equals(Shader x, Shader y)
			{
				return x == y;
			}

			public int GetHashCode(Shader obj)
			{
				return (!((Object)(object)obj == (Object)null)) ? RuntimeHelpers.GetHashCode(obj) : 0;
			}
		}

		public static readonly List<GameObject> prefabsToReplaceShader = new List<GameObject>();

		public static readonly List<Material> materialsInPrefabs = new List<Material>();

		public static readonly List<Shader> shaders = new List<Shader>();

		public static bool debug = false;

		public static bool debugShaderDifferences = false;

		public static bool debugTargetOnlyProperties = false;

		public static bool debugShaderCollisions = false;

		public static int maxDifferenceLogsPerShaderPair = 20;

		public static float fallbackCutoff = 0.5f;

		private const float MeaningfulFloatEpsilon = 0.0001f;

		private static readonly Dictionary<string, Shader> ShaderCache = new Dictionary<string, Shader>(StringComparer.Ordinal);

		private static readonly Dictionary<string, Shader> TrustedShaderOverrides = new Dictionary<string, Shader>(StringComparer.Ordinal);

		private static readonly Dictionary<string, List<ShaderEvidence>> LastShaderEvidence = new Dictionary<string, List<ShaderEvidence>>(StringComparer.Ordinal);

		private static readonly HashSet<Material> RegisteredMaterials = new HashSet<Material>(MaterialReferenceComparer.Instance);

		private static readonly Dictionary<Material, MaterialRegistration> MaterialRegistrations = new Dictionary<Material, MaterialRegistration>(MaterialReferenceComparer.Instance);

		private static readonly HashSet<Material> SuccessfullyProcessedMaterials = new HashSet<Material>(MaterialReferenceComparer.Instance);

		private static readonly HashSet<string> AnalysedShaderPairs = new HashSet<string>(StringComparer.Ordinal);

		private static ShaderEvidenceSnapshot CurrentEvidenceSnapshot;

		private static readonly HashSet<string> StrictCutoutShaderNames = new HashSet<string>(StringComparer.Ordinal) { "Custom/Grass", "Custom/Vegetation" };

		private static readonly HashSet<string> ProtectedCutoutStateProperties = new HashSet<string>(StringComparer.Ordinal) { "_Mode", "_Surface", "_Blend", "_SrcBlend", "_DstBlend", "_ZWrite", "_AlphaClip", "_AlphaClipThreshold" };

		public static void Replace(GameObject gameObject)
		{
			if (!IsDedicatedServer() && !((Object)(object)gameObject == (Object)null))
			{
				if (!prefabsToReplaceShader.Contains(gameObject))
				{
					prefabsToReplaceShader.Add(gameObject);
				}
				CollectMaterialsFromPrefab(gameObject);
			}
		}

		public static void GetMaterialsInPrefab(GameObject gameObject)
		{
			CollectMaterialsFromPrefab(gameObject);
		}

		public static void ForceEnableGpuInstancing(GameObject gameObject)
		{
			CollectMaterialsFromPrefab(gameObject);
		}

		public static void LoadShadersFromBundles()
		{
			RefreshShaderCache();
		}

		public static void getMeShaders()
		{
			LoadShadersFromBundles();
		}

		public static void RefreshShaderCache()
		{
			ShaderCache.Clear();
			shaders.Clear();
			LastShaderEvidence.Clear();
			foreach (KeyValuePair<string, Shader> trustedShaderOverride in TrustedShaderOverrides)
			{
				if (!((Object)(object)trustedShaderOverride.Value == (Object)null))
				{
					ShaderCache[trustedShaderOverride.Key] = trustedShaderOverride.Value;
					AddPublicShaderReference(trustedShaderOverride.Value);
				}
			}
			HashSet<string> hashSet = CollectRegisteredTargetShaderNames();
			CurrentEvidenceSnapshot = BuildEvidenceSnapshot(hashSet);
			foreach (string item in hashSet)
			{
				if (!TrustedShaderOverrides.ContainsKey(item))
				{
					Shader val = ResolveShaderByEvidence(item, CurrentEvidenceSnapshot, forceDiagnosticLog: false);
					if (!((Object)(object)val == (Object)null))
					{
						ShaderCache[item] = val;
						AddPublicShaderReference(val);
					}
				}
			}
			if (debug)
			{
				Debug.Log((object)("[BalrondShaderReplacement] Shader cache rebuilt. targets=" + hashSet.Count + ", resolved=" + ShaderCache.Count + ", trustedOverrides=" + TrustedShaderOverrides.Count));
			}
		}

		public static void RegisterTrustedShader(Shader shader)
		{
			if (!((Object)(object)shader == (Object)null) && !string.IsNullOrWhiteSpace(((Object)shader).name))
			{
				RegisterTrustedShader(((Object)shader).name, shader);
			}
		}

		public static void RegisterTrustedShader(string shaderName, Shader shader)
		{
			if (!((Object)(object)shader == (Object)null) && !string.IsNullOrWhiteSpace(shaderName))
			{
				string text = shaderName.Trim();
				TrustedShaderOverrides[text] = shader;
				ShaderCache[text] = shader;
				AddPublicShaderReference(shader);
				if (debug)
				{
					Debug.Log((object)("[BalrondShaderReplacement] Explicit trusted shader '" + text + "', instanceID=" + SafeGetInstanceId((Object)(object)shader) + ", passes=" + SafeGetPassCount(shader) + ", properties=" + SafeGetPropertyCount(shader)));
				}
			}
		}

		public static void RemoveTrustedShader(string shaderName)
		{
			if (!string.IsNullOrWhiteSpace(shaderName))
			{
				string key = shaderName.Trim();
				TrustedShaderOverrides.Remove(key);
				ShaderCache.Remove(key);
			}
		}

		public static Shader GetShaderByName(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			string text = name.Trim();
			if (TrustedShaderOverrides.TryGetValue(text, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (ShaderCache.TryGetValue(text, out var value2) && (Object)(object)value2 != (Object)null)
			{
				return value2;
			}
			HashSet<string> targetNames = new HashSet<string>(StringComparer.Ordinal) { text };
			ShaderEvidenceSnapshot snapshot = BuildEvidenceSnapshot(targetNames);
			Shader val = ResolveShaderByEvidence(text, snapshot, forceDiagnosticLog: false);
			if ((Object)(object)val != (Object)null)
			{
				ShaderCache[text] = val;
				AddPublicShaderReference(val);
			}
			return val;
		}

		public static Shader findShader(string name)
		{
			return GetShaderByName(name);
		}

		public static void RunMaterialFix()
		{
			if (IsDedicatedServer())
			{
				return;
			}
			RefreshShaderCache();
			int count = materialsInPrefabs.Count;
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			for (int i = 0; i < count; i++)
			{
				Material val = materialsInPrefabs[i];
				if ((Object)(object)val == (Object)null)
				{
					num5++;
					continue;
				}
				val.enableInstancing = true;
				Shader targetShader;
				string selectedTargetName;
				bool cutoutRepaired;
				if (!TryGetOrCreateMaterialRegistration(val, out var registration))
				{
					num4++;
				}
				else if (!TryResolveTargetShader(registration.OriginalDummyShaderName, out targetShader, out selectedTargetName))
				{
					SuccessfullyProcessedMaterials.Remove(val);
					num3++;
				}
				else if (val.shader == targetShader)
				{
					if (RepairStrictCutoutState(val, registration.OriginalSnapshot, targetShader))
					{
						num6++;
					}
					val.enableInstancing = true;
					SuccessfullyProcessedMaterials.Add(val);
					num2++;
				}
				else if (TryApplyTargetShader(val, registration, targetShader, selectedTargetName, out cutoutRepaired))
				{
					if (cutoutRepaired)
					{
						num6++;
					}
					SuccessfullyProcessedMaterials.Add(val);
					num++;
				}
				else
				{
					SuccessfullyProcessedMaterials.Remove(val);
					num3++;
				}
			}
			if (debug)
			{
				Debug.Log((object)("[BalrondShaderReplacement] Material fix finished. registered=" + count + ", replaced=" + num + ", alreadyExact=" + num2 + ", cutoutRepairs=" + num6 + ", missingShader=" + num3 + ", unmanaged=" + num4 + ", invalid=" + num5));
			}
		}

		public static void runMaterialFix()
		{
			RunMaterialFix();
		}

		public static void ForceRefreshAndRunMaterialFix()
		{
			SuccessfullyProcessedMaterials.Clear();
			AnalysedShaderPairs.Clear();
			ShaderCache.Clear();
			CurrentEvidenceSnapshot = null;
			RunMaterialFix();
		}

		public static void RepairAllRegisteredMaterials()
		{
			ForceRefreshAndRunMaterialFix();
		}

		public static void ClearRegisteredMaterials()
		{
			prefabsToReplaceShader.Clear();
			materialsInPrefabs.Clear();
			RegisteredMaterials.Clear();
			MaterialRegistrations.Clear();
			SuccessfullyProcessedMaterials.Clear();
			ShaderCache.Clear();
			LastShaderEvidence.Clear();
			AnalysedShaderPairs.Clear();
			CurrentEvidenceSnapshot = null;
		}

		public static void ResetProcessedMaterials()
		{
			SuccessfullyProcessedMaterials.Clear();
			AnalysedShaderPairs.Clear();
		}

		public static void DiagnoseRegisteredShaderCollisions()
		{
			HashSet<string> hashSet = CollectRegisteredTargetShaderNames();
			ShaderEvidenceSnapshot snapshot = BuildEvidenceSnapshot(hashSet);
			foreach (string item in hashSet)
			{
				ResolveShaderByEvidence(item, snapshot, forceDiagnosticLog: true);
			}
		}

		private static void CollectMaterialsFromPrefab(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren != null)
			{
				foreach (Renderer val in componentsInChildren)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Material[] sharedMaterials = val.sharedMaterials;
					if (sharedMaterials != null)
					{
						for (int j = 0; j < sharedMaterials.Length; j++)
						{
							RegisterMaterial(sharedMaterials[j]);
						}
					}
				}
			}
			InstanceRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren<InstanceRenderer>(true);
			if (componentsInChildren2 == null)
			{
				return;
			}
			foreach (InstanceRenderer val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					RegisterMaterial(val2.m_material);
				}
			}
		}

		private static void RegisterMaterial(Material material)
		{
			if (!((Object)(object)material == (Object)null))
			{
				material.enableInstancing = true;
				if (RegisteredMaterials.Add(material))
				{
					materialsInPrefabs.Add(material);
				}
				TryGetOrCreateMaterialRegistration(material, out var _);
			}
		}

		private static bool TryGetOrCreateMaterialRegistration(Material material, out MaterialRegistration registration)
		{
			registration = null;
			if ((Object)(object)material == (Object)null)
			{
				return false;
			}
			if (MaterialRegistrations.TryGetValue(material, out registration) && registration != null && !string.IsNullOrEmpty(registration.OriginalDummyShaderName))
			{
				return true;
			}
			Shader shader = material.shader;
			if ((Object)(object)shader == (Object)null || !IsDummyShader(((Object)shader).name))
			{
				return false;
			}
			registration = new MaterialRegistration
			{
				OriginalDummyShaderName = ((Object)shader).name,
				OriginalSnapshot = CaptureMaterial(material)
			};
			MaterialRegistrations[material] = registration;
			if (debug)
			{
				float snapshotFloat = GetSnapshotFloat(registration.OriginalSnapshot, "_Cutoff", float.NaN);
				Debug.Log((object)("[BalrondShaderReplacement] Registered material '" + ((Object)material).name + "', dummy='" + ((Object)shader).name + "', properties=" + registration.OriginalSnapshot.Properties.Count + ", cutoff=" + (float.IsNaN(snapshotFloat) ? "<missing>" : snapshotFloat.ToString("0.####")) + ", queue=" + registration.OriginalSnapshot.RenderQueue));
			}
			return true;
		}

		private static bool IsDummyShader(string shaderName)
		{
			return !string.IsNullOrEmpty(shaderName) && shaderName.StartsWith("Balrond/", StringComparison.Ordinal);
		}

		private static List<string> GetTargetShaderCandidates(string oldShaderName)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrEmpty(oldShaderName))
			{
				return list;
			}
			string text = oldShaderName;
			if (text.StartsWith("Balrond/", StringComparison.Ordinal))
			{
				text = text.Substring("Balrond/".Length);
			}
			string text2 = RemovePrefix(text, "Particles/");
			if (ContainsOrdinalIgnoreCase(text, "Tess Bumped"))
			{
				AddCandidate(list, "Lux Lit Particles/ Tess Bumped");
				AddCandidate(list, "Lux Lit Particles/Tess Bumped");
				AddCandidate(list, "Lux Lit Particles/" + text2);
			}
			if (ContainsOrdinalIgnoreCase(text, "Bumped"))
			{
				AddCandidate(list, "Lux Lit Particles/ Bumped");
				AddCandidate(list, "Lux Lit Particles/Bumped");
				AddCandidate(list, "Lux Lit Particles/" + text2);
			}
			if (ContainsOrdinalIgnoreCase(text, "Standard Surface"))
			{
				AddCandidate(list, "Particles/Standard Surface");
				AddCandidate(list, "Particles/Standard Surface2");
				string text3 = text2;
				if (ContainsOrdinalIgnoreCase(text3, "Standard Surface2"))
				{
					text3 = ReplaceOrdinalIgnoreCase(text3, "Standard Surface2", "Standard Surface");
				}
				AddCandidate(list, "Particles/" + text3);
			}
			if (ContainsOrdinalIgnoreCase(text, "Standard Unlit"))
			{
				AddCandidate(list, "Particles/Standard Unlit2");
				AddCandidate(list, "Particles/Standard Unlit");
				string text4 = text2;
				if (!ContainsOrdinalIgnoreCase(text4, "Standard Unlit2"))
				{
					text4 = ReplaceOrdinalIgnoreCase(text4, "Standard Unlit", "Standard Unlit2");
				}
				AddCandidate(list, "Particles/" + text4);
			}
			AddCandidate(list, "Custom/" + text);
			return list;
		}

		private static void AddCandidate(List<string> candidates, string shaderName)
		{
			if (!string.IsNullOrWhiteSpace(shaderName))
			{
				string item = shaderName.Trim();
				if (!candidates.Contains(item))
				{
					candidates.Add(item);
				}
			}
		}

		private static bool TryResolveTargetShader(string oldShaderName, out Shader targetShader, out string selectedTargetName)
		{
			targetShader = null;
			selectedTargetName = null;
			List<string> targetShaderCandidates = GetTargetShaderCandidates(oldShaderName);
			for (int i = 0; i < targetShaderCandidates.Count; i++)
			{
				string text = targetShaderCandidates[i];
				Shader shaderByName = GetShaderByName(text);
				if (IsUsableTargetShader(shaderByName, text))
				{
					targetShader = shaderByName;
					selectedTargetName = text;
					return true;
				}
			}
			if (debug)
			{
				Debug.LogWarning((object)("[BalrondShaderReplacement] No target shader for dummy '" + oldShaderName + "'. Checked: " + string.Join(", ", targetShaderCandidates)));
			}
			return false;
		}

		private static bool IsUsableTargetShader(Shader shader, string expectedName)
		{
			if ((Object)(object)shader == (Object)null)
			{
				return false;
			}
			if (!string.Equals(((Object)shader).name, expectedName, StringComparison.Ordinal))
			{
				return false;
			}
			if (!SafeGetIsSupported(shader))
			{
				if (debug)
				{
					Debug.LogWarning((object)("[BalrondShaderReplacement] Rejected unsupported shader '" + expectedName + "', instanceID=" + SafeGetInstanceId((Object)(object)shader)));
				}
				return false;
			}
			if (SafeGetPassCount(shader) <= 0)
			{
				if (debug)
				{
					Debug.LogWarning((object)("[BalrondShaderReplacement] Rejected zero-pass shader '" + expectedName + "', instanceID=" + SafeGetInstanceId((Object)(object)shader)));
				}
				return false;
			}
			return true;
		}

		private static HashSet<string> CollectRegisteredTargetShaderNames()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (KeyValuePair<Material, MaterialRegistration> materialRegistration in MaterialRegistrations)
			{
				MaterialRegistration value = materialRegistration.Value;
				if (value != null && !string.IsNullOrEmpty(value.OriginalDummyShaderName))
				{
					List<string> targetShaderCandidates = GetTargetShaderCandidates(value.OriginalDummyShaderName);
					for (int i = 0; i < targetShaderCandidates.Count; i++)
					{
						hashSet.Add(targetShaderCandidates[i]);
					}
				}
			}
			return hashSet;
		}

		private static ShaderEvidenceSnapshot BuildEvidenceSnapshot(HashSet<string> targetNames)
		{
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			ShaderEvidenceSnapshot shaderEvidenceSnapshot = new ShaderEvidenceSnapshot();
			if (targetNames == null || targetNames.Count == 0)
			{
				return shaderEvidenceSnapshot;
			}
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			if (array != null)
			{
				foreach (Material val in array)
				{
					if ((Object)(object)val == (Object)null || RegisteredMaterials.Contains(val) || (Object)(object)val.shader == (Object)null)
					{
						continue;
					}
					Shader shader = val.shader;
					string name = ((Object)shader).name;
					if (!string.IsNullOrEmpty(name) && targetNames.Contains(name))
					{
						ShaderEvidence orCreate = shaderEvidenceSnapshot.GetOrCreate(name, shader);
						if (orCreate != null)
						{
							orCreate.MaterialReferenceCount++;
						}
					}
				}
			}
			Renderer[] array2 = Resources.FindObjectsOfTypeAll<Renderer>();
			if (array2 != null)
			{
				foreach (Renderer val2 in array2)
				{
					if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null)
					{
						continue;
					}
					Scene scene = ((Component)val2).gameObject.scene;
					if (!((Scene)(ref scene)).IsValid())
					{
						continue;
					}
					scene = ((Component)val2).gameObject.scene;
					if (!((Scene)(ref scene)).isLoaded)
					{
						continue;
					}
					Material[] sharedMaterials = val2.sharedMaterials;
					if (sharedMaterials == null)
					{
						continue;
					}
					foreach (Material val3 in sharedMaterials)
					{
						if ((Object)(object)val3 == (Object)null || RegisteredMaterials.Contains(val3) || (Object)(object)val3.shader == (Object)null)
						{
							continue;
						}
						Shader shader2 = val3.shader;
						string name2 = ((Object)shader2).name;
						if (!string.IsNullOrEmpty(name2) && targetNames.Contains(name2))
						{
							ShaderEvidence orCreate2 = shaderEvidenceSnapshot.GetOrCreate(name2, shader2);
							if (orCreate2 != null)
							{
								orCreate2.LiveRendererReferenceCount++;
							}
						}
					}
				}
			}
			Shader[] array3 = Resources.FindObjectsOfTypeAll<Shader>();
			if (array3 != null)
			{
				foreach (Shader val4 in array3)
				{
					if (!((Object)(object)val4 == (Object)null) && !string.IsNullOrEmpty(((Object)val4).name) && targetNames.Contains(((Object)val4).name))
					{
						shaderEvidenceSnapshot.GetOrCreate(((Object)val4).name, val4);
					}
				}
			}
			foreach (string targetName in targetNames)
			{
				Shader val5 = null;
				try
				{
					val5 = Shader.Find(targetName);
				}
				catch (Exception ex)
				{
					if (debug)
					{
						Debug.LogWarning((object)("[BalrondShaderReplacement] Shader.Find failed for '" + targetName + "': " + ex.Message));
					}
				}
				if (!((Object)(object)val5 == (Object)null) && string.Equals(((Object)val5).name, targetName, StringComparison.Ordinal))
				{
					ShaderEvidence orCreate3 = shaderEvidenceSnapshot.GetOrCreate(targetName, val5);
					if (orCreate3 != null)
					{
						orCreate3.ReturnedByShaderFind = true;
					}
				}
			}
			return shaderEvidenceSnapshot;
		}

		private static Shader ResolveShaderByEvidence(string shaderName, ShaderEvidenceSnapshot snapshot, bool forceDiagnosticLog)
		{
			if (string.IsNullOrWhiteSpace(shaderName))
			{
				return null;
			}
			string text = shaderName.Trim();
			if (TrustedShaderOverrides.TryGetValue(text, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (snapshot == null || !snapshot.ByName.TryGetValue(text, out var value2))
			{
				if (debug)
				{
					Debug.LogWarning((object)("[BalrondShaderReplacement] No loaded shader candidates for '" + text + "'."));
				}
				return null;
			}
			bool flag = false;
			foreach (ShaderEvidence value3 in value2.Values)
			{
				if (value3 == null || (Object)(object)value3.Shader == (Object)null || !value3.IsSupported || value3.PassCount <= 0 || !value3.HasRuntimeEvidence)
				{
					continue;
				}
				flag = true;
				break;
			}
			ShaderEvidence shaderEvidence = null;
			foreach (ShaderEvidence value4 in value2.Values)
			{
				if (value4 != null && !((Object)(object)value4.Shader == (Object)null) && value4.IsSupported && value4.PassCount > 0 && (!flag || value4.HasRuntimeEvidence) && (shaderEvidence == null || value4.Score > shaderEvidence.Score))
				{
					shaderEvidence = value4;
				}
			}
			List<ShaderEvidence> list = new List<ShaderEvidence>(value2.Values);
			list.Sort(delegate(ShaderEvidence left, ShaderEvidence right)
			{
				if (left == right)
				{
					return 0;
				}
				return (left == null) ? 1 : (right?.Score.CompareTo(left.Score) ?? (-1));
			});
			LastShaderEvidence[text] = list;
			bool flag2 = list.Count > 1;
			if (forceDiagnosticLog || (debugShaderCollisions && flag2))
			{
				Debug.LogWarning((object)("[BalrondShaderReplacement] Shader candidates for '" + text + "': count=" + list.Count + ", runtimeEvidenceMode=" + flag + ", selected=" + ((shaderEvidence != null) ? SafeGetInstanceId((Object)(object)shaderEvidence.Shader).ToString() : "<none>")));
				for (int num = 0; num < list.Count; num++)
				{
					ShaderEvidence shaderEvidence2 = list[num];
					if (shaderEvidence2 != null)
					{
						bool flag3 = shaderEvidence != null && shaderEvidence2.Shader == shaderEvidence.Shader;
						Debug.LogWarning((object)("[BalrondShaderReplacement]   " + (flag3 ? "[SELECTED] " : string.Empty) + "instanceID=" + SafeGetInstanceId((Object)(object)shaderEvidence2.Shader) + ", supported=" + shaderEvidence2.IsSupported + ", passes=" + shaderEvidence2.PassCount + ", properties=" + shaderEvidence2.PropertyCount + ", externalMaterialRefs=" + shaderEvidence2.MaterialReferenceCount + ", externalLiveRendererRefs=" + shaderEvidence2.LiveRendererReferenceCount + ", Shader.Find=" + shaderEvidence2.ReturnedByShaderFind + ", score=" + shaderEvidence2.Score));
					}
				}
			}
			return shaderEvidence?.Shader;
		}

		private static bool TryApplyTargetShader(Material material, MaterialRegistration registration, Shader targetShader, string selectedTargetName, out bool cutoutRepaired)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			cutoutRepaired = false;
			if ((Object)(object)material == (Object)null || registration == null || (Object)(object)targetShader == (Object)null)
			{
				return false;
			}
			Shader shader = material.shader;
			string text = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : "<null>");
			MaterialSnapshot materialSnapshot = registration.OriginalSnapshot ?? CaptureMaterial(material);
			if (debugShaderDifferences)
			{
				AnalyseShaderDifferences(material, materialSnapshot, targetShader, registration.OriginalDummyShaderName, selectedTargetName);
			}
			string text2 = (debug ? FormatKeywords(material.shaderKeywords) : string.Empty);
			try
			{
				material.shader = targetShader;
				bool flag = IsStrictCutoutTarget(targetShader);
				int num = RestoreCompatibleProperties(material, materialSnapshot, flag);
				if (flag)
				{
					material.renderQueue = -1;
				}
				else if (materialSnapshot != null && materialSnapshot.HadCustomRenderQueue)
				{
					material.renderQueue = materialSnapshot.RenderQueue;
				}
				if (materialSnapshot != null)
				{
					material.globalIlluminationFlags = materialSnapshot.GlobalIlluminationFlags;
					material.doubleSidedGI = materialSnapshot.DoubleSidedGI;
				}
				material.enableInstancing = true;
				cutoutRepaired = RepairStrictCutoutState(material, materialSnapshot, targetShader);
				if (debug)
				{
					float f = (material.HasProperty("_Cutoff") ? material.GetFloat("_Cutoff") : float.NaN);
					string text3 = FormatKeywords(material.shaderKeywords);
					Debug.Log((object)("[BalrondShaderReplacement] Repaired material '" + ((Object)material).name + "': '" + text + "' [" + SafeGetInstanceId((Object)(object)shader) + "] -> '" + ((Object)targetShader).name + "' [" + SafeGetInstanceId((Object)(object)targetShader) + "], restoredProperties=" + num + ", queue=" + material.renderQueue + ", cutoff=" + (float.IsNaN(f) ? "<none>" : f.ToString("0.####")) + ", cutoffSafety=" + cutoutRepaired + ", keywordsBefore='" + text2 + "', keywordsAfter='" + text3 + "'"));
				}
				return true;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[BalrondShaderReplacement] Failed replacing shader on material '" + ((Object)material).name + "'. dummy='" + registration.OriginalDummyShaderName + "', current='" + text + "', target='" + ((Object)targetShader).name + "'. " + ex));
				return false;
			}
		}

		private static bool IsStrictCutoutTarget(Shader shader)
		{
			return (Object)(object)shader != (Object)null && StrictCutoutShaderNames.Contains(((Object)shader).name);
		}

		private static bool RepairStrictCutoutState(Material material, MaterialSnapshot originalSnapshot, Shader targetShader)
		{
			if ((Object)(object)material == (Object)null || (Object)(object)targetShader == (Object)null || !IsStrictCutoutTarget(targetShader))
			{
				return false;
			}
			bool result = false;
			if (material.HasProperty("_Cutoff"))
			{
				float num = material.GetFloat("_Cutoff");
				float snapshotFloat = GetSnapshotFloat(originalSnapshot, "_Cutoff", float.NaN);
				float num2 = ((float.IsNaN(snapshotFloat) || !(snapshotFloat > 0.0001f)) ? Mathf.Clamp01(fallbackCutoff) : Mathf.Clamp01(snapshotFloat));
				if (num2 > 0.0001f && Mathf.Abs(num - num2) > 0.0001f)
				{
					material.SetFloat("_Cutoff", num2);
					result = true;
				}
			}
			if (material.renderQueue != -1)
			{
				material.renderQueue = -1;
				result = true;
			}
			return result;
		}

		private static MaterialSnapshot CaptureMaterial(Material material)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected I4, but got Unknown
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			MaterialSnapshot materialSnapshot = new MaterialSnapshot();
			if ((Object)(object)material == (Object)null)
			{
				return materialSnapshot;
			}
			Shader shader = material.shader;
			materialSnapshot.MaterialName = ((Object)material).name;
			materialSnapshot.ShaderName = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : string.Empty);
			materialSnapshot.RenderQueue = material.renderQueue;
			materialSnapshot.HadCustomRenderQueue = (Object)(object)shader != (Object)null && material.renderQueue != shader.renderQueue;
			materialSnapshot.GlobalIlluminationFlags = material.globalIlluminationFlags;
			materialSnapshot.DoubleSidedGI = material.doubleSidedGI;
			try
			{
				string[] shaderKeywords = material.shaderKeywords;
				materialSnapshot.DiagnosticOriginalKeywords = ((shaderKeywords != null) ? ((string[])shaderKeywords.Clone()) : new string[0]);
			}
			catch
			{
				materialSnapshot.DiagnosticOriginalKeywords = new string[0];
			}
			if ((Object)(object)shader == (Object)null)
			{
				return materialSnapshot;
			}
			int num = SafeGetPropertyCount(shader);
			for (int i = 0; i < num; i++)
			{
				string propertyName;
				ShaderPropertyType propertyType;
				try
				{
					propertyName = shader.GetPropertyName(i);
					propertyType = shader.GetPropertyType(i);
				}
				catch (Exception ex)
				{
					if (debug)
					{
						Debug.LogWarning((object)("[BalrondShaderReplacement] Could not read shader property metadata from '" + ((Object)shader).name + "': " + ex.Message));
					}
					continue;
				}
				if (string.IsNullOrEmpty(propertyName) || !material.HasProperty(propertyName))
				{
					continue;
				}
				PropertySnapshot propertySnapshot = new PropertySnapshot
				{
					Name = propertyName,
					Type = propertyType
				};
				try
				{
					ShaderPropertyType val = propertyType;
					ShaderPropertyType val2 = val;
					switch ((int)val2)
					{
					default:
						goto end_IL_0179;
					case 4:
						propertySnapshot.TextureValue = material.GetTexture(propertyName);
						propertySnapshot.TextureScale = material.GetTextureScale(propertyName);
						propertySnapshot.TextureOffset = material.GetTextureOffset(propertyName);
						break;
					case 0:
						propertySnapshot.ColorValue = material.GetColor(propertyName);
						break;
					case 1:
						propertySnapshot.VectorValue = material.GetVector(propertyName);
						break;
					case 2:
					case 3:
						propertySnapshot.FloatValue = material.GetFloat(propertyName);
						break;
					}
					materialSnapshot.Properties[propertyName] = propertySnapshot;
					end_IL_0179:;
				}
				catch (Exception ex2)
				{
					if (debug)
					{
						Debug.LogWarning((object)("[BalrondShaderReplacement] Could not capture property '" + propertyName + "' from material '" + ((Object)material).name + "': " + ex2.Message));
					}
				}
			}
			return materialSnapshot;
		}

		private static int RestoreCompatibleProperties(Material material, MaterialSnapshot snapshot, bool protectCutoutRenderState)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected I4, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null || snapshot == null)
			{
				return 0;
			}
			Dictionary<string, ShaderPropertyType> shaderPropertyTypes = GetShaderPropertyTypes(material.shader);
			int num = 0;
			foreach (KeyValuePair<string, PropertySnapshot> property in snapshot.Properties)
			{
				string key = property.Key;
				PropertySnapshot value = property.Value;
				if ((protectCutoutRenderState && ProtectedCutoutStateProperties.Contains(key)) || !shaderPropertyTypes.TryGetValue(key, out var value2) || !ArePropertyTypesCompatible(value.Type, value2) || !material.HasProperty(key))
				{
					continue;
				}
				try
				{
					ShaderPropertyType val = value2;
					ShaderPropertyType val2 = val;
					switch ((int)val2)
					{
					default:
						goto end_IL_00ca;
					case 4:
						material.SetTexture(key, value.TextureValue);
						material.SetTextureScale(key, value.TextureScale);
						material.SetTextureOffset(key, value.TextureOffset);
						break;
					case 0:
						material.SetColor(key, value.ColorValue);
						break;
					case 1:
						material.SetVector(key, value.VectorValue);
						break;
					case 2:
					case 3:
						material.SetFloat(key, value.FloatValue);
						break;
					}
					num++;
					end_IL_00ca:;
				}
				catch (Exception ex)
				{
					if (debug)
					{
						Debug.LogWarning((object)("[BalrondShaderReplacement] Could not restore property '" + key + "' on material '" + ((Object)material).name + "': " + ex.Message));
					}
				}
			}
			return num;
		}

		private static Dictionary<string, ShaderPropertyType> GetShaderPropertyTypes(Shader shader)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, ShaderPropertyType> dictionary = new Dictionary<string, ShaderPropertyType>(StringComparer.Ordinal);
			if ((Object)(object)shader == (Object)null)
			{
				return dictionary;
			}
			int num = SafeGetPropertyCount(shader);
			for (int i = 0; i < num; i++)
			{
				try
				{
					string propertyName = shader.GetPropertyName(i);
					ShaderPropertyType propertyType = shader.GetPropertyType(i);
					if (!string.IsNullOrEmpty(propertyName))
					{
						dictionary[propertyName] = propertyType;
					}
				}
				catch
				{
				}
			}
			return dictionary;
		}

		private static bool ArePropertyTypesCompatible(ShaderPropertyType sourceType, ShaderPropertyType targetType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (sourceType == targetType)
			{
				return true;
			}
			bool flag = (int)sourceType == 2 || (int)sourceType == 3;
			bool flag2 = (int)targetType == 2 || (int)targetType == 3;
			return flag && flag2;
		}

		private static float GetSnapshotFloat(MaterialSnapshot snapshot, string propertyName, float fallback)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			if (snapshot == null || string.IsNullOrEmpty(propertyName) || !snapshot.Properties.TryGetValue(propertyName, out var value))
			{
				return fallback;
			}
			if ((int)value.Type != 2 && (int)value.Type != 3)
			{
				return fallback;
			}
			return value.FloatValue;
		}

		private unsafe static void AnalyseShaderDifferences(Material material, MaterialSnapshot sourceSnapshot, Shader targetShader, string oldShaderName, string targetShaderName)
		{
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if (sourceSnapshot == null || (Object)(object)targetShader == (Object)null)
			{
				return;
			}
			string text = oldShaderName + " -> " + targetShaderName;
			if (!AnalysedShaderPairs.Add(text))
			{
				return;
			}
			Dictionary<string, ShaderPropertyType> shaderPropertyTypes = GetShaderPropertyTypes(targetShader);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int currentCount = 0;
			foreach (KeyValuePair<string, PropertySnapshot> property in sourceSnapshot.Properties)
			{
				string key = property.Key;
				PropertySnapshot value = property.Value;
				if (!shaderPropertyTypes.TryGetValue(key, out var value2))
				{
					if (IsMeaningfulValue(value))
					{
						num2++;
						if (CanLogAnotherDifference(ref currentCount))
						{
							Debug.LogWarning((object)("[BalrondShaderReplacement] Target '" + targetShaderName + "' is missing source property '" + key + "' (" + ((object)Unsafe.As<ShaderPropertyType, ShaderPropertyType>(ref value.Type)/*cast due to .constrained prefix*/).ToString() + ") from material '" + ((Object)material).name + "', value=" + FormatPropertyValue(value)));
						}
					}
				}
				else if (!ArePropertyTypesCompatible(value.Type, value2))
				{
					num3++;
					if (CanLogAnotherDifference(ref currentCount))
					{
						Debug.LogWarning((object)("[BalrondShaderReplacement] Property type mismatch for '" + text + "', property='" + key + "', dummy=" + ((object)Unsafe.As<ShaderPropertyType, ShaderPropertyType>(ref value.Type)/*cast due to .constrained prefix*/).ToString() + ", target=" + ((object)(*(ShaderPropertyType*)(&value2))/*cast due to .constrained prefix*/).ToString()));
					}
				}
				else
				{
					num++;
				}
			}
			foreach (string key2 in shaderPropertyTypes.Keys)
			{
				if (!sourceSnapshot.Properties.ContainsKey(key2))
				{
					num4++;
					if (debugTargetOnlyProperties && CanLogAnotherDifference(ref currentCount))
					{
						Debug.Log((object)("[BalrondShaderReplacement] Target-only property for '" + text + "': '" + key2 + "'."));
					}
				}
			}
			Debug.Log((object)("[BalrondShaderReplacement] Shader analysis '" + text + "': dummyProperties=" + sourceSnapshot.Properties.Count + ", targetProperties=" + shaderPropertyTypes.Count + ", compatible=" + num + ", meaningfulMissing=" + num2 + ", typeMismatch=" + num3 + ", targetOnly=" + num4));
		}

		private static bool IsMeaningfulValue(PropertySnapshot property)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected I4, but got Unknown
			if (property == null)
			{
				return false;
			}
			ShaderPropertyType type = property.Type;
			ShaderPropertyType val = type;
			switch ((int)val)
			{
			case 4:
				return (Object)(object)property.TextureValue != (Object)null;
			case 2:
			case 3:
				return Mathf.Abs(property.FloatValue) > 0.0001f;
			case 0:
				return Mathf.Abs(property.ColorValue.r) > 0.0001f || Mathf.Abs(property.ColorValue.g) > 0.0001f || Mathf.Abs(property.ColorValue.b) > 0.0001f || Mathf.Abs(property.ColorValue.a) > 0.0001f;
			case 1:
				return ((Vector4)(ref property.VectorValue)).sqrMagnitude > 9.999999E-09f;
			default:
				return false;
			}
		}

		private static string FormatPropertyValue(PropertySnapshot property)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected I4, but got Unknown
			if (property == null)
			{
				return "null";
			}
			ShaderPropertyType type = property.Type;
			ShaderPropertyType val = type;
			switch ((int)val)
			{
			case 4:
				return ((Object)(object)property.TextureValue != (Object)null) ? ((Object)property.TextureValue).name : "null";
			case 2:
			case 3:
				return property.FloatValue.ToString("0.####");
			case 0:
				return ((object)Unsafe.As<Color, Color>(ref property.ColorValue)/*cast due to .constrained prefix*/).ToString();
			case 1:
				return ((object)Unsafe.As<Vector4, Vector4>(ref property.VectorValue)/*cast due to .constrained prefix*/).ToString();
			default:
				return "unsupported";
			}
		}

		private static bool CanLogAnotherDifference(ref int currentCount)
		{
			if (maxDifferenceLogsPerShaderPair <= 0 || currentCount >= maxDifferenceLogsPerShaderPair)
			{
				return false;
			}
			currentCount++;
			return true;
		}

		private static void AddPublicShaderReference(Shader shader)
		{
			if ((Object)(object)shader == (Object)null)
			{
				return;
			}
			for (int i = 0; i < shaders.Count; i++)
			{
				if (shaders[i] == shader)
				{
					return;
				}
			}
			shaders.Add(shader);
		}

		private static string FormatKeywords(string[] keywords)
		{
			if (keywords == null || keywords.Length == 0)
			{
				return string.Empty;
			}
			return string.Join(",", keywords);
		}

		private static int SafeGetPropertyCount(Shader shader)
		{
			if ((Object)(object)shader == (Object)null)
			{
				return 0;
			}
			try
			{
				return shader.GetPropertyCount();
			}
			catch (Exception ex)
			{
				if (debug)
				{
					Debug.LogWarning((object)("[BalrondShaderReplacement] GetPropertyCount failed for '" + ((Object)shader).name + "': " + ex.Message));
				}
				return 0;
			}
		}

		private static int SafeGetPassCount(Shader shader)
		{
			if ((Object)(object)shader == (Object)null)
			{
				return 0;
			}
			try
			{
				return shader.passCount;
			}
			catch (Exception ex)
			{
				if (debug)
				{
					Debug.LogWarning((object)("[BalrondShaderReplacement] passCount failed for '" + ((Object)shader).name + "': " + ex.Message));
				}
				return 0;
			}
		}

		private static bool SafeGetIsSupported(Shader shader)
		{
			if ((Object)(object)shader == (Object)null)
			{
				return false;
			}
			try
			{
				return shader.isSupported;
			}
			catch (Exception ex)
			{
				if (debug)
				{
					Debug.LogWarning((object)("[BalrondShaderReplacement] isSupported failed for '" + ((Object)shader).name + "': " + ex.Message));
				}
				return false;
			}
		}

		private static int SafeGetInstanceId(Object unityObject)
		{
			if (unityObject == (Object)null)
			{
				return 0;
			}
			try
			{
				return unityObject.GetInstanceID();
			}
			catch
			{
				return 0;
			}
		}

		private static bool IsDedicatedServer()
		{
			try
			{
				return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated();
			}
			catch
			{
				return false;
			}
		}

		private static string RemovePrefix(string value, string prefix)
		{
			if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(prefix))
			{
				return value;
			}
			return value.StartsWith(prefix, StringComparison.Ordinal) ? value.Substring(prefix.Length) : value;
		}

		private static bool ContainsOrdinalIgnoreCase(string value, string fragment)
		{
			return !string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(fragment) && value.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static string ReplaceOrdinalIgnoreCase(string source, string oldValue, string newValue)
		{
			if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(oldValue))
			{
				return source;
			}
			int num = source.IndexOf(oldValue, StringComparison.OrdinalIgnoreCase);
			if (num < 0)
			{
				return source;
			}
			return source.Substring(0, num) + newValue + source.Substring(num + oldValue.Length);
		}
	}
	internal static class TableMapper
	{
		private static readonly PrefabLookupCache PrefabCache = new PrefabLookupCache();

		private static List<GameObject> _prefabs;

		public static CraftingStation Workbench { get; private set; }

		public static CraftingStation Stonecutter { get; private set; }

		public static void SetupTables(List<GameObject> prefabs)
		{
			_prefabs = prefabs;
			PrefabCache.Rebuild(prefabs);
			Workbench = FindStation("piece_workbench");
			Stonecutter = FindStation("piece_stonecutter", Workbench);
		}

		private static CraftingStation FindStation(string prefabName, CraftingStation fallback = null)
		{
			GameObject val = PrefabCache.Find(prefabName, _prefabs);
			if ((Object)(object)val != (Object)null)
			{
				CraftingStation val2 = val.GetComponent<CraftingStation>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = val.GetComponentInChildren<CraftingStation>(true);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			if ((Object)(object)fallback != (Object)null)
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogWarning((object)("Crafting station '" + prefabName + "' not found. Falling back to '" + ((Object)((Component)fallback).gameObject).name + "'."));
				}
				return fallback;
			}
			if (Launch.Log != null)
			{
				Launch.Log.LogError((object)("Crafting station not found: " + prefabName));
			}
			return null;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency("com.jotunn.jotunn", "2.30.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("balrond.astafaraios.RavenwoodColosseum", "RavenwoodColosseum", "1.1.9")]
	public sealed class Launch : BaseUnityPlugin
	{
		public const string PluginGUID = "balrond.astafaraios.RavenwoodColosseum";

		public const string PluginName = "RavenwoodColosseum";

		public const string PluginVersion = "1.1.9";

		public static string projectName = "RavenwoodColosseum";

		private static readonly Type[] NoParameters = Type.EmptyTypes;

		private static readonly Type[] OneObjectDbParameter = new Type[1] { typeof(ObjectDB) };

		private static Harmony _harmony;

		private static bool _materialsFixed;

		internal static ManualLogSource Log;

		public static readonly ModResourceLoader modResourceLoader = new ModResourceLoader();

		public static readonly BuildPieceBuilder buildPieceBuilder = new BuildPieceBuilder();

		public static readonly FxReplacment fxReplacment = new FxReplacment();

		public static ConfigEntry<bool> LockConfiguration;

		private static readonly Dictionary<string, ConfigEntry<string>> RecipeConfigs = new Dictionary<string, ConfigEntry<string>>(StringComparer.Ordinal);

		private void Awake()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				ServerSyncBridge.Initialize("balrond.astafaraios.RavenwoodColosseum", "RavenwoodColosseum", "1.1.9");
				BindConfiguration();
				Log.LogInfo((object)"Embedded ServerSync initialized (ILRepack).");
			}
			catch (Exception ex)
			{
				ServerSyncBridge.Reset();
				Log.LogError((object)("Configuration/ServerSync initialization failed: " + ex));
				throw;
			}
			InitializeRavenwoodCategoryAtStartup();
			SafeLoadAssets();
			buildPieceBuilder.PrepareLoadedPrefabs(modResourceLoader.BuildPrefabs);
			RavenwoodJotunnRegistrar.RegisterPieces(modResourceLoader.BuildPrefabs);
			try
			{
				if (_harmony == null)
				{
					_harmony = new Harmony("balrond.astafaraios.RavenwoodColosseum");
				}
				RegisterHarmonyPatches();
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Harmony patch registration failed: " + ex2));
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				try
				{
					_harmony.UnpatchSelf();
				}
				catch (Exception ex)
				{
					if (Log != null)
					{
						Log.LogError((object)("Harmony unpatch failed: " + ex));
					}
				}
				finally
				{
					_harmony = null;
				}
			}
			ServerSyncBridge.Reset();
		}

		private void BindConfiguration()
		{
			LockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "LockConfiguration", true, "Lock synchronized RavenwoodColosseum settings to the server/host values.");
			ServerSyncBridge.AddLockingConfigEntry(LockConfiguration);
			RecipeConfigs.Clear();
			for (int i = 0; i < PieceCatalog.Pieces.Length; i++)
			{
				PieceDefinition pieceDefinition = PieceCatalog.Pieces[i];
				string prefabName = pieceDefinition.PrefabName;
				ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Recipes", prefabName, pieceDefinition.DefaultRecipe, "Build recipe for " + prefabName + ". Format: PrefabName:Amount,PrefabName:Amount. Use 'None' for a free piece. Invalid values fall back to the default recipe.");
				ServerSyncBridge.AddConfigEntry<string>(val);
				RecipeConfigs[prefabName] = val;
				val.SettingChanged += delegate
				{
					buildPieceBuilder.ApplyConfiguredRecipeIfReady(prefabName);
				};
			}
		}

		internal static string GetConfiguredRecipe(PieceDefinition definition)
		{
			if (definition == null)
			{
				return null;
			}
			if (RecipeConfigs.TryGetValue(definition.PrefabName, out var value) && value != null)
			{
				return value.Value;
			}
			return definition.DefaultRecipe;
		}

		private static void InitializeRavenwoodCategoryAtStartup()
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0036: Expected I4, but got Unknown
			try
			{
				PieceCategory category = RavenwoodBuildMenuCompat.GetOrCreateRavenwoodCategory((PieceCategory)0);
				if (Log != null && RavenwoodBuildMenuCompat.TryGetResolvedCategory(out category))
				{
					Log.LogInfo((object)("Ravenwood category startup registration complete: id=" + (int)category + ", provider=" + RavenwoodBuildMenuCompat.GetProviderDescription() + "."));
				}
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogError((object)("Ravenwood category startup registration failed: " + ex));
				}
			}
		}

		private static void SafeLoadAssets()
		{
			try
			{
				modResourceLoader.LoadAssets();
			}
			catch (Exception ex)
			{
				if (Log != null)
				{
					Log.LogError((object)("Failed to load RavenwoodColosseum assets: " + ex));
				}
			}
		}

		private static void RegisterHarmonyPatches()
		{
			int applied = 0;
			int missing = 0;
			RegisterPatch(typeof(FejdStartup), "Awake", NoParameters, null, "FejdStartupAwakePostfix", 0, ref applied, ref missing);
			RegisterPatch(typeof(Hud), "Awake", NoParameters, "HudAwakePrefix", "HudAwakePostfix", 800, ref applied, ref missing);
			RegisterPatch(typeof(AudioMan), "Awake", NoParameters, null, "AudioManAwakePostfix", 400, ref applied, ref missing);
			RegisterPatch(typeof(ObjectDB), "CopyOtherDB", OneObjectDbParameter, null, "ObjectDbCopyOtherDbPostfix", 0, ref applied, ref missing);
			RegisterPatch(typeof(ObjectDB), "Awake", NoParameters, null, "ObjectDbAwakePostfix", 0, ref applied, ref missing);
			RegisterPatch(typeof(DungeonDB), "Start", NoParameters, "DungeonDbStartPrefix", null, 800, ref applied, ref missing);
			RegisterPatch(typeof(DungeonDB), "Start", NoParameters, null, "DungeonDbStartPostfix", 0, ref applied, ref missing);
			RegisterPatch(typeof(PieceTable), "UpdateAvailable", null, "PieceTableUpdateAvailablePrefix", null, 800, ref applied, ref missing);
			RegisterPatch(typeof(PieceTable), "UpdateAvailable", null, null, "PieceTableUpdateAvailablePostfix", 0, ref applied, ref missing);
			RegisterPatch(typeof(ZNetScene), "Awake", NoParameters, "ZNetSceneAwakePrefix", "ZNetSceneAwakePostfix", 0, ref applied, ref missing);
			if (Log != null)
			{
				if (missing == 0)
				{
					Log.LogInfo((object)("Valheim compatibility patches registered: " + applied + "."));
					return;
				}
				Log.LogWarning((object)("Valheim compatibility patches registered: " + applied + "; unavailable integration points: " + missing + "."));
			}
		}

		private static void RegisterPatch(Type targetType, string targetName, Type[] targetParameters, string prefixName, string postfixName, int priority, ref int applied, ref int missing)
		{
			MethodInfo methodInfo = ((targetParameters == null) ? AccessTools.Method(targetType, targetName, (Type[])null, (Type[])null) : AccessTools.Method(targetType, targetName, targetParameters, (Type[])null));
			if (methodInfo == null)
			{
				missing++;
				if (