Decompiled source of RavenwoodBalrondPieces v2.0.0

plugins/RavenwoodBalrondPieces/RavenwoodBalrondPieces.dll

Decompiled 5 days 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 Balrond.Shared;
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.Audio;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("RavenwoodBalrondPieces")]
[assembly: AssemblyDescription("Ravenwood building and furniture piece collection")]
[assembly: AssemblyCompany("Balrond")]
[assembly: AssemblyProduct("RavenwoodBalrondPieces")]
[assembly: ComVisible(false)]
[assembly: Guid("FE018D9B-F2F6-4BDC-AB33-0A5CFCCB04B9")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
namespace Balrond.Shared
{
	public static class AudioRoutingService
	{
		public enum AudioRoute
		{
			SFX,
			Ambient,
			Music,
			Master
		}

		private enum TargetKind
		{
			Route,
			NamedRuntimeGroup
		}

		private sealed class AudioTarget
		{
			public TargetKind Kind;

			public AudioRoute Route;

			public string RuntimeGroupName;

			public string Reason;
		}

		private sealed class AudioBinding
		{
			public AudioSource Source;

			public AudioTarget Target;
		}

		private sealed class ProcessedNode
		{
			public GameObject Root;

			public readonly List<AudioBinding> AudioBindings = new List<AudioBinding>();

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

			public readonly HashSet<GameObject> ReferencedRootSet = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance);
		}

		private sealed class ExplicitOverride
		{
			public bool UsesNamedGroup;

			public AudioRoute Route;

			public string RuntimeGroupName;
		}

		private sealed class RuntimeMixerCatalog
		{
			private readonly Dictionary<string, AudioMixerGroup> _groupsByName = new Dictionary<string, AudioMixerGroup>(StringComparer.OrdinalIgnoreCase);

			private AudioMixer _mixer;

			private AudioMixerGroup _master;

			private AudioMixerGroup _ambient;

			private AudioMixerGroup _music;

			private AudioMixerGroup _sfx;

			public bool IsReady => (Object)(object)_mixer != (Object)null || (Object)(object)_master != (Object)null || (Object)(object)_ambient != (Object)null || (Object)(object)_music != (Object)null;

			public void Rebuild(AudioMan audioMan)
			{
				_groupsByName.Clear();
				_mixer = null;
				_master = null;
				_ambient = null;
				_music = null;
				_sfx = null;
				if ((Object)(object)audioMan == (Object)null)
				{
					return;
				}
				_master = ReadAudioManGroup(audioMan, "m_masterMixer");
				_ambient = ReadAudioManGroup(audioMan, "m_ambientMixer");
				_music = ReadAudioManGroup(audioMan, "m_musicMixer");
				_mixer = GetMixer(_master) ?? GetMixer(_ambient) ?? GetMixer(_music);
				AddGroup(_master);
				AddGroup(_ambient);
				AddGroup(_music);
				if ((Object)(object)_mixer != (Object)null)
				{
					try
					{
						AudioMixerGroup[] array = _mixer.FindMatchingGroups(string.Empty);
						if (array != null)
						{
							for (int i = 0; i < array.Length; i++)
							{
								AddGroup(array[i]);
							}
						}
					}
					catch (Exception ex)
					{
						Warn("Could not enumerate runtime AudioMixer groups: " + ex.Message);
					}
				}
				_sfx = FindNamedGroup("SFX");
				if ((Object)(object)_sfx == (Object)null)
				{
					_sfx = QueryExactGroup("SFX");
				}
				if ((Object)(object)_sfx == (Object)null)
				{
					AudioMixerGroup val = FindNamedGroup("Effects");
					if ((Object)(object)val == (Object)null)
					{
						val = QueryExactGroup("Effects");
					}
					_sfx = val;
				}
				if ((Object)(object)_sfx == (Object)null)
				{
					_sfx = _master;
					WarnOnce("sfx-group-fallback", "Runtime SFX mixer group was not found. Falling back to the AudioMan master output group.");
				}
			}

			public AudioMixerGroup Resolve(AudioTarget target)
			{
				if (target == null)
				{
					return ResolveRoute(AudioRoute.SFX);
				}
				if (target.Kind == TargetKind.NamedRuntimeGroup)
				{
					AudioMixerGroup val = FindNamedGroup(target.RuntimeGroupName);
					if ((Object)(object)val == (Object)null)
					{
						val = QueryExactGroup(target.RuntimeGroupName);
					}
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
					return ResolveRoute(AudioRoute.SFX);
				}
				return ResolveRoute(target.Route);
			}

			public bool HasNamedGroup(string groupName)
			{
				if (string.IsNullOrEmpty(groupName))
				{
					return false;
				}
				return (Object)(object)FindNamedGroup(groupName) != (Object)null || (Object)(object)QueryExactGroup(groupName) != (Object)null;
			}

			private AudioMixerGroup ResolveRoute(AudioRoute route)
			{
				return (AudioMixerGroup)(route switch
				{
					AudioRoute.Ambient => _ambient ?? _sfx ?? _master, 
					AudioRoute.Music => _music ?? _sfx ?? _master, 
					AudioRoute.Master => _master ?? _sfx ?? _ambient ?? _music, 
					_ => _sfx ?? _master ?? _ambient ?? _music, 
				});
			}

			private AudioMixerGroup FindNamedGroup(string groupName)
			{
				if (!string.IsNullOrEmpty(groupName) && _groupsByName.TryGetValue(groupName, out var value))
				{
					return value;
				}
				return null;
			}

			private AudioMixerGroup QueryExactGroup(string groupName)
			{
				if ((Object)(object)_mixer == (Object)null || string.IsNullOrEmpty(groupName))
				{
					return null;
				}
				try
				{
					AudioMixerGroup[] array = _mixer.FindMatchingGroups(groupName);
					if (array == null)
					{
						return null;
					}
					foreach (AudioMixerGroup val in array)
					{
						AddGroup(val);
						if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, groupName, StringComparison.OrdinalIgnoreCase))
						{
							return val;
						}
					}
				}
				catch (Exception ex)
				{
					WarnOnce("query-group-" + groupName, "Could not query runtime AudioMixer group '" + groupName + "': " + ex.Message);
				}
				return null;
			}

			private void AddGroup(AudioMixerGroup group)
			{
				if (!((Object)(object)group == (Object)null) && !string.IsNullOrEmpty(((Object)group).name) && !_groupsByName.ContainsKey(((Object)group).name))
				{
					_groupsByName.Add(((Object)group).name, group);
				}
			}

			private static AudioMixer GetMixer(AudioMixerGroup group)
			{
				try
				{
					return ((Object)(object)group != (Object)null) ? group.audioMixer : null;
				}
				catch
				{
					return null;
				}
			}

			private static AudioMixerGroup ReadAudioManGroup(AudioMan audioMan, string fieldName)
			{
				try
				{
					FieldInfo field = typeof(AudioMan).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field == null)
					{
						return null;
					}
					object value = field.GetValue(audioMan);
					AudioMixerGroup val = (AudioMixerGroup)((value is AudioMixerGroup) ? value : null);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
					AudioSource val2 = (AudioSource)((value is AudioSource) ? value : null);
					if ((Object)(object)val2 != (Object)null)
					{
						return val2.outputAudioMixerGroup;
					}
				}
				catch (Exception ex)
				{
					WarnOnce("audioman-field-" + fieldName, "Could not read AudioMan." + fieldName + ": " + ex.Message);
				}
				return null;
			}
		}

		private sealed class ReferenceComparer<T> : IEqualityComparer<T> where T : class
		{
			public static readonly ReferenceComparer<T> Instance = new ReferenceComparer<T>();

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

			public int GetHashCode(T obj)
			{
				return RuntimeHelpers.GetHashCode(obj);
			}
		}

		private const int MaxManagedDepth = 24;

		private const int MaxCollectionEntries = 4096;

		private static readonly RuntimeMixerCatalog MixerCatalog = new RuntimeMixerCatalog();

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

		private static readonly Dictionary<GameObject, ProcessedNode> ProcessedNodes = new Dictionary<GameObject, ProcessedNode>(ReferenceComparer<GameObject>.Instance);

		private static readonly Dictionary<AudioSource, AudioBinding> SourceBindings = new Dictionary<AudioSource, AudioBinding>(ReferenceComparer<AudioSource>.Instance);

		private static readonly Dictionary<Type, FieldInfo[]> TraversalFields = new Dictionary<Type, FieldInfo[]>();

		private static readonly HashSet<GameObject> RegisteredRootSet = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance);

		private static readonly List<GameObject> RegisteredRoots = new List<GameObject>();

		private static readonly HashSet<GameObject> ActiveProcessing = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance);

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

		private static Action<string> _infoLogger;

		private static Action<string> _warningLogger;

		private static Action<string> _errorLogger;

		public static bool DebugLogging { get; set; }

		public static void ConfigureLogging(Action<string> infoLogger, Action<string> warningLogger, Action<string> errorLogger)
		{
			_infoLogger = infoLogger;
			_warningLogger = warningLogger;
			_errorLogger = errorLogger;
		}

		public static void SetOverride(string gameObjectName, AudioRoute route)
		{
			if (!string.IsNullOrWhiteSpace(gameObjectName))
			{
				Overrides[gameObjectName] = new ExplicitOverride
				{
					UsesNamedGroup = false,
					Route = route,
					RuntimeGroupName = null
				};
				InvalidateClassificationCaches();
			}
		}

		public static void SetOverrides(AudioRoute route, params string[] gameObjectNames)
		{
			if (gameObjectNames == null)
			{
				return;
			}
			bool flag = false;
			foreach (string text in gameObjectNames)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					Overrides[text] = new ExplicitOverride
					{
						UsesNamedGroup = false,
						Route = route,
						RuntimeGroupName = null
					};
					flag = true;
				}
			}
			if (flag)
			{
				InvalidateClassificationCaches();
			}
		}

		public static void SetMixerGroupOverride(string gameObjectName, string runtimeMixerGroupName)
		{
			if (!string.IsNullOrWhiteSpace(gameObjectName) && !string.IsNullOrWhiteSpace(runtimeMixerGroupName))
			{
				Overrides[gameObjectName] = new ExplicitOverride
				{
					UsesNamedGroup = true,
					Route = AudioRoute.SFX,
					RuntimeGroupName = runtimeMixerGroupName
				};
				InvalidateClassificationCaches();
			}
		}

		public static void RemoveOverride(string gameObjectName)
		{
			if (!string.IsNullOrWhiteSpace(gameObjectName) && Overrides.Remove(gameObjectName))
			{
				InvalidateClassificationCaches();
			}
		}

		public static void Process(GameObject root)
		{
			if (IsUsable((Object)(object)root))
			{
				RegisterRoot(root);
				if (MixerCatalog.IsReady)
				{
					ProcessRoot(root);
				}
			}
		}

		public static void Process(IEnumerable<GameObject> roots)
		{
			if (roots == null)
			{
				return;
			}
			foreach (GameObject root in roots)
			{
				if (IsUsable((Object)(object)root))
				{
					RegisterRoot(root);
				}
			}
			if (!MixerCatalog.IsReady)
			{
				return;
			}
			for (int i = 0; i < RegisteredRoots.Count; i++)
			{
				GameObject val = RegisteredRoots[i];
				if (IsUsable((Object)(object)val))
				{
					ProcessRoot(val);
				}
			}
		}

		public static void OnAudioManAwake(AudioMan audioMan)
		{
			if ((Object)(object)audioMan == (Object)null)
			{
				return;
			}
			MixerCatalog.Rebuild(audioMan);
			if (!MixerCatalog.IsReady)
			{
				Error("AudioMan was available, but no usable runtime mixer group could be resolved.");
				return;
			}
			HashSet<GameObject> visited = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance);
			for (int i = 0; i < RegisteredRoots.Count; i++)
			{
				GameObject val = RegisteredRoots[i];
				if (IsUsable((Object)(object)val))
				{
					if (ProcessedNodes.TryGetValue(val, out var value))
					{
						ValidateNodeGraph(value, visited);
					}
					else
					{
						ProcessRoot(val);
					}
				}
			}
		}

		private static void RegisterRoot(GameObject root)
		{
			if (RegisteredRootSet.Add(root))
			{
				RegisteredRoots.Add(root);
			}
		}

		private static void ProcessRoot(GameObject root)
		{
			if (!MixerCatalog.IsReady || !IsUsable((Object)(object)root))
			{
				return;
			}
			if (ProcessedNodes.TryGetValue(root, out var value))
			{
				ValidateNodeGraph(value, new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance));
			}
			else
			{
				if (!ActiveProcessing.Add(root))
				{
					return;
				}
				ProcessedNode processedNode = new ProcessedNode
				{
					Root = root
				};
				ProcessedNodes[root] = processedNode;
				try
				{
					ScanAudioSources(root, processedNode);
					ScanBehaviourReferences(root, processedNode);
				}
				catch (Exception ex)
				{
					Error("Failed to process audio graph for '" + SafeName((Object)(object)root) + "': " + ex);
				}
				finally
				{
					ActiveProcessing.Remove(root);
				}
			}
		}

		private static void ScanAudioSources(GameObject root, ProcessedNode node)
		{
			AudioSource[] componentsInChildren;
			try
			{
				componentsInChildren = root.GetComponentsInChildren<AudioSource>(true);
			}
			catch (Exception ex)
			{
				Warn("Could not enumerate AudioSources under '" + SafeName((Object)(object)root) + "': " + ex.Message);
				return;
			}
			if (componentsInChildren == null)
			{
				return;
			}
			foreach (AudioSource val in componentsInChildren)
			{
				if (IsUsable((Object)(object)val))
				{
					if (!SourceBindings.TryGetValue(val, out var value))
					{
						value = new AudioBinding
						{
							Source = val,
							Target = ClassifySource(root, val)
						};
						SourceBindings[val] = value;
					}
					if (!node.AudioBindings.Contains(value))
					{
						node.AudioBindings.Add(value);
					}
					ApplyBinding(value, root);
				}
			}
		}

		private static void ScanBehaviourReferences(GameObject root, ProcessedNode node)
		{
			MonoBehaviour[] componentsInChildren;
			try
			{
				componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			}
			catch (Exception ex)
			{
				Warn("Could not enumerate MonoBehaviours under '" + SafeName((Object)(object)root) + "': " + ex.Message);
				return;
			}
			if (componentsInChildren == null)
			{
				return;
			}
			HashSet<object> managedVisited = new HashSet<object>(ReferenceComparer<object>.Instance);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (IsUsable((Object)(object)val) && !(val is ZSFX))
				{
					TraverseManagedObject(val, root, node, managedVisited, 0, isComponentRoot: true);
				}
			}
		}

		private static void TraverseManagedObject(object value, GameObject ownerRoot, ProcessedNode node, HashSet<object> managedVisited, int depth, bool isComponentRoot)
		{
			if (value == null || depth > 24)
			{
				return;
			}
			Type type = value.GetType();
			if (!type.IsValueType && !managedVisited.Add(value))
			{
				return;
			}
			FieldInfo[] traversalFields = GetTraversalFields(type, isComponentRoot);
			foreach (FieldInfo fieldInfo in traversalFields)
			{
				object value2;
				try
				{
					value2 = fieldInfo.GetValue(value);
				}
				catch
				{
					continue;
				}
				TraverseValue(value2, ownerRoot, node, managedVisited, depth + 1);
			}
		}

		private static void TraverseValue(object value, GameObject ownerRoot, ProcessedNode node, HashSet<object> managedVisited, int depth)
		{
			if (value == null || depth > 24)
			{
				return;
			}
			EffectList val = (EffectList)((value is EffectList) ? value : null);
			if (val != null)
			{
				TraverseEffectList(val, ownerRoot, node);
				return;
			}
			GameObject val2 = (GameObject)((value is GameObject) ? value : null);
			if ((Object)(object)val2 != (Object)null)
			{
				HandleReferencedGameObject(val2, ownerRoot, node);
				return;
			}
			Component val3 = (Component)((value is Component) ? value : null);
			if ((Object)(object)val3 != (Object)null)
			{
				if (IsUsable((Object)(object)val3))
				{
					HandleReferencedGameObject(val3.gameObject, ownerRoot, node);
				}
				return;
			}
			AudioClip val4 = (AudioClip)((value is AudioClip) ? value : null);
			if ((Object)(object)val4 != (Object)null)
			{
				return;
			}
			Object val5 = (Object)((value is Object) ? value : null);
			if (val5 != (Object)null)
			{
				ScriptableObject val6 = (ScriptableObject)((value is ScriptableObject) ? value : null);
				if ((Object)(object)val6 != (Object)null)
				{
					TraverseManagedObject(val6, ownerRoot, node, managedVisited, depth, isComponentRoot: false);
				}
				return;
			}
			if (value is IDictionary dictionary)
			{
				int num = 0;
				{
					foreach (DictionaryEntry item in dictionary)
					{
						TraverseValue(item.Value, ownerRoot, node, managedVisited, depth + 1);
						num++;
						if (num >= 4096)
						{
							break;
						}
					}
					return;
				}
			}
			if (value is IEnumerable enumerable && !(value is string))
			{
				int num2 = 0;
				{
					foreach (object item2 in enumerable)
					{
						TraverseValue(item2, ownerRoot, node, managedVisited, depth + 1);
						num2++;
						if (num2 >= 4096)
						{
							break;
						}
					}
					return;
				}
			}
			Type type = value.GetType();
			if (ShouldTraverseManagedType(type))
			{
				TraverseManagedObject(value, ownerRoot, node, managedVisited, depth, isComponentRoot: false);
			}
		}

		private static void TraverseEffectList(EffectList effectList, GameObject ownerRoot, ProcessedNode node)
		{
			EffectData[] effectPrefabs = effectList.m_effectPrefabs;
			if (effectPrefabs == null)
			{
				return;
			}
			for (int i = 0; i < effectPrefabs.Length; i++)
			{
				GameObject prefab = effectPrefabs[i].m_prefab;
				if (IsUsable((Object)(object)prefab))
				{
					HandleReferencedGameObject(prefab, ownerRoot, node);
				}
			}
		}

		private static void HandleReferencedGameObject(GameObject referenced, GameObject ownerRoot, ProcessedNode ownerNode)
		{
			if (IsUsable((Object)(object)referenced) && IsUsable((Object)(object)ownerRoot) && !IsInsideHierarchy(referenced, ownerRoot))
			{
				if (ownerNode.ReferencedRootSet.Add(referenced))
				{
					ownerNode.ReferencedRoots.Add(referenced);
				}
				ProcessRoot(referenced);
			}
		}

		private static bool IsInsideHierarchy(GameObject candidate, GameObject root)
		{
			if (candidate == root)
			{
				return true;
			}
			try
			{
				Transform transform = candidate.transform;
				Transform transform2 = root.transform;
				return (Object)(object)transform != (Object)null && (Object)(object)transform2 != (Object)null && transform.IsChildOf(transform2);
			}
			catch
			{
				return false;
			}
		}

		private static AudioTarget ClassifySource(GameObject root, AudioSource source)
		{
			AudioTarget audioTarget = FindExplicitOverride(((Component)source).gameObject, root);
			if (audioTarget != null)
			{
				return audioTarget;
			}
			if (HierarchyHasSfxPrefix(((Component)source).gameObject, root))
			{
				return RouteTarget(AudioRoute.SFX, "sfx_/vfx_/fx_ GameObject name");
			}
			if (HierarchyHasZSFX(((Component)source).gameObject, root))
			{
				return RouteTarget(AudioRoute.SFX, "ZSFX context");
			}
			AudioMixerGroup val = null;
			try
			{
				val = source.outputAudioMixerGroup;
			}
			catch
			{
				val = null;
			}
			AudioTarget audioTarget2 = ClassifyOldMixerGroup(val);
			if (audioTarget2 != null)
			{
				return audioTarget2;
			}
			return RouteTarget(AudioRoute.SFX, "default SFX fallback");
		}

		private static AudioTarget FindExplicitOverride(GameObject sourceObject, GameObject root)
		{
			Transform val = null;
			Transform val2 = null;
			try
			{
				val = (((Object)(object)sourceObject != (Object)null) ? sourceObject.transform : null);
				val2 = (((Object)(object)root != (Object)null) ? root.transform : null);
			}
			catch
			{
				return null;
			}
			while ((Object)(object)val != (Object)null)
			{
				string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : null);
				if (!string.IsNullOrEmpty(text) && Overrides.TryGetValue(text, out var value))
				{
					if (value.UsesNamedGroup)
					{
						return NamedTarget(value.RuntimeGroupName, "explicit mixer-group override on '" + text + "'");
					}
					return RouteTarget(value.Route, "explicit route override on '" + text + "'");
				}
				if (val == val2)
				{
					break;
				}
				val = val.parent;
			}
			return null;
		}

		private static bool HierarchyHasSfxPrefix(GameObject sourceObject, GameObject root)
		{
			Transform val = null;
			Transform val2 = null;
			try
			{
				val = (((Object)(object)sourceObject != (Object)null) ? sourceObject.transform : null);
				val2 = (((Object)(object)root != (Object)null) ? root.transform : null);
			}
			catch
			{
				return false;
			}
			while ((Object)(object)val != (Object)null)
			{
				string name = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : null);
				if (HasSfxPrefix(name))
				{
					return true;
				}
				if (val == val2)
				{
					break;
				}
				val = val.parent;
			}
			return false;
		}

		private static bool HierarchyHasZSFX(GameObject sourceObject, GameObject root)
		{
			Transform val = null;
			Transform val2 = null;
			try
			{
				val = (((Object)(object)sourceObject != (Object)null) ? sourceObject.transform : null);
				val2 = (((Object)(object)root != (Object)null) ? root.transform : null);
			}
			catch
			{
				return false;
			}
			while ((Object)(object)val != (Object)null)
			{
				try
				{
					if ((Object)(object)((Component)val).GetComponent<ZSFX>() != (Object)null)
					{
						return true;
					}
				}
				catch
				{
				}
				if (val == val2)
				{
					break;
				}
				val = val.parent;
			}
			return false;
		}

		private static AudioTarget ClassifyOldMixerGroup(AudioMixerGroup oldGroup)
		{
			if ((Object)(object)oldGroup == (Object)null || string.IsNullOrEmpty(((Object)oldGroup).name))
			{
				return null;
			}
			string name = ((Object)oldGroup).name;
			if (IsGenericMasterName(name))
			{
				return null;
			}
			if (ContainsInvariant(name, "ambient"))
			{
				return RouteTarget(AudioRoute.Ambient, "old mixer-group name: " + name);
			}
			if (ContainsInvariant(name, "music"))
			{
				return RouteTarget(AudioRoute.Music, "old mixer-group name: " + name);
			}
			if (ContainsInvariant(name, "sfx") || ContainsInvariant(name, "vfx") || ContainsInvariant(name, "effect"))
			{
				return RouteTarget(AudioRoute.SFX, "old mixer-group name: " + name);
			}
			if (MixerCatalog.HasNamedGroup(name))
			{
				return NamedTarget(name, "matching runtime mixer-group name");
			}
			return null;
		}

		private static bool HasSfxPrefix(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			return name.StartsWith("sfx_", StringComparison.OrdinalIgnoreCase) || name.StartsWith("vfx_", StringComparison.OrdinalIgnoreCase) || name.StartsWith("fx_", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsGenericMasterName(string name)
		{
			return string.Equals(name, "Master", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "MasterAudio", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "Master Mixer", StringComparison.OrdinalIgnoreCase);
		}

		private static bool ContainsInvariant(string text, string fragment)
		{
			return text != null && fragment != null && text.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static AudioTarget RouteTarget(AudioRoute route, string reason)
		{
			return new AudioTarget
			{
				Kind = TargetKind.Route,
				Route = route,
				RuntimeGroupName = null,
				Reason = reason
			};
		}

		private static AudioTarget NamedTarget(string groupName, string reason)
		{
			return new AudioTarget
			{
				Kind = TargetKind.NamedRuntimeGroup,
				Route = AudioRoute.SFX,
				RuntimeGroupName = groupName,
				Reason = reason
			};
		}

		private static void ApplyBinding(AudioBinding binding, GameObject semanticRoot)
		{
			if (binding == null || !IsUsable((Object)(object)binding.Source))
			{
				return;
			}
			AudioMixerGroup val = MixerCatalog.Resolve(binding.Target);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			AudioMixerGroup val2 = null;
			try
			{
				val2 = binding.Source.outputAudioMixerGroup;
			}
			catch
			{
				val2 = null;
			}
			if (val2 != val)
			{
				try
				{
					binding.Source.outputAudioMixerGroup = val;
				}
				catch (Exception ex)
				{
					Warn("Could not route AudioSource '" + SafeName((Object)(object)((Component)binding.Source).gameObject) + "' under '" + SafeName((Object)(object)semanticRoot) + "': " + ex.Message);
					return;
				}
			}
			if (DebugLogging)
			{
				Info("AudioSource '" + SafeName((Object)(object)((Component)binding.Source).gameObject) + "' under '" + SafeName((Object)(object)semanticRoot) + "' -> '" + ((Object)val).name + "' (" + ((binding.Target != null) ? binding.Target.Reason : "unknown") + ").");
			}
		}

		private static void ValidateNodeGraph(ProcessedNode node, HashSet<GameObject> visited)
		{
			if (node == null || !IsUsable((Object)(object)node.Root) || !visited.Add(node.Root))
			{
				return;
			}
			for (int i = 0; i < node.AudioBindings.Count; i++)
			{
				ApplyBinding(node.AudioBindings[i], node.Root);
			}
			for (int j = 0; j < node.ReferencedRoots.Count; j++)
			{
				GameObject val = node.ReferencedRoots[j];
				if (IsUsable((Object)(object)val))
				{
					if (ProcessedNodes.TryGetValue(val, out var value))
					{
						ValidateNodeGraph(value, visited);
					}
					else
					{
						ProcessRoot(val);
					}
				}
			}
		}

		private static FieldInfo[] GetTraversalFields(Type type, bool isComponentRoot)
		{
			if (TraversalFields.TryGetValue(type, out var value))
			{
				return value;
			}
			List<FieldInfo> list = new List<FieldInfo>();
			Type type2 = type;
			while (type2 != null && type2 != typeof(object) && !(type2 == typeof(MonoBehaviour)) && !(type2 == typeof(Behaviour)) && !(type2 == typeof(Component)) && !(type2 == typeof(ScriptableObject)) && !(type2 == typeof(Object)))
			{
				FieldInfo[] array;
				try
				{
					array = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					array = null;
				}
				if (array != null)
				{
					foreach (FieldInfo fieldInfo in array)
					{
						if (ShouldInspectField(fieldInfo))
						{
							list.Add(fieldInfo);
						}
					}
				}
				type2 = type2.BaseType;
			}
			value = list.ToArray();
			TraversalFields[type] = value;
			return value;
		}

		private static bool ShouldInspectField(FieldInfo field)
		{
			if (field == null || field.IsStatic || field.IsLiteral || field.IsNotSerialized)
			{
				return false;
			}
			Type fieldType = field.FieldType;
			if (fieldType == null)
			{
				return false;
			}
			if (typeof(EffectList).IsAssignableFrom(fieldType) || typeof(GameObject).IsAssignableFrom(fieldType) || typeof(Component).IsAssignableFrom(fieldType) || typeof(ScriptableObject).IsAssignableFrom(fieldType))
			{
				return true;
			}
			if (fieldType.IsArray || typeof(IEnumerable).IsAssignableFrom(fieldType))
			{
				return true;
			}
			if (fieldType == typeof(object) || fieldType.IsInterface || fieldType.IsAbstract)
			{
				return HasSerializeReferenceAttribute(field);
			}
			return ShouldTraverseManagedType(fieldType);
		}

		private static bool HasSerializeReferenceAttribute(FieldInfo field)
		{
			try
			{
				object[] customAttributes = field.GetCustomAttributes(inherit: false);
				if (customAttributes == null)
				{
					return false;
				}
				foreach (object obj in customAttributes)
				{
					if (obj != null)
					{
						string fullName = obj.GetType().FullName;
						if (string.Equals(fullName, "UnityEngine.SerializeReference", StringComparison.Ordinal))
						{
							return true;
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool ShouldTraverseManagedType(Type type)
		{
			if (type == null || type.IsPrimitive || type.IsEnum || type.IsPointer)
			{
				return false;
			}
			if (type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(TimeSpan) || type == typeof(Guid) || type == typeof(IntPtr) || type == typeof(UIntPtr) || type == typeof(Type))
			{
				return false;
			}
			if (typeof(Delegate).IsAssignableFrom(type))
			{
				return false;
			}
			if (typeof(Object).IsAssignableFrom(type))
			{
				return typeof(ScriptableObject).IsAssignableFrom(type);
			}
			string text = type.Namespace ?? string.Empty;
			if (text.StartsWith("System", StringComparison.Ordinal) || text.StartsWith("UnityEngine", StringComparison.Ordinal))
			{
				return false;
			}
			return type.IsClass || type.IsValueType;
		}

		private static void InvalidateClassificationCaches()
		{
			ProcessedNodes.Clear();
			SourceBindings.Clear();
			ActiveProcessing.Clear();
			if (!MixerCatalog.IsReady)
			{
				return;
			}
			for (int i = 0; i < RegisteredRoots.Count; i++)
			{
				GameObject val = RegisteredRoots[i];
				if (IsUsable((Object)(object)val))
				{
					ProcessRoot(val);
				}
			}
		}

		private static bool IsUsable(Object obj)
		{
			if (obj == null)
			{
				return false;
			}
			try
			{
				return obj != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static string SafeName(Object obj)
		{
			if (!IsUsable(obj))
			{
				return "<null>";
			}
			try
			{
				return obj.name ?? "<unnamed>";
			}
			catch
			{
				return "<unavailable>";
			}
		}

		private static void Info(string message)
		{
			if (_infoLogger != null)
			{
				_infoLogger("[AudioRoutingService] " + message);
			}
		}

		private static void Warn(string message)
		{
			if (_warningLogger != null)
			{
				_warningLogger("[AudioRoutingService] " + message);
			}
		}

		private static void Error(string message)
		{
			if (_errorLogger != null)
			{
				_errorLogger("[AudioRoutingService] " + message);
			}
		}

		private static void WarnOnce(string key, string message)
		{
			if (WarnedKeys.Add(key))
			{
				Warn(message);
			}
		}
	}
}
namespace RavenwoodBalrondPieces
{
	internal sealed class BuildPieceDefinition
	{
		internal string PrefabName { get; private set; }

		internal string DefaultRecipe { get; private set; }

		internal string CraftingStationPrefab { get; private set; }

		internal UsageTagFlags BaseUsage { get; private set; }

		internal string FuelPrefab { get; private set; }

		internal BuildPieceDefinition(string prefabName, string defaultRecipe, string craftingStationPrefab, UsageTagFlags baseUsage, string fuelPrefab = null)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			PrefabName = prefabName;
			DefaultRecipe = defaultRecipe;
			CraftingStationPrefab = craftingStationPrefab;
			BaseUsage = baseUsage;
			FuelPrefab = fuelPrefab;
		}
	}
	internal static class BuildPieceList
	{
		internal static readonly BuildPieceDefinition[] Definitions = new BuildPieceDefinition[149]
		{
			new BuildPieceDefinition("clutter_bookset1_bal", "FineWood:1,LeatherScraps:1,Resin:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("clutter_bookset2_bal", "FineWood:1,LeatherScraps:1,Resin:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("clutter_bookset3_bal", "FineWood:1,LeatherScraps:1,Resin:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("clutter_bottleset_bal", "RWc_Deer:5", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("clutter_cupset_bal", "RWc_Deer:5", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("clutter_tableset_bal", "RWc_Deer:5", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("Hearth_1x3_bal", "Stone:6,RWc_Deer:5", "piece_stonecutter", (UsageTagFlags)1, "Wood"),
			new BuildPieceDefinition("Hearth_2x3_bal", "Stone:12,RWc_Deer:5", "piece_stonecutter", (UsageTagFlags)1, "Wood"),
			new BuildPieceDefinition("Hearth_2x2_bal", "Stone:9,RWc_Deer:5", "piece_stonecutter", (UsageTagFlags)1, "Wood"),
			new BuildPieceDefinition("charred_chest_bal", "CharredBone:10,FlametalNew:10,MorgenHeart:1,RWc_Snake:1", "blackforge", (UsageTagFlags)128),
			new BuildPieceDefinition("dvergr_bed_bal", "Wood:2,ScaleHide:2,YggdrasilWood:2,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("dvergr_chair_bal", "LeatherScraps:2,YggdrasilWood:2,Copper:2,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("dvergr_chest_bal", "BronzeNails:12,YggdrasilWood:5,Copper:5,RWc_Snake:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("dvergr_shelf_bal", "Wood:2,YggdrasilWood:2,Copper:2,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("dvergr_stool_bal", "Wood:2,YggdrasilWood:2,Copper:2,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("dvergr_table_bal", "Wood:2,YggdrasilWood:2,Copper:2,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_chest_private_bal", "BronzeNails:20,YggdrasilWood:5,DvergrKeyFragment:1,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("bed_noble_bal", "FineWood:5,JuteRed:2,LinenThread:5,RWc_Deer:5", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("black_carpet_end_bal", "TrollHide:1,LinenThread:1,Coal:4,RWc_Bear:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("black_carpet_mid_bal", "TrollHide:5,LinenThread:4,Coal:8,RWc_Bear:3", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("ground_spike_trap_bal", "Root:2,Wood:2,BoneFragments:5,RWc_Bear:3", "piece_workbench", (UsageTagFlags)1),
			new BuildPieceDefinition("piece_banner_black1_bal", "FineWood:1,LeatherScraps:4,Blueberries:2,RWc_Deer:3", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_banner_black2_bal", "FineWood:1,LeatherScraps:4,Cloudberry:2,RWc_Deer:3", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_banner_black3_bal", "FineWood:1,LeatherScraps:4,Guck:2,RWc_Deer:3", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_banner_black4_bal", "FineWood:1,LeatherScraps:4,Bloodbag:2,RWc_Deer:3", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_bed03_bal", "JuteRed:2,JuteBlue:4,YggdrasilWood:20,RWc_Snake:1", "piece_workbench", (UsageTagFlags)0),
			new BuildPieceDefinition("piece_candlechandelier_bal", "Honey:8,Chain:5,Iron:4,RWc_Snake:2", "forge", (UsageTagFlags)128, "Crystal"),
			new BuildPieceDefinition("piece_chest_jewelbox_bal", "FineWood:10,HardAntler:1,RWc_Deer:10", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_chest_stone_bal", "Stone:30,Flint:10,SharpeningStone:1,RWc_Deer:5", "piece_stonecutter", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_crystal_walltorch_bal", "Crystal:2,Iron:2,RWc_Wolf:1", "forge", (UsageTagFlags)128, "Crystal"),
			new BuildPieceDefinition("piece_crystalchandelier_bal", "Crystal:12,Iron:6,Chain:5,RWc_Wolf:2", "forge", (UsageTagFlags)128, "Resin"),
			new BuildPieceDefinition("piece_curtain_big_bal", "Silver:2,JuteRed:4,LeatherScraps:8,RWc_Wolf:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_elegant_bench_bal", "Iron:1,Blackwood:4,JuteRed:1,RWc_Snake:1", "forge", (UsageTagFlags)0),
			new BuildPieceDefinition("piece_elegant_bench2_bal", "Iron:1,Blackwood:4,JuteRed:1,RWc_Snake:1", "forge", (UsageTagFlags)0),
			new BuildPieceDefinition("piece_emberwood_stool_bal", "Iron:1,Blackwood:2,JuteRed:1,RWc_Snake:1", "forge", (UsageTagFlags)0),
			new BuildPieceDefinition("piece_emberwoodchair_bal", "Iron:2,Blackwood:5,JuteRed:1,RWc_Snake:1", "forge", (UsageTagFlags)0),
			new BuildPieceDefinition("piece_table_round_noble_bal", "Iron:2,Blackwood:6,JuteRed:1,RWc_Snake:1", "forge", (UsageTagFlags)0),
			new BuildPieceDefinition("runefire_bal", "Thunderstone:2,TrophySkeleton:5,Flint:10,RWc_Bear:5", "piece_stonecutter", (UsageTagFlags)1, "TrophySkeleton"),
			new BuildPieceDefinition("linen_carpet_bal", "Bloodbag:2,LinenThread:10,RWc_Wolf:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("rug_neck_bal", "AskHide:2,RWc_Snake:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("rug_fox_bal", "LeatherScraps:20,RWc_Deer:5", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("rug_bear_bal", "BjornHide:4,RWc_Bear:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("wood_pillar4_bal", "Wood:4,RWc_Deer:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("wood_long_stair_bal", "FineWood:15,RWc_Deer:5", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_grausten_roof_45_top_bal", "Grausten:5,RWc_Snake:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("dverger_gate_bal", "BlackMarble:12,Iron:6,MechanicalSpring:1,RWc_Lion:1", "blackforge", (UsageTagFlags)4),
			new BuildPieceDefinition("dvergr_secretdoor_bal", "BlackMarble:13,MechanicalSpring:1,RWc_Wolf:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("giant_metal_gate_bal", "BlackMarble:6,Iron:6,MechanicalSpring:1,RWc_Lion:1", "blackforge", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_floor4m_bal", "BlackMarble:12,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_roof27_bal", "BlackMarble:6,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_stair_inner_bal", "BlackMarble:6,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_stair_outer_bal", "BlackMarble:6,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_stone_ladder_bal", "BlackMarble:4,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("crystal_tile_floor_2x2_bal", "Crystal:3,RWc_Wolf:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("crystal_wall_2x2_bal", "Crystal:3,RWc_Wolf:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("emberwood_pillar2_bal", "RoundLog:3,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("emberwood_pillar4_bal", "RoundLog:6,Flint:4,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("plate_gate_bal", "FineWood:4,Iron:2,BlackMetal:4,RWc_Wolf:1", "forge", (UsageTagFlags)4),
			new BuildPieceDefinition("rawstone_pole_bal", "Stone:2,Flint:2,Wood:2,RWc_Deer:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("rune_floor_bal", "Stone:8,Crystal:4,RWc_Wolf:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_floor_triangle_bal", "Stone:3,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_long_stair_bal", "Stone:16,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_pole_bal", "Stone:2,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_railing_bal", "Stone:3,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_roof27_bal", "Stone:6,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_corner_bal", "Stone:8,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_corner_left_bal", "Stone:8,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_inner_bal", "Stone:8,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_outer_bal", "Stone:8,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_railing_bal", "Stone:10,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_railing_left_bal", "Stone:9,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stair_railing_right_bal", "Stone:9,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_stepladder_bal", "Stone:5,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stonemoss_tile_floor_2x2_bal", "Stone:6,Wood:2,RWc_Deer:2", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_creep_slope_inverted_2x2x1_bal", "BlackMarble:2,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_1x1_enforced_bal", "BlackMarble:2,CopperScrap:1,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_1x1_enforced_bal", "Stone:3,CopperScrap:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_Wall_Window_2x2_bal", "BlackMarble:4,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("stone_beam_bal", "Stone:2,RWc_Deer:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("blackmarble_long_stair_bal", "BlackMarble:16,RWc_Bear:1", "piece_stonecutter", (UsageTagFlags)4),
			new BuildPieceDefinition("clay_stair_bal", "Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("ClayBeam_bal", "Flint:1,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("ClayCube_bal", "Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("ClayPole_bal", "Flint:1,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("clayr_arch_bal", "Flint:1,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("ClayWall_bal", "Wood:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("bg_stake_wall_bal", "RoundLog:8,Wood:4,RWc_Bear:1", "piece_workbench", (UsageTagFlags)1),
			new BuildPieceDefinition("leather_roof_bal", "Wood:2,LeatherScraps:2,RWc_Deer:2", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("clay_floor_2x2_bal", "Wood:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("bush_roof_bal", "Wood:5,Dandelion:5,Thistle:5,RWc_Deer:5", "piece_workbench", (UsageTagFlags)0),
			new BuildPieceDefinition("bush_roof_top_bal", "Wood:5,Dandelion:5,Thistle:5,RWc_Deer:5", "piece_workbench", (UsageTagFlags)0),
			new BuildPieceDefinition("bush_roof_icorner_bal", "Wood:5,Dandelion:5,Thistle:5,RWc_Deer:5", "piece_workbench", (UsageTagFlags)0),
			new BuildPieceDefinition("bush_roof_ocorner_bal", "Wood:5,Dandelion:5,Thistle:5,RWc_Deer:5", "piece_workbench", (UsageTagFlags)0),
			new BuildPieceDefinition("piece_sharpstakes_big_bal", "Wood:10,RoundLog:10,RWc_Bear:1", "piece_workbench", (UsageTagFlags)1),
			new BuildPieceDefinition("Piece_hardwood_pillar_arch_bal", "RoundLog:3,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillar_arch_small_bal", "RoundLog:1,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillarbase_medium_bal", "RoundLog:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillarbase_small_bal", "RoundLog:1,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillarbase_tapered_bal", "RoundLog:3,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillarbase_tapered_inverted_bal", "RoundLog:3,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillarbeam_medium_bal", "RoundLog:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("Piece_hardwood_pillarbeam_small_bal", "RoundLog:1,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_arch_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_arch_corner_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_arch_corner2_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_corner_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_corner2_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("piece_hardwood_roof_45_top_bal", "RoundLog:2,Flint:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("wood_roof_flat_bal", "Wood:2,RWc_Deer:1", "piece_workbench", (UsageTagFlags)0),
			new BuildPieceDefinition("silver_ore_pile_bal", "SilverOre:30", "forge", (UsageTagFlags)1),
			new BuildPieceDefinition("bcopper_ore_pile_bal", "CopperOre:30", "forge", (UsageTagFlags)1),
			new BuildPieceDefinition("biron_ore_pile_bal", "IronScrap:30", "forge", (UsageTagFlags)1),
			new BuildPieceDefinition("bmetal_ore_pile_bal", "BlackMetalScrap:30", "forge", (UsageTagFlags)0),
			new BuildPieceDefinition("flametal_ore_pile_bal", "FlametalOreNew:30", "blackforge", (UsageTagFlags)0),
			new BuildPieceDefinition("straw_floor_2x2_bal", "Dandelion:5,RWc_Deer:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("rostrum_bal", "FineWood:3,Resin:3,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("sulfur_cauldron_bal", "BlackMetal:3,SulfurStone:3,RWc_Wolf:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("target_practice_bal", "Wood:3,Dandelion:3,LeatherScraps:3,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("fishing_rack_bal", "Wood:3,FishRaw:5,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("hardwood_door_bal", "RoundLog:3,IronScrap:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)4),
			new BuildPieceDefinition("animal_cages_bal", "Wood:10,LeatherScraps:5,RWc_Deer:3", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("supply_shelf_bal", "FineWood:5,Bronze:2,LeatherScraps:3,RWc_Bear:2", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("weapon_rack_bal", "Wood:6,Iron:1,Bronze:1,RWc_Snake:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("blackmarble_sarcophagus_bal", "BlackMarble:10,BoneFragments:10,DvergrKeyFragment:1,RWc_Wolf:1", "piece_stonecutter", (UsageTagFlags)128),
			new BuildPieceDefinition("bookcabinet_bal", "FineWood:8,LeatherScraps:10,RWc_Bear:5,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("herb_ladder_bal", "RoundLog:3,Dandelion:2,FreshSeaweed:2,RWc_Bear:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("hook_itemstand_bal", "Chain:1,Iron:2,RWc_Snake:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("itemstand26_inner_bal", "FineWood:2,Wood:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("itemstand26_outer_bal", "FineWood:2,Wood:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("itemstand45_inner_bal", "FineWood:2,Wood:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("itemstand45_outer_bal", "FineWood:2,Wood:1,RWc_Deer:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_ashwood_echandelier_bal", "Flametal:4,Blackwood:2,Resin:4,RWc_Lion:1", "blackforge", (UsageTagFlags)128, "Resin"),
			new BuildPieceDefinition("piece_banner_metal1_long_bal", "Iron:1,LinenThread:2,Cloudberry:4,RWc_Wolf:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_banner_metal2_long_bal", "Iron:1,LinenThread:2,Raspberry:4,RWc_Deer:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_banner_metal3_long_bal", "Iron:1,LinenThread:2,Guck:4,RWc_Snake:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_banner_metal4_long_bal", "Iron:1,LinenThread:2,Blueberries:4,RWc_Bear:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_braziercolumn_bal", "Stone:12,Coal:2,Iron:1,RWc_Snake:1", "piece_stonecutter", (UsageTagFlags)1, "Coal"),
			new BuildPieceDefinition("piece_clamChest_bal", "BoneFragments:10,AmberPearl:1,RWc_Deer:2", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_curtain_side_bal", "Silver:1,JuteBlue:2,LeatherScraps:4,RWc_Wolf:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_sofa_bal", "JuteRed:4,JuteBlue:1,FineWood:9,RWc_Wolf:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_sofa_reverse_bal", "JuteRed:4,JuteBlue:1,FineWood:9,RWc_Wolf:1", "forge", (UsageTagFlags)128),
			new BuildPieceDefinition("piece_table_drakkar_bal", "YggdrasilWood:20,CeramicPlate:20,BronzeNails:100,RWc_Lion:2", "blackforge", (UsageTagFlags)128),
			new BuildPieceDefinition("rostrum_itemstand_bal", "Stone:5,Flint:5,Resin:4,RWc_Deer:2", "piece_stonecutter", (UsageTagFlags)128),
			new BuildPieceDefinition("scarecrow_bal", "Wood:2,LeatherScraps:5,LinenThread:3,RWc_Snake:1", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("StatueRaven_bal", "Stone:20,RWc_Deer:5", "piece_stonecutter", (UsageTagFlags)1),
			new BuildPieceDefinition("StatueThor_bal", "BlackMarble:25,Stone:10,Ruby:2,RWc_Wolf:1", "piece_stonecutter", (UsageTagFlags)1),
			new BuildPieceDefinition("torn_carpet_bal", "Bloodbag:3,LinenThread:9,JuteRed:3,RWc_Snake:3", "piece_workbench", (UsageTagFlags)128),
			new BuildPieceDefinition("weathervane_bal", "Wood:5,Bronze:5,RWc_Bear:5", "forge", (UsageTagFlags)512)
		};

		internal static readonly string[] buildPieces = CreateNameArray();

		private static readonly Dictionary<string, BuildPieceDefinition> ByName = CreateMap();

		internal static BuildPieceDefinition Find(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return null;
			}
			BuildPieceDefinition value;
			return ByName.TryGetValue(prefabName, out value) ? value : null;
		}

		private static string[] CreateNameArray()
		{
			string[] array = new string[Definitions.Length];
			for (int i = 0; i < Definitions.Length; i++)
			{
				array[i] = Definitions[i].PrefabName;
			}
			return array;
		}

		private static Dictionary<string, BuildPieceDefinition> CreateMap()
		{
			Dictionary<string, BuildPieceDefinition> dictionary = new Dictionary<string, BuildPieceDefinition>(StringComparer.Ordinal);
			for (int i = 0; i < Definitions.Length; i++)
			{
				dictionary[Definitions[i].PrefabName] = Definitions[i];
			}
			return dictionary;
		}
	}
	internal static class BuildPieceRecipeConfig
	{
		private const string GeneralSection = "1 - General";

		private const string RecipeSection = "2 - Build Piece Recipes";

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

		internal static ConfigEntry<bool> LockConfiguration { get; private set; }

		internal static event Action<string> RecipeChanged;

		internal static void Initialize(Launch plugin)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			if ((Object)(object)plugin == (Object)null)
			{
				throw new ArgumentNullException("plugin");
			}
			ResetEntries();
			LockConfiguration = ((BaseUnityPlugin)plugin).Config.Bind<bool>("1 - General", "Lock Configuration", true, new ConfigDescription("When enabled, build-piece recipe settings are controlled by the server/host for connected clients.", (AcceptableValueBase)null, Array.Empty<object>()));
			ServerSyncBridge.AddLockingConfigEntry(LockConfiguration);
			BuildPieceDefinition[] definitions = BuildPieceList.Definitions;
			foreach (BuildPieceDefinition buildPieceDefinition in definitions)
			{
				string prefabName = buildPieceDefinition.PrefabName;
				ConfigEntry<string> val = ((BaseUnityPlugin)plugin).Config.Bind<string>("2 - Build Piece Recipes", prefabName, buildPieceDefinition.DefaultRecipe, new ConfigDescription("Recipe for '" + prefabName + "'. Format: ItemPrefab:Amount,ItemPrefab:Amount. Example: Stone:100 or Stone:80,Iron:10. Use NONE for a zero-cost piece.", (AcceptableValueBase)null, Array.Empty<object>()));
				val.SettingChanged += OnRecipeSettingChanged;
				RecipeEntries[prefabName] = val;
				ServerSyncBridge.AddConfigEntry<string>(val);
			}
		}

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

		internal static void Reset()
		{
			ResetEntries();
			LockConfiguration = null;
			BuildPieceRecipeConfig.RecipeChanged = null;
		}

		private static void ResetEntries()
		{
			foreach (KeyValuePair<string, ConfigEntry<string>> recipeEntry in RecipeEntries)
			{
				if (recipeEntry.Value != null)
				{
					recipeEntry.Value.SettingChanged -= OnRecipeSettingChanged;
				}
			}
			RecipeEntries.Clear();
		}

		private static void OnRecipeSettingChanged(object sender, EventArgs eventArgs)
		{
			ConfigEntryBase val = (ConfigEntryBase)((sender is ConfigEntryBase) ? sender : null);
			if (val != null)
			{
				BuildPieceRecipeConfig.RecipeChanged?.Invoke(val.Definition.Key);
			}
		}
	}
	public class BalrondWindControler : MonoBehaviour
	{
		public bool m_windDirection;

		public bool m_northdirection;

		public bool m_;

		private float m_cover;

		public AudioSource[] m_sfxLoops;

		public float m_bomRotationSpeed = 200f;

		public float m_propellerRotationSpeed = -600f;

		public float m_minWindSpeed = 0.1f;

		public float m_minPitch = 1f;

		public float m_maxPitch = 1.5f;

		public float m_maxPitchVel = 1f;

		public float m_maxVol = 0.01f;

		public float m_maxVolVel = 0.5f;

		public float m_audioChangeSpeed = 2f;

		public Transform m_bom;

		public Transform m_kompas;

		public Transform m_propeller;

		private float m_propAngle;

		private Quaternion currentRotation = Quaternion.identity;

		private void Start()
		{
			((MonoBehaviour)this).InvokeRepeating("CheckCover", 0.1f, 5f);
		}

		private void Update()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)EnvMan.instance == (Object)null)
			{
				return;
			}
			float powerOutput = GetPowerOutput();
			Vector3 val = EnvMan.instance.GetWindDir();
			if ((Object)(object)m_propeller != (Object)null)
			{
				val = -val;
			}
			if ((Object)(object)m_bom != (Object)null && ((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				Quaternion val2 = Quaternion.LookRotation(val);
				m_bom.rotation = Quaternion.RotateTowards(m_bom.rotation, val2, m_bomRotationSpeed * powerOutput * Time.deltaTime);
			}
			if ((Object)(object)m_kompas != (Object)null)
			{
				Quaternion val3 = Quaternion.LookRotation(Vector3.forward, Vector3.up);
				m_kompas.rotation = Quaternion.RotateTowards(m_kompas.rotation, val3, m_bomRotationSpeed * powerOutput * Time.deltaTime);
			}
			if ((Object)(object)m_propeller != (Object)null)
			{
				m_propAngle += powerOutput * m_propellerRotationSpeed * Time.deltaTime;
				m_propeller.localRotation = Quaternion.Euler(0f, 0f, m_propAngle);
			}
			if ((Object)(object)m_bom != (Object)null)
			{
				if (Quaternion.Angle(currentRotation, m_bom.rotation) >= 0.1f)
				{
					UpdateAudio(Time.deltaTime);
					currentRotation = m_bom.rotation;
				}
			}
			else
			{
				UpdateAudio(Time.deltaTime);
			}
		}

		public float GetPowerOutput()
		{
			if ((Object)(object)EnvMan.instance == (Object)null)
			{
				return 0f;
			}
			return (1f - m_cover) * Utils.LerpStep(m_minWindSpeed, 1f, EnvMan.instance.GetWindIntensity());
		}

		private void CheckCover()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)m_bom != (Object)null) ? m_bom.position : ((Component)this).transform.position);
			bool flag = default(bool);
			Cover.GetCoverForPoint(val, ref m_cover, ref flag, 0.5f);
		}

		private void UpdateAudio(float dt)
		{
			if (m_sfxLoops == null || m_sfxLoops.Length == 0)
			{
				return;
			}
			float powerOutput = GetPowerOutput();
			float num = Mathf.Lerp(m_minPitch, m_maxPitch, Mathf.Clamp01(powerOutput / m_maxPitchVel));
			float num2 = m_maxVol * Mathf.Clamp01(powerOutput / m_maxVolVel);
			for (int i = 0; i < m_sfxLoops.Length; i++)
			{
				AudioSource val = m_sfxLoops[i];
				if (!((Object)(object)val == (Object)null))
				{
					val.volume = Mathf.MoveTowards(val.volume, num2, m_audioChangeSpeed * dt);
					val.pitch = Mathf.MoveTowards(val.pitch, num, m_audioChangeSpeed * dt);
				}
			}
		}
	}
	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);
		}
	}
	internal sealed class EffectReferenceMapper
	{
		private readonly PrefabLookupCache _prefabCache = new PrefabLookupCache();

		private List<GameObject> _scenePrefabs;

		internal void Rebuild(List<GameObject> scenePrefabs)
		{
			_scenePrefabs = scenePrefabs;
			_prefabCache.Rebuild(scenePrefabs);
		}

		internal void RepairBuildPiece(GameObject prefab)
		{
			if (!((Object)(object)prefab == (Object)null) && _scenePrefabs != null)
			{
				Piece component = prefab.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					RepairEffectList(component.m_placeEffect);
				}
				WearNTear component2 = prefab.GetComponent<WearNTear>();
				if ((Object)(object)component2 != (Object)null)
				{
					RepairEffectList(component2.m_hitEffect);
					RepairEffectList(component2.m_destroyedEffect);
				}
			}
		}

		private void RepairEffectList(EffectList effectList)
		{
			if (effectList == null)
			{
				return;
			}
			EffectData[] effectPrefabs = effectList.m_effectPrefabs;
			if (effectPrefabs == null || effectPrefabs.Length == 0)
			{
				return;
			}
			foreach (EffectData val in effectPrefabs)
			{
				if ((Object)(object)val.m_prefab == (Object)null)
				{
					continue;
				}
				string name = ((Object)val.m_prefab).name;
				if (!string.IsNullOrEmpty(name))
				{
					GameObject val2 = _prefabCache.Find(name, _scenePrefabs);
					if ((Object)(object)val2 != (Object)null)
					{
						val.m_prefab = val2;
					}
				}
			}
		}
	}
	internal sealed class JsonLoader
	{
		private const string EnglishResourceSuffix = "Translations.English.English.json";

		private CustomLocalization _localization;

		private bool _loaded;

		internal void LoadJson()
		{
			if (_loaded)
			{
				return;
			}
			_localization = LocalizationManager.Instance.GetLocalization();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = null;
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			for (int i = 0; i < manifestResourceNames.Length; i++)
			{
				if (manifestResourceNames[i].EndsWith("Translations.English.English.json", StringComparison.OrdinalIgnoreCase))
				{
					text = manifestResourceNames[i];
					break;
				}
			}
			if (text == null)
			{
				throw new InvalidOperationException("Embedded English localization resource was not found.");
			}
			using (Stream stream = executingAssembly.GetManifestResourceStream(text))
			{
				using StreamReader streamReader = new StreamReader(stream);
				_localization.AddJsonFile("English", streamReader.ReadToEnd());
			}
			_loaded = true;
			if (Launch.Log != null)
			{
				Launch.Log.LogInfo((object)"Jotunn English localization loaded.");
			}
		}

		internal void NormalizePiece(GameObject prefab)
		{
			if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrEmpty(((Object)prefab).name))
			{
				Piece component = prefab.GetComponent<Piece>();
				if (!((Object)(object)component == (Object)null))
				{
					string text = "tag_" + ((Object)prefab).name.ToLowerInvariant();
					component.m_name = "$" + text;
					component.m_description = "$" + text + "_description";
				}
			}
		}

		internal void NormalizePieces(IList<GameObject> prefabs)
		{
			if (prefabs != null)
			{
				for (int i = 0; i < prefabs.Count; i++)
				{
					NormalizePiece(prefabs[i]);
				}
			}
		}
	}
	public class ModResourceLoader
	{
		private const string BundleResourceName = "ravenwoodrepack";

		private const string BaseAssetPath = "Assets/Custom/Comission/BuildPieceRepackRavenWood/";

		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 static readonly string[] OtherPrefabNames = new string[1] { "sfx_queendoor_open1" };

		private readonly PrefabLookupCache _scenePrefabCache = new PrefabLookupCache();

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

		private readonly EffectReferenceMapper _effectReferenceMapper = new EffectReferenceMapper();

		private bool _sceneRegistrationCompleted;

		public AssetBundle assetBundle;

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

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

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

		public void loadAssets()
		{
			buildPrefabs.Clear();
			vfxPrefabs.Clear();
			registeredBuildPrefabs.Clear();
			_sceneRegistrationCompleted = false;
			assetBundle = GetAssetBundleFromResources("ravenwoodrepack");
			if (!((Object)(object)assetBundle == (Object)null))
			{
				ShaderReplacement.RegisterBundleShaders(assetBundle);
				LoadPieces("Assets/Custom/Comission/BuildPieceRepackRavenWood/Pieces/");
				LoadOther("Assets/Custom/Comission/BuildPieceRepackRavenWood/Other/");
			}
		}

		public void AddPrefabsToZnetScene(ZNetScene zNetScene)
		{
			if (!((Object)(object)zNetScene == (Object)null) && zNetScene.m_prefabs != null)
			{
				registeredBuildPrefabs.Clear();
				_scenePrefabCache.Rebuild(zNetScene.m_prefabs);
				RebuildSceneHashCache(zNetScene.m_prefabs);
				RegisterPrefabCollection(vfxPrefabs, zNetScene, null);
				RegisterPrefabCollection(buildPrefabs, zNetScene, registeredBuildPrefabs);
				_effectReferenceMapper.Rebuild(zNetScene.m_prefabs);
				for (int i = 0; i < registeredBuildPrefabs.Count; i++)
				{
					_effectReferenceMapper.RepairBuildPiece(registeredBuildPrefabs[i]);
				}
				_sceneRegistrationCompleted = true;
			}
		}

		public void FinalizeZNetSceneSetup(ZNetScene zNetScene)
		{
			if (!((Object)(object)zNetScene == (Object)null) && zNetScene.m_prefabs != null)
			{
				_scenePrefabCache.Rebuild(zNetScene.m_prefabs);
				RefreshRegisteredBuildPrefabs(zNetScene.m_prefabs);
				SetBalrondWindController(zNetScene);
				SetupBuildPiecesList(zNetScene);
				setupBuildPiecesListDB();
			}
		}

		public void setupBuildPiecesListDB()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || instance.m_items == null || !_sceneRegistrationCompleted)
			{
				return;
			}
			GameObject val = instance.GetItemPrefab("Hammer");
			if ((Object)(object)val == (Object)null)
			{
				val = instance.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "Hammer");
			}
			if (TryGetPieceTable(val, 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 || instance.m_items == null)
			{
				return false;
			}
			GameObject val = instance.GetItemPrefab("Hammer");
			if ((Object)(object)val == (Object)null)
			{
				val = instance.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "Hammer");
			}
			if (!TryGetPieceTable(val, 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];
				}
			}
			for (int j = 0; j < vfxPrefabs.Count; j++)
			{
				if ((Object)(object)vfxPrefabs[j] != (Object)null)
				{
					yield return vfxPrefabs[j];
				}
			}
		}

		private void LoadPieces(string path)
		{
			LoadPrefabCollection(BuildPieceList.buildPieces, path, buildPrefabs, "piece");
		}

		private void LoadOther(string path)
		{
			LoadPrefabCollection(OtherPrefabNames, path, vfxPrefabs, "object");
		}

		private void LoadPrefabCollection(string[] prefabNames, string path, List<GameObject> destination, string assetKind)
		{
			if (prefabNames == null || destination == null || (Object)(object)assetBundle == (Object)null)
			{
				return;
			}
			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 " + assetKind + " entry ignored while loading: " + text));
					}
					continue;
				}
				GameObject val = null;
				try
				{
					val = assetBundle.LoadAsset<GameObject>(path + text + ".prefab");
				}
				catch (Exception ex)
				{
					if (Launch.Log != null)
					{
						Launch.Log.LogError((object)("Failed to load " + assetKind + " '" + text + "': " + ex));
					}
					continue;
				}
				if ((Object)(object)val == (Object)null)
				{
					list.Add(text);
					continue;
				}
				ShaderReplacement.Replace(val);
				destination.Add(val);
			}
			if (list.Count > 0 && Launch.Log != null)
			{
				int num = Math.Min(list.Count, 24);
				string text2 = string.Join(", ", list.GetRange(0, num).ToArray());
				if (list.Count > num)
				{
					text2 += ", ...";
				}
				Launch.Log.LogWarning((object)("AssetBundle is missing " + list.Count + " " + assetKind + " prefab(s): " + text2));
			}
		}

		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)
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogError((object)("Could not open embedded AssetBundle resource: " + text));
				}
				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))
				{
					int key = BalrondHashCompat.StableHash(((Object)val).name);
					if (!_sceneHashNames.ContainsKey(key))
					{
						_sceneHashNames.Add(key, ((Object)val).name);
					}
				}
			}
		}

		private void RegisterPrefabCollection(List<GameObject> prefabs, ZNetScene zNetScene, List<GameObject> registered)
		{
			if (prefabs == null)
			{
				return;
			}
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i];
				if (RegisterPrefab(val, zNetScene) && registered != null && (Object)(object)val != (Object)null)
				{
					registered.Add(val);
				}
			}
		}

		private bool RegisterPrefab(GameObject prefab, ZNetScene zNetScene)
		{
			if ((Object)(object)prefab == (Object)null || string.IsNullOrEmpty(((Object)prefab).name) || (Object)(object)zNetScene == (Object)null || zNetScene.m_prefabs == null)
			{
				return false;
			}
			GameObject val = _scenePrefabCache.Find(((Object)prefab).name, zNetScene.m_prefabs);
			if ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)val == (Object)(object)prefab)
				{
					return true;
				}
				if (Launch.Log != null)
				{
					Launch.Log.LogWarning((object)("Prefab name conflict for '" + ((Object)prefab).name + "'. Keeping the prefab already registered by the game or another mod."));
				}
				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 is already used by '" + value + "'."));
				}
				return false;
			}
			zNetScene.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;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			BuildPieceDefinition[] definitions = BuildPieceList.Definitions;
			for (int i = 0; i < definitions.Length; i++)
			{
				string prefabName = definitions[i].PrefabName;
				GameObject val = _scenePrefabCache.Find(prefabName, scenePrefabs);
				if ((Object)(object)val == (Object)null)
				{
					num3++;
					continue;
				}
				registeredBuildPrefabs.Add(val);
				GameObject val2 = null;
				for (int j = 0; j < buildPrefabs.Count; j++)
				{
					GameObject val3 = buildPrefabs[j];
					if ((Object)(object)val3 != (Object)null && string.Equals(((Object)val3).name, prefabName, StringComparison.Ordinal))
					{
						val2 = val3;
						break;
					}
				}
				if (val == val2)
				{
					num++;
				}
				else
				{
					num2++;
				}
			}
			if (Launch.Log != null)
			{
				Launch.Log.LogInfo((object)("Active Ravenwood build prefabs resolved: total=" + registeredBuildPrefabs.Count + ", owned=" + num + ", reusedExisting=" + num2 + ", missing=" + num3 + "."));
			}
		}

		private void SetBalrondWindController(ZNetScene zNetScene)
		{
			if ((Object)(object)zNetScene == (Object)null || zNetScene.m_prefabs == null)
			{
				return;
			}
			GameObject val = _scenePrefabCache.Find("weathervane_bal", zNetScene.m_prefabs);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MonoBehaviour[] components = val.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val2 in components)
			{
				if ((Object)(object)val2 != (Object)null && string.Equals(((object)val2).GetType().Name, "BalrondWindControler", StringComparison.Ordinal))
				{
					return;
				}
			}
			Windmill component = val.GetComponent<Windmill>();
			if ((Object)(object)component == (Object)null)
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogWarning((object)"Weathervane wind-controller source Windmill is missing. Existing prefab behavior was preserved.");
				}
				return;
			}
			BalrondWindControler balrondWindControler = val.AddComponent<BalrondWindControler>();
			balrondWindControler.m_propeller = component.m_propeller;
			balrondWindControler.m_bom = component.m_bom;
			balrondWindControler.m_kompas = component.m_grindstone;
			balrondWindControler.m_sfxLoops = component.m_sfxLoops;
			balrondWindControler.m_windDirection = true;
			Object.DestroyImmediate((Object)(object)component);
			if (Launch.Log != null)
			{
				Launch.Log.LogInfo((object)"weathervane_bal wind controller initialized.");
			}
		}

		private void SetupBuildPiecesList(ZNetScene zNetScene)
		{
			GameObject tool = _scenePrefabCache.Find("Hammer", zNetScene.m_prefabs);
			if (!TryGetPieceTable(tool, out var pieceTable))
			{
				if (Launch.Log != null)
				{
					Launch.Log.LogError((object)"Hammer PieceTable could not be resolved in ZNetScene.");
				}
				return;
			}
			for (int i = 0; i < HammerNames.Length; i++)
			{
				GameObject val = _scenePrefabCache.Find(HammerNames[i], zNetScene.m_prefabs);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ItemDrop component = val.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
				{
					if (Launch.Log != null)
					{
						Launch.Log.LogWarning((object)("Build tool has invalid ItemDrop data: " + HammerNames[i]));
					}
				}
				else
				{
					component.m_itemData.m_shared.m_buildPieces = pieceTable;
				}
			}
			GameObject ravenGuidePrefab = GetRavenGuidePrefab(zNetScene);
			for (int j = 0; j < registeredBuildPrefabs.Count; j++)
			{
				GameObject gameObject = registeredBuildPrefabs[j];
				SetupRavenGuide(gameObject, ravenGuidePrefab);
			}
			AddBuildPrefabsToPieceTable(pieceTable, registeredBuildPrefabs);
			RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0);
		}

		private void AddBuildPrefabsToPieceTable(PieceTable pieceTable, List<GameObject> prefabs)
		{
			if ((Object)(object)pieceTable == (Object)null || pieceTable.m_pieces == null || prefabs == null)
			{
				return;
			}
			List<GameObject> pieces = pieceTable.m_pieces;
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			for (int i = 0; i < pieces.Count; i++)
			{
				GameObject val = 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 prefab = prefabs[j];
				if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrEmpty(((Object)prefab).name) && !hashSet.Contains(((Object)prefab).name))
				{
					GameObject val2 = pieces.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == ((Object)prefab).name);
					if ((Object)(object)val2 != (Object)null)
					{
						hashSet.Add(((Object)prefab).name);
						continue;
					}
					pieces.Add(prefab);
					hashSet.Add(((Object)prefab).name);
				}
			}
		}

		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 was skipped; verify the current Valheim API.");
				}
				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));
				}
			}
		}

		private GameObject GetRavenGuidePrefab(ZNetScene zNetScene)
		{
			GameObject val = _scenePrefabCache.Find("Ravens", zNetScene.m_prefabs);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			GameObject val2 = _scenePrefabCache.Find("piece_workbench", zNetScene.m_prefabs);
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			Transform val3 = val2.transform.Find("GuidePoint");
			if ((Object)(object)val3 == (Object)null)
			{
				return null;
			}
			GuidePoint component = ((Component)val3).GetComponent<GuidePoint>();
			return ((Object)(object)component != (Object)null) ? component.m_ravenPrefab : null;
		}

		private void SetupRavenGuide(GameObject gameObject, GameObject ravenPrefab)
		{
			if ((Object)(object)gameObject == (Object)null || (Object)(object)ravenPrefab == (Object)null)
			{
				return;
			}
			Transform val = gameObject.transform.Find("GuidePoint");
			if (!((Object)(object)val == (Object)null))
			{
				GuidePoint component = ((Component)val).GetComponent<GuidePoint>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_ravenPrefab = ravenPrefab;
				}
			}
		}

		private static bool TryGetPieceTable(GameObject tool, out PieceTable pieceTable)
		{
			pieceTable = null;
			if ((Object)(object)tool == (Object)null)
			{
				return false;
			}
			ItemDrop component = tool.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				return false;
			}
			pieceTable = component.m_itemData.m_shared.m_buildPieces;
			return (Object)(object)pieceTable != (Object)null && pieceTable.m_pieces != null;
		}
	}
	internal static class PieceMetadataCompat
	{
		private const int MaxAuditNames = 24;

		internal static void Apply(Piece piece, string prefabName)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_0063: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null))
			{
				if (piece.m_resources == null)
				{
					piece.m_resources = (Requirement[])(object)new Requirement[0];
				}
				BuildPieceDefinition buildPieceDefinition = BuildPieceList.Find(prefabName);
				UsageTagFlags val = (UsageTagFlags)((buildPieceDefinition != null) ? ((int)buildPieceDefinition.BaseUsage) : 0);
				val |= InferFromName(prefabName);
				val |= InferFromComponents(((Component)piece).gameObject);
				if ((val & 0x60078) > 0)
				{
					val = (UsageTagFlags)(val | 4);
				}
				piece.m_usage |= val;
				if ((int)piece.m_usage == 0)
				{
					piece.m_usage = (UsageTagFlags)1;
				}
			}
		}

		internal 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++;
					Remember(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 (!RavenwoodBuildMenuCompat.IsKnownCategory(component.m_category))
				{
					num5++;
					flag = true;
				}
				if ((Object)(object)component.m_icon == (Object)null)
				{
					num6++;
					flag = true;
				}
				if (flag)
				{
					Remember(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 issues: " + string.Join(", ", list.ToArray())));
			}
		}

		private static UsageTagFlags InferFromComponents(GameObject prefab)
		{
			//IL_0011: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_0083: 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)
			if ((Object)(object)prefab == (Object)null)
			{
				return (UsageTagFlags)0;
			}
			UsageTagFlags val = (UsageTagFlags)0;
			if ((Object)(object)prefab.GetComponent<Container>() != (Object)null)
			{
				val = (UsageTagFlags)(val | 0x480);
			}
			if ((Object)(object)prefab.GetComponent<Fireplace>() != (Object)null)
			{
				val = (UsageTagFlags)(val | 0x100);
			}
			if ((Object)(object)prefab.GetComponent<Door>() != (Object)null)
			{
				val = (UsageTagFlags)(val | 0x40004);
			}
			if ((Object)(object)prefab.GetComponent<CraftingStation>() != (Object)null || (Object)(object)prefab.GetComponent<StationExtension>() != (Object)null)
			{
				val = (UsageTagFlags)(val | 2);
			}
			return val;
		}

		private static UsageTagFlags InferFromName(string prefabName)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: 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_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(prefabName))
			{
				return (UsageTagFlags)0;
			}
			string value = prefabName.ToLowerInvariant();
			UsageTagFlags val = (UsageTagFlags)0;
			if (HasAny(value, "floor", "platform", "ceiling", "celling", "slab"))
			{
				val = (UsageTagFlags)(val | 8);
			}
			if (HasAny(value, "wall", "window"))
			{
				val = (UsageTagFlags)(val | 0x10);
			}
			if (HasAny(value, "roof", "canopy"))
			{
				val = (UsageTagFlags)(val | 0x20);
			}
			if (HasAny(value, "stair", "ladder", "ramp", "step"))
			{
				val = (UsageTagFlags)(val | 0x20000);
			}
			if (HasAny(value, "door", "gate", "hatch"))
			{
				val = (UsageTagFlags)(val | 0x40000);
			}
			if (HasAny(value, "beam", "pole", "pillar", "column", "arch", "frame", "trim", "railing", "slope", "oriel"))
			{
				val = (UsageTagFlags)(val | 0x40);
			}
			if (HasAny(value, "stake", "spike", "fence", "palisade", "barricade", "trap", "cage", "target"))
			{
				val = (UsageTagFlags)(val | 0x8000);
			}
			if (HasAny(value, "chair", "bench", "table", "bed", "throne", "stool", "carpet", "rug"))
			{
				val = (UsageTagFlags)(val | 0x80);
			}
			if (HasAny(value, "torch", "light", "lantern", "brazier", "braizer", "candle", "fire", "hearth"))
			{
				val = (UsageTagFlags)(val | 0x100);
			}
			if (HasAny(value, "chest", "storage", "shelf", "rack", "crate"))
			{
				val = (UsageTagFlags)(val | 0x400);
			}
			if (HasAny(value, "clutter", "banner", "deco", "decor", "statue", "raven", "dragon", "vigvisir", "rune", "rostrum"))
			{
				val = (UsageTagFlags)(val | 0x200);
			}
			if (HasAny(value, "workbench", "forge", "cauldron", "craft", "smelter", "kiln", "oven", "windmill", "spinning"))
			{
				val = (UsageTagFlags)(val | 2);
			}
			if (HasAny(value, "bridge", "cart", "wagon"))
			{
				val = (UsageTagFlags)(val | 0x800);
			}
			if (HasAny(value, "stack", "pile"))
			{
				val = (UsageTagFlags)(val | 0x10000);
			}
			return val;
		}

		private static bool HasAny(string value, params string[] tokens)
		{
			for (int i = 0; i < tokens.Length; i++)
			{
				if (value.IndexOf(tokens[i], StringComparison.Ordinal) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static void Remember(List<string> names, string name)
		{
			if (names.Count < 24)
			{
				names.Add(name);
			}
		}
	}
	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 void Clear()
		{
			_source = null;
			_byName.Clear();
		}
	}
	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_categoryLabe