Decompiled source of AdvancedPortals v1.2.0

plugins/AdvancedPortals.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Common;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using SimpleJson;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AdvancedPortals")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Randy Knapp Mods")]
[assembly: AssemblyProduct("AdvancedPortals")]
[assembly: AssemblyCopyright("Copyright © Randy Knapp 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0ddde55c-5daf-4b53-b5e2-83b5c44c4682")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: IgnoresAccessChecksTo("Splatform")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
public static class PlayerExtensions
{
	public static ZDO GetZDO(this Player player)
	{
		return ((Character)player).m_nview.GetZDO();
	}
}
namespace Common
{
	public class ConfigPositionedElement : MonoBehaviour
	{
		public ConfigEntry<TextAnchor> AnchorConfig;

		public ConfigEntry<Vector2> PositionConfig;

		protected RectTransform _rt;

		protected TextAnchor _currentAnchor;

		public virtual void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			_rt = (RectTransform)((Component)this).transform;
			EnsureCorrectPosition();
		}

		public virtual void Update()
		{
			EnsureCorrectPosition();
		}

		public virtual void EnsureCorrectPosition()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected I4, but got Unknown
			//IL_0029: 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_00ab: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			if (AnchorConfig != null && PositionConfig != null && (_currentAnchor != AnchorConfig.Value || !(_rt.anchoredPosition == PositionConfig.Value)))
			{
				_currentAnchor = AnchorConfig.Value;
				TextAnchor currentAnchor = _currentAnchor;
				Vector2 val = default(Vector2);
				switch ((int)currentAnchor)
				{
				case 0:
				{
					RectTransform rt25 = _rt;
					RectTransform rt26 = _rt;
					RectTransform rt27 = _rt;
					((Vector2)(ref val))..ctor(0f, 1f);
					rt27.anchorMax = val;
					Vector2 pivot = (rt26.anchorMin = val);
					rt25.pivot = pivot;
					break;
				}
				case 1:
				{
					RectTransform rt22 = _rt;
					RectTransform rt23 = _rt;
					RectTransform rt24 = _rt;
					((Vector2)(ref val))..ctor(0.5f, 1f);
					rt24.anchorMax = val;
					Vector2 pivot = (rt23.anchorMin = val);
					rt22.pivot = pivot;
					break;
				}
				case 2:
				{
					RectTransform rt19 = _rt;
					RectTransform rt20 = _rt;
					RectTransform rt21 = _rt;
					((Vector2)(ref val))..ctor(1f, 1f);
					rt21.anchorMax = val;
					Vector2 pivot = (rt20.anchorMin = val);
					rt19.pivot = pivot;
					break;
				}
				case 3:
				{
					RectTransform rt16 = _rt;
					RectTransform rt17 = _rt;
					RectTransform rt18 = _rt;
					((Vector2)(ref val))..ctor(0f, 0.5f);
					rt18.anchorMax = val;
					Vector2 pivot = (rt17.anchorMin = val);
					rt16.pivot = pivot;
					break;
				}
				case 4:
				{
					RectTransform rt13 = _rt;
					RectTransform rt14 = _rt;
					RectTransform rt15 = _rt;
					((Vector2)(ref val))..ctor(0.5f, 0.5f);
					rt15.anchorMax = val;
					Vector2 pivot = (rt14.anchorMin = val);
					rt13.pivot = pivot;
					break;
				}
				case 5:
				{
					RectTransform rt10 = _rt;
					RectTransform rt11 = _rt;
					RectTransform rt12 = _rt;
					((Vector2)(ref val))..ctor(1f, 0.5f);
					rt12.anchorMax = val;
					Vector2 pivot = (rt11.anchorMin = val);
					rt10.pivot = pivot;
					break;
				}
				case 6:
				{
					RectTransform rt7 = _rt;
					RectTransform rt8 = _rt;
					RectTransform rt9 = _rt;
					((Vector2)(ref val))..ctor(0f, 0f);
					rt9.anchorMax = val;
					Vector2 pivot = (rt8.anchorMin = val);
					rt7.pivot = pivot;
					break;
				}
				case 7:
				{
					RectTransform rt4 = _rt;
					RectTransform rt5 = _rt;
					RectTransform rt6 = _rt;
					((Vector2)(ref val))..ctor(0.5f, 0f);
					rt6.anchorMax = val;
					Vector2 pivot = (rt5.anchorMin = val);
					rt4.pivot = pivot;
					break;
				}
				case 8:
				{
					RectTransform rt = _rt;
					RectTransform rt2 = _rt;
					RectTransform rt3 = _rt;
					((Vector2)(ref val))..ctor(1f, 0f);
					rt3.anchorMax = val;
					Vector2 pivot = (rt2.anchorMin = val);
					rt.pivot = pivot;
					break;
				}
				}
				_rt.anchoredPosition = PositionConfig.Value;
			}
		}
	}
	[Serializable]
	public class RecipeRequirementConfig
	{
		public string item = "";

		public int amount = 1;
	}
	[Serializable]
	public class RecipeConfig
	{
		public string name = "";

		public string item = "";

		public int amount = 1;

		public string craftingStation = "";

		public int minStationLevel = 1;

		public bool enabled = true;

		public string repairStation = "";

		public List<RecipeRequirementConfig> resources = new List<RecipeRequirementConfig>();
	}
	[Serializable]
	public class RecipesConfig
	{
		public List<RecipeConfig> recipes = new List<RecipeConfig>();
	}
	public static class GameObjectExtensions
	{
		public static RectTransform RectTransform(this GameObject go)
		{
			Transform transform = go.transform;
			return (RectTransform)(object)((transform is RectTransform) ? transform : null);
		}

		public static T RequireComponent<T>(this GameObject go) where T : Component
		{
			T component = go.GetComponent<T>();
			if (!((Object)(object)component == (Object)null))
			{
				return component;
			}
			return go.AddComponent<T>();
		}
	}
	public class GotDestroyed : MonoBehaviour
	{
		public void OnDisable()
		{
			Debug.LogError((object)("I got destroyed! (" + ((Object)((Component)this).gameObject).name + ")"));
			Debug.Log((object)Environment.StackTrace);
		}
	}
	public static class AssetBundleLoader
	{
		private static readonly List<Stream> _liveStreams = new List<Stream>();

		public static AssetBundle LoadFromResources(string filename, Assembly assembly)
		{
			if (assembly == null)
			{
				throw new ArgumentNullException("assembly");
			}
			string text = assembly.GetName().Name + "." + filename;
			try
			{
				Stream manifestResourceStream = assembly.GetManifestResourceStream(text);
				if (manifestResourceStream == null)
				{
					ModLogger.LogError("Embedded asset bundle '" + text + "' not found in " + assembly.GetName().Name + ".");
					return null;
				}
				AssetBundle val = AssetBundle.LoadFromStream(manifestResourceStream);
				if ((Object)(object)val == (Object)null)
				{
					manifestResourceStream.Dispose();
					ModLogger.LogError("Embedded asset bundle '" + text + "' failed to load.");
					return null;
				}
				_liveStreams.Add(manifestResourceStream);
				return val;
			}
			catch (Exception ex)
			{
				ModLogger.LogError("Failed to load embedded asset bundle '" + text + "': " + ex.Message);
				return null;
			}
		}

		public static AssetBundle LoadIntoContext(string filename, Assembly assembly)
		{
			AssetBundle val = LoadFromResources(filename, assembly);
			if ((Object)(object)val != (Object)null)
			{
				ModContext.AssetBundle = val;
			}
			return val;
		}
	}
	public static class ConfigBinder
	{
		private static ConfigFile Cfg => ModContext.Cfg;

		public static ConfigEntry<bool> BindServerConfig(string category, string key, bool value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return Cfg.Bind<bool>(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<int> BindServerConfig(string category, string key, int value, string description, bool advanced = false, int valMin = 0, int valMax = 150)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return Cfg.Bind<int>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<float> BindServerConfig(string category, string key, float value, string description, bool advanced = false, float valMin = 0f, float valMax = 150f)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return Cfg.Bind<float>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<string> BindServerConfig(string category, string key, string value, string description, AcceptableValueList<string> acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return Cfg.Bind<string>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<T> BindServerConfig<T>(string category, string key, T value, string description, AcceptableValueBase acceptableValues, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return Cfg.Bind<T>(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<T> BindClientConfig<T>(string category, string key, T value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return Cfg.Bind<T>(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = false,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<T> BindServerConfigInOrder<T>(string category, string key, T value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false)
		{
			//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_0026: Expected O, but got Unknown
			return ConfigFileExtensions.BindConfigInOrder<T>(Cfg, category, key, value, description, true, true, true, acceptableValues, (Action<ConfigEntryBase>)null, new ConfigurationManagerAttributes
			{
				IsAdvanced = advanced
			});
		}

		public static ConfigEntry<T> BindClientConfigInOrder<T>(string category, string key, T value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false)
		{
			//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_0026: Expected O, but got Unknown
			return ConfigFileExtensions.BindConfigInOrder<T>(Cfg, category, key, value, description, false, true, true, acceptableValues, (Action<ConfigEntryBase>)null, new ConfigurationManagerAttributes
			{
				IsAdvanced = advanced
			});
		}
	}
	public static class ConfigChangeDebouncer
	{
		private static readonly Dictionary<object, Action> pendingActions = new Dictionary<object, Action>();

		private static readonly Dictionary<object, float> fireAt = new Dictionary<object, float>();

		private static readonly HashSet<object> running = new HashSet<object>();

		public static void Schedule(object key, Action action)
		{
			float num = ((ModContext.ConfigApplyDelay != null) ? ModContext.ConfigApplyDelay.Value : 0f);
			if (num <= 0f)
			{
				action();
				return;
			}
			ThreadingHelper instance = ThreadingHelper.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				pendingActions[key] = action;
				fireAt[key] = Time.realtimeSinceStartup + num;
				if (!running.Contains(key))
				{
					running.Add(key);
					((MonoBehaviour)instance).StartCoroutine(Run(key));
				}
			}
		}

		private static IEnumerator Run(object key)
		{
			float value;
			while (fireAt.TryGetValue(key, out value) && Time.realtimeSinceStartup < value)
			{
				yield return null;
			}
			pendingActions.TryGetValue(key, out var value2);
			pendingActions.Remove(key);
			fireAt.Remove(key);
			running.Remove(key);
			value2?.Invoke();
		}
	}
	internal static class ConfigDrawHelpers
	{
		private static readonly Dictionary<object, string> TextBuffer = new Dictionary<object, string>();

		private static readonly Dictionary<object, float> SliderPending = new Dictionary<object, float>();

		private static GUIStyle _headerButton;

		private static GUIStyle _groupLabel;

		private static GUIStyle _dim;

		internal static GUIStyle HeaderButton => _headerButton;

		internal static GUIStyle Dim => _dim;

		internal static void EnsureStyles()
		{
			//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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0068: Expected O, but got Unknown
			if (_headerButton == null)
			{
				_headerButton = new GUIStyle(GUI.skin.button)
				{
					alignment = (TextAnchor)3,
					fontStyle = (FontStyle)1
				};
				_groupLabel = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1
				};
				_dim = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)2,
					fontSize = 11
				};
			}
		}

		internal static ConfigurationManagerAttributes GetAttributes(ConfigEntryBase entry)
		{
			if (entry == null)
			{
				return null;
			}
			ConfigDescription description = entry.Description;
			if (description == null)
			{
				return null;
			}
			return description.Tags?.OfType<ConfigurationManagerAttributes>().FirstOrDefault();
		}

		internal static void Hide(ConfigEntryBase entry)
		{
			ConfigurationManagerAttributes attributes = GetAttributes(entry);
			if (attributes != null)
			{
				attributes.Browsable = false;
			}
		}

		internal static void GroupHeader(string text)
		{
			GUILayout.Space(4f);
			GUILayout.Label(text, _groupLabel, Array.Empty<GUILayoutOption>());
		}

		private static bool EnterPressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			if ((int)Event.current.type == 4)
			{
				if ((int)Event.current.keyCode != 13)
				{
					return (int)Event.current.keyCode == 271;
				}
				return true;
			}
			return false;
		}

		internal static void DrawBool(string label, ConfigEntry<bool> cfg)
		{
			bool flag = GUILayout.Toggle(cfg.Value, " " + label, Array.Empty<GUILayoutOption>());
			if (flag != cfg.Value)
			{
				cfg.Value = flag;
			}
		}

		internal static void DrawString(string label, ConfigEntry<string> cfg)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			string text = "str_" + ((object)cfg).GetHashCode();
			GUI.SetNextControlName(text);
			bool flag = GUI.GetNameOfFocusedControl() == text;
			string value;
			string text2 = GUILayout.TextField((flag && TextBuffer.TryGetValue(cfg, out value)) ? value : cfg.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			string value2;
			if (flag)
			{
				TextBuffer[cfg] = text2;
				if (EnterPressed() && cfg.Value != text2)
				{
					cfg.Value = text2;
				}
			}
			else if (TextBuffer.TryGetValue(cfg, out value2))
			{
				if (cfg.Value != value2)
				{
					cfg.Value = value2;
				}
				TextBuffer.Remove(cfg);
			}
			GUILayout.EndHorizontal();
		}

		internal static void DrawChoice(string label, ConfigEntry<string> cfg)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			if (((ConfigEntryBase)cfg).Description.AcceptableValues is AcceptableValueList<string> val && val.AcceptableValues.Length != 0)
			{
				string[] acceptableValues = val.AcceptableValues;
				int num = Array.IndexOf(acceptableValues, cfg.Value);
				if (num < 0)
				{
					num = 0;
				}
				if (GUILayout.Button("◄", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }))
				{
					cfg.Value = acceptableValues[(num - 1 + acceptableValues.Length) % acceptableValues.Length];
				}
				GUILayout.Label(cfg.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) });
				if (GUILayout.Button("►", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }))
				{
					cfg.Value = acceptableValues[(num + 1) % acceptableValues.Length];
				}
			}
			else
			{
				GUILayout.Label(cfg.Value, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndHorizontal();
		}

		internal static void DrawFloat(string label, ConfigEntry<float> cfg)
		{
			float num = 0f;
			float num2 = Mathf.Max(100f, cfg.Value);
			if (((ConfigEntryBase)cfg).Description.AcceptableValues is AcceptableValueRange<float> val)
			{
				num = val.MinValue;
				num2 = val.MaxValue;
			}
			float num3 = DrawSliderRow(label, cfg, cfg.Value, num, num2, isInt: false);
			if (num3 != cfg.Value)
			{
				cfg.Value = Mathf.Clamp(num3, num, num2);
			}
		}

		internal static void DrawInt(string label, ConfigEntry<int> cfg)
		{
			float num = 0f;
			float num2 = Mathf.Max(100f, (float)cfg.Value);
			if (((ConfigEntryBase)cfg).Description.AcceptableValues is AcceptableValueRange<int> val)
			{
				num = val.MinValue;
				num2 = val.MaxValue;
			}
			int num3 = Mathf.Clamp(Mathf.RoundToInt(DrawSliderRow(label, cfg, cfg.Value, num, num2, isInt: true)), (int)num, (int)num2);
			if (num3 != cfg.Value)
			{
				cfg.Value = num3;
			}
		}

		private static float DrawSliderRow(string label, object key, float current, float min, float max, bool isInt)
		{
			float num = current;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			float value;
			float num2 = (SliderPending.TryGetValue(key, out value) ? value : current);
			float num3 = GUILayout.HorizontalSlider(num2, min, max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			if (Mathf.Abs(num3 - num2) > Mathf.Epsilon)
			{
				SliderPending[key] = num3;
			}
			if (SliderPending.TryGetValue(key, out var value2) && !Input.GetMouseButton(0))
			{
				SliderPending.Remove(key);
				num = value2;
			}
			float value3;
			float num4 = (SliderPending.TryGetValue(key, out value3) ? value3 : num);
			string text = "num_" + key.GetHashCode();
			GUI.SetNextControlName(text);
			bool flag = GUI.GetNameOfFocusedControl() == text;
			string text2 = (isInt ? Mathf.RoundToInt(num4).ToString() : num4.ToString("0.###"));
			string value4;
			string text3 = GUILayout.TextField((flag && TextBuffer.TryGetValue(key, out value4)) ? value4 : text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			string value5;
			if (flag)
			{
				TextBuffer[key] = text3;
				if (EnterPressed() && float.TryParse(text3, out var result))
				{
					num = result;
				}
			}
			else if (TextBuffer.TryGetValue(key, out value5))
			{
				if (float.TryParse(value5, out var result2))
				{
					num = result2;
				}
				TextBuffer.Remove(key);
			}
			GUILayout.Label("[" + (isInt ? min.ToString() : min.ToString("0.#")) + " - " + (isInt ? max.ToString() : max.ToString("0.#")) + "]", _dim, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			GUILayout.EndHorizontal();
			return num;
		}
	}
	internal static class ItemConfigDrawer
	{
		private static readonly Dictionary<string, bool> Expanded = new Dictionary<string, bool>();

		private static readonly Dictionary<object, List<string[]>> RecipeRows = new Dictionary<object, List<string[]>>();

		private static int _order = 0;

		private static readonly KeyValuePair<string, ItemStat[]>[] StatGroups = new KeyValuePair<string, ItemStat[]>[5]
		{
			new KeyValuePair<string, ItemStat[]>("Damage", new ItemStat[20]
			{
				ItemStat.slash,
				ItemStat.slash_per_level,
				ItemStat.blunt,
				ItemStat.blunt_per_level,
				ItemStat.pierce,
				ItemStat.pierce_per_level,
				ItemStat.fire,
				ItemStat.fire_per_level,
				ItemStat.lightning,
				ItemStat.lightning_per_level,
				ItemStat.frost,
				ItemStat.frost_per_level,
				ItemStat.poison,
				ItemStat.poison_per_level,
				ItemStat.spirit,
				ItemStat.spirit_per_level,
				ItemStat.pickaxe,
				ItemStat.pickaxe_per_level,
				ItemStat.chop,
				ItemStat.chop_per_level
			}),
			new KeyValuePair<string, ItemStat[]>("Combat", new ItemStat[20]
			{
				ItemStat.attack_force,
				ItemStat.primary_attack_force_multiply,
				ItemStat.secondary_attack_force_multiply,
				ItemStat.primary_attack_stamina,
				ItemStat.primary_attack_eitr,
				ItemStat.primary_attack_flat_health_cost,
				ItemStat.primary_attack_percent_health_cost,
				ItemStat.primary_attack_health_returned,
				ItemStat.primary_attack_damage_bonus_per_missing_hp,
				ItemStat.primary_attack_projectile_count,
				ItemStat.secondary_attack_stamina,
				ItemStat.secondary_attack_eitr,
				ItemStat.secondary_attack_flat_health_cost,
				ItemStat.secondary_attack_percent_health_cost,
				ItemStat.projectile_velocity,
				ItemStat.projectile_accuracy_max,
				ItemStat.bow_draw_speed,
				ItemStat.crossbow_reload_speed,
				ItemStat.crossbow_reload_stamina_drain,
				ItemStat.draw_stamina_drain
			}),
			new KeyValuePair<string, ItemStat[]>("Defense", new ItemStat[5]
			{
				ItemStat.block_armor,
				ItemStat.block_armor_per_level,
				ItemStat.parry,
				ItemStat.block_force,
				ItemStat.block_force_per_level
			}),
			new KeyValuePair<string, ItemStat[]>("Item", new ItemStat[6]
			{
				ItemStat.durability,
				ItemStat.durability_per_level,
				ItemStat.max_item_level,
				ItemStat.tool_level,
				ItemStat.movement_speed,
				ItemStat.amount
			}),
			new KeyValuePair<string, ItemStat[]>("Food", new ItemStat[5]
			{
				ItemStat.food_health,
				ItemStat.food_stamina,
				ItemStat.food_eitr,
				ItemStat.food_regen,
				ItemStat.food_duration
			})
		};

		internal static void Attach(ItemDefinition itemdef)
		{
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)itemdef.StationLVLCfg);
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)itemdef.CraftAmountCfg);
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)itemdef.CraftedAtCfg);
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)itemdef.Recipe.RecipeConfig);
			if (itemdef.ModifableStats != null)
			{
				foreach (ItemStatConfig value in itemdef.ModifableStats.Values)
				{
					if (value.Cfg != null)
					{
						ConfigDrawHelpers.Hide((ConfigEntryBase)(object)value.Cfg);
					}
					if (value.CfgInt != null)
					{
						ConfigDrawHelpers.Hide((ConfigEntryBase)(object)value.CfgInt);
					}
				}
			}
			if (itemdef.DamageMods != null)
			{
				foreach (HitCustomDamageMod value2 in itemdef.DamageMods.Values)
				{
					if (value2.DmgModCfg != null)
					{
						ConfigDrawHelpers.Hide((ConfigEntryBase)(object)value2.DmgModCfg);
					}
				}
			}
			ConfigurationManagerAttributes attributes = ConfigDrawHelpers.GetAttributes((ConfigEntryBase)(object)itemdef.CraftableCfg);
			if (attributes != null)
			{
				attributes.CustomDrawer = delegate
				{
					Draw(itemdef);
				};
				attributes.HideSettingName = true;
				attributes.HideDefaultButton = true;
				attributes.Category = itemdef.Category.ToString();
				attributes.Order = _order--;
			}
		}

		private static void Draw(ItemDefinition itemdef)
		{
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			ConfigDrawHelpers.EnsureStyles();
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			bool value;
			bool flag = Expanded.TryGetValue(itemdef.DisplayName, out value) && value;
			if (GUILayout.Button((flag ? "▾ " : "▸ ") + itemdef.Name, ConfigDrawHelpers.HeaderButton, Array.Empty<GUILayoutOption>()))
			{
				flag = !flag;
				Expanded[itemdef.DisplayName] = flag;
			}
			if (flag)
			{
				int num;
				if (SynchronizationManager.Instance != null)
				{
					num = (SynchronizationManager.Instance.PlayerIsAdmin ? 1 : 0);
					if (num == 0)
					{
						GUILayout.Label("Server-controlled – admin only.", ConfigDrawHelpers.Dim, Array.Empty<GUILayoutOption>());
					}
				}
				else
				{
					num = 1;
				}
				bool enabled = GUI.enabled;
				GUI.enabled = (byte)num != 0;
				ConfigDrawHelpers.GroupHeader("Crafting");
				ConfigDrawHelpers.DrawBool("Craftable", itemdef.CraftableCfg);
				ConfigDrawHelpers.DrawString("Crafted at", itemdef.CraftedAtCfg);
				ConfigDrawHelpers.DrawInt("Station level", itemdef.StationLVLCfg);
				ConfigDrawHelpers.DrawInt("Craft amount", itemdef.CraftAmountCfg);
				DrawRecipeEditor(itemdef);
				HashSet<ItemStat> drawn = new HashSet<ItemStat>();
				KeyValuePair<string, ItemStat[]>[] statGroups = StatGroups;
				for (int i = 0; i < statGroups.Length; i++)
				{
					KeyValuePair<string, ItemStat[]> keyValuePair = statGroups[i];
					List<ItemStat> list = keyValuePair.Value.Where((ItemStat s) => IsConfigurable(itemdef, s)).ToList();
					bool flag2 = keyValuePair.Key == "Damage" && itemdef.DamageMods != null && itemdef.DamageMods.Count > 0;
					if (list.Count == 0 && !flag2)
					{
						continue;
					}
					ConfigDrawHelpers.GroupHeader(keyValuePair.Key);
					foreach (ItemStat item in list)
					{
						DrawStat(itemdef, item);
						drawn.Add(item);
					}
					if (!flag2)
					{
						continue;
					}
					foreach (KeyValuePair<DamageType, HitCustomDamageMod> damageMod in itemdef.DamageMods)
					{
						if (damageMod.Value.Configurable && damageMod.Value.DmgModCfg != null)
						{
							ConfigDrawHelpers.DrawChoice(((object)damageMod.Key/*cast due to .constrained prefix*/).ToString() + " resistance", damageMod.Value.DmgModCfg);
						}
					}
				}
				if (itemdef.ModifableStats != null)
				{
					List<ItemStat> list2 = itemdef.ModifableStats.Keys.Where((ItemStat s) => !drawn.Contains(s) && IsConfigurable(itemdef, s)).ToList();
					if (list2.Count > 0)
					{
						ConfigDrawHelpers.GroupHeader("Other");
						foreach (ItemStat item2 in list2)
						{
							DrawStat(itemdef, item2);
						}
					}
				}
				GUI.enabled = enabled;
			}
			GUILayout.EndVertical();
		}

		private static bool IsConfigurable(ItemDefinition itemdef, ItemStat s)
		{
			if (itemdef.ModifableStats != null && itemdef.ModifableStats.TryGetValue(s, out var value))
			{
				return value.Configurable;
			}
			return false;
		}

		private static void DrawStat(ItemDefinition itemdef, ItemStat s)
		{
			ItemStatConfig itemStatConfig = itemdef.ModifableStats[s];
			string label = s.ToString().Replace('_', ' ');
			if (itemStatConfig.IsInt)
			{
				ConfigDrawHelpers.DrawInt(label, itemStatConfig.CfgInt);
			}
			else
			{
				ConfigDrawHelpers.DrawFloat(label, itemStatConfig.Cfg);
			}
		}

		private static void DrawRecipeEditor(ItemDefinition itemdef)
		{
			ConfigEntry<string> recipeConfig = itemdef.Recipe.RecipeConfig;
			ConfigDrawHelpers.GroupHeader("Recipe");
			if (!RecipeRows.TryGetValue(recipeConfig, out var value))
			{
				value = ParseCsv(recipeConfig.Value, 3);
				RecipeRows[recipeConfig] = value;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Resource (prefab)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			GUILayout.Label("Amount", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			GUILayout.Label("Per level", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			GUILayout.EndHorizontal();
			for (int i = 0; i < value.Count; i++)
			{
				string[] array = value[i];
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				array[0] = GUILayout.TextField(array[0] ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
				array[1] = DigitsOnly(GUILayout.TextField(array[1] ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }));
				array[2] = DigitsOnly(GUILayout.TextField(array[2] ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }));
				bool num = GUILayout.Button("✕", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) });
				GUILayout.EndHorizontal();
				if (num)
				{
					value.RemoveAt(i);
					i--;
				}
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Add resource", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
			{
				value.Add(new string[3] { "", "1", "0" });
			}
			if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				recipeConfig.Value = SerializeCsv(value);
			}
			if (GUILayout.Button("Reload", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				RecipeRows[recipeConfig] = ParseCsv(recipeConfig.Value, 3);
			}
			GUILayout.EndHorizontal();
			GUILayout.Label("Applied: " + recipeConfig.Value, ConfigDrawHelpers.Dim, Array.Empty<GUILayoutOption>());
		}

		internal static List<string[]> ParseCsv(string csv, int cols)
		{
			List<string[]> list = new List<string[]>();
			string[] array = (csv ?? "").Split(new char[1] { '|' });
			foreach (string text in array)
			{
				if (!string.IsNullOrEmpty(text) && text.Trim().Length != 0)
				{
					string[] array2 = text.Split(new char[1] { ',' });
					string[] array3 = new string[cols];
					for (int j = 0; j < cols; j++)
					{
						array3[j] = ((j < array2.Length) ? array2[j] : "");
					}
					list.Add(array3);
				}
			}
			return list;
		}

		internal static string SerializeCsv(List<string[]> rows)
		{
			return string.Join("|", (from r in rows
				where !string.IsNullOrEmpty(r[0]) && r[0].Trim().Length > 0
				select string.Join(",", r)).ToArray());
		}

		internal static string DigitsOnly(string s)
		{
			return new string((s ?? "").Where((char ch) => char.IsDigit(ch) || ch == '-').ToArray());
		}
	}
	internal static class PieceConfigDrawer
	{
		private static readonly Dictionary<string, bool> Expanded = new Dictionary<string, bool>();

		private static readonly Dictionary<object, List<string[]>> CostRows = new Dictionary<object, List<string[]>>();

		private static int _order = 0;

		internal static void Attach(PieceLoader.BuildPiece jp)
		{
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)jp.Cfgs.RequiresWorkbench);
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)jp.Cfgs.Workbench);
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)jp.Cfgs.PieceCategory);
			ConfigDrawHelpers.Hide((ConfigEntryBase)(object)jp.Cfgs.PieceCost);
			ConfigurationManagerAttributes attributes = ConfigDrawHelpers.GetAttributes((ConfigEntryBase)(object)jp.Cfgs.Enabled);
			if (attributes != null)
			{
				attributes.CustomDrawer = delegate
				{
					Draw(jp);
				};
				attributes.HideSettingName = true;
				attributes.HideDefaultButton = true;
				attributes.Category = "Building Pieces";
				attributes.Order = _order--;
			}
		}

		private static void Draw(PieceLoader.BuildPiece jp)
		{
			ConfigDrawHelpers.EnsureStyles();
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			bool value;
			bool flag = Expanded.TryGetValue(jp.Name, out value) && value;
			if (GUILayout.Button((flag ? "▾ " : "▸ ") + jp.Name, ConfigDrawHelpers.HeaderButton, Array.Empty<GUILayoutOption>()))
			{
				flag = !flag;
				Expanded[jp.Name] = flag;
			}
			if (flag)
			{
				int num;
				if (SynchronizationManager.Instance != null)
				{
					num = (SynchronizationManager.Instance.PlayerIsAdmin ? 1 : 0);
					if (num == 0)
					{
						GUILayout.Label("Server-controlled – admin only.", ConfigDrawHelpers.Dim, Array.Empty<GUILayoutOption>());
					}
				}
				else
				{
					num = 1;
				}
				bool enabled = GUI.enabled;
				GUI.enabled = (byte)num != 0;
				ConfigDrawHelpers.GroupHeader("Settings");
				ConfigDrawHelpers.DrawBool("Enabled", jp.Cfgs.Enabled);
				ConfigDrawHelpers.DrawBool("Requires workbench", jp.Cfgs.RequiresWorkbench);
				ConfigDrawHelpers.DrawString("Workbench", jp.Cfgs.Workbench);
				ConfigDrawHelpers.DrawChoice("Piece category", jp.Cfgs.PieceCategory);
				DrawCostEditor(jp);
				GUI.enabled = enabled;
			}
			GUILayout.EndVertical();
		}

		private static void DrawCostEditor(PieceLoader.BuildPiece jp)
		{
			ConfigEntry<string> pieceCost = jp.Cfgs.PieceCost;
			ConfigDrawHelpers.GroupHeader("Building Cost");
			if (!CostRows.TryGetValue(pieceCost, out var value))
			{
				value = ItemConfigDrawer.ParseCsv(pieceCost.Value, 3);
				CostRows[pieceCost] = value;
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Resource (prefab)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
			GUILayout.Label("Amount", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			GUILayout.Label("Refund", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			GUILayout.EndHorizontal();
			for (int i = 0; i < value.Count; i++)
			{
				string[] array = value[i];
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				array[0] = GUILayout.TextField(array[0] ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) });
				array[1] = ItemConfigDrawer.DigitsOnly(GUILayout.TextField(array[1] ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }));
				bool num = (array[2] ?? "").Trim().ToLower() != "false";
				bool flag = GUILayout.Toggle(num, num ? " refundable" : " no refund", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
				array[2] = (flag ? "true" : "false");
				bool num2 = GUILayout.Button("✕", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) });
				GUILayout.EndHorizontal();
				if (num2)
				{
					value.RemoveAt(i);
					i--;
				}
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Add resource", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
			{
				value.Add(new string[3] { "", "1", "true" });
			}
			if (GUILayout.Button("Apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				pieceCost.Value = ItemConfigDrawer.SerializeCsv(value);
			}
			if (GUILayout.Button("Reload", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
			{
				CostRows[pieceCost] = ItemConfigDrawer.ParseCsv(pieceCost.Value, 3);
			}
			GUILayout.EndHorizontal();
			GUILayout.Label("Applied: " + pieceCost.Value, ConfigDrawHelpers.Dim, Array.Empty<GUILayoutOption>());
		}
	}
	public class ItemBatchLoader
	{
		internal static List<ItemDefinition> resourceDefinitions = new List<ItemDefinition>();

		internal static AssetBundle Assets;

		internal static Dictionary<string, string> AddedItems = new Dictionary<string, string>();

		internal static List<string> ArcheryAmmoToAdd = new List<string>();

		public static string PrefabPathFormat = "Assets/Custom/Weapons/{0}/{1}.prefab";

		public static string IconPathFormat = "Assets/Custom/Icons/{0}.png";

		public static bool FixReferences = true;

		private static readonly List<KeyValuePair<string, Action<ItemData>>> pendingWorldUpdates = new List<KeyValuePair<string, Action<ItemData>>>();

		private static bool worldUpdateScheduled = false;

		internal static readonly AcceptableValueList<string> allowedModifiers = new AcceptableValueList<string>(new string[6]
		{
			((object)(DamageModifier)0/*cast due to .constrained prefix*/).ToString(),
			((object)(DamageModifier)6/*cast due to .constrained prefix*/).ToString(),
			((object)(DamageModifier)2/*cast due to .constrained prefix*/).ToString(),
			((object)(DamageModifier)1/*cast due to .constrained prefix*/).ToString(),
			((object)(DamageModifier)5/*cast due to .constrained prefix*/).ToString(),
			((object)(DamageModifier)3/*cast due to .constrained prefix*/).ToString()
		});

		public bool AddDefinition(ItemDefinition itemdef)
		{
			resourceDefinitions.Add(itemdef);
			return true;
		}

		public bool BatchSetup(AssetBundle assetBundle = null, bool reverse_order = true)
		{
			Assets = assetBundle ?? ModContext.AssetBundle;
			if ((Object)(object)Assets == (Object)null)
			{
				ModLogger.LogError("No asset bundle available; items will not be registered.");
				return false;
			}
			if (reverse_order)
			{
				resourceDefinitions.Reverse();
			}
			ModContext.SaveOnSet(enabled: false);
			WireConfigDefs();
			if (!Utils.IsServer())
			{
				BatchAddItems();
				SetupOnChange();
				ItemManager.OnItemsRegistered += AddAmmoItemsToArcheryTarget;
				ItemManager.OnItemsRegistered += ReapplyAllRecipeConfig;
				SynchronizationManager.OnConfigurationSynchronized += OnModConfigsChanged;
			}
			ModContext.SaveOnSet(enabled: true);
			return true;
		}

		private static bool WireConfigDefs()
		{
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemDefinition resourceDefinition in resourceDefinitions)
			{
				if (resourceDefinition.Recipe == null)
				{
					resourceDefinition.Recipe = new RecipeDefinition();
				}
				if (resourceDefinition.Recipe.RecipeItems == null)
				{
					ModLogger.LogError("Item definition '" + resourceDefinition.Name + "' has no recipe items; it will be registered without a crafting recipe.");
					resourceDefinition.Recipe.RecipeItems = new List<RecipeIngredient>();
				}
				resourceDefinition.DisplayName = string.Join("", resourceDefinition.Name.Split((string[]?)null, StringSplitOptions.RemoveEmptyEntries));
				AddedItems.Add(resourceDefinition.DisplayName, resourceDefinition.Prefab);
				string category = $"{resourceDefinition.Category} - {resourceDefinition.Name}";
				resourceDefinition.CraftableCfg = ConfigBinder.BindServerConfig(category, resourceDefinition.DisplayName + "-craftable", resourceDefinition.Craftable, "Enable/Disable the crafting recipe for " + resourceDefinition.Name + ".");
				resourceDefinition.StationLVLCfg = ConfigBinder.BindServerConfig(category, resourceDefinition.DisplayName + "-stationRequiredLevel", resourceDefinition.ReqStationlevel, "Sets the required minimum crafting station level to craft " + resourceDefinition.Name, advanced: true, 1, 10);
				resourceDefinition.CraftAmountCfg = ConfigBinder.BindServerConfig(category, resourceDefinition.DisplayName + "-craftAmount", resourceDefinition.CraftAmount, "Sets the amount of " + resourceDefinition.Name + " crafted per recipe.", advanced: true, 1, 50);
				resourceDefinition.CraftedAtCfg = ConfigBinder.BindServerConfig(category, resourceDefinition.DisplayName + "-craftedAt", resourceDefinition.CraftedAt, "Sets the crafting station for " + resourceDefinition.Name + ".");
				foreach (KeyValuePair<ItemStat, ItemStatConfig> modifableStat in resourceDefinition.ModifableStats)
				{
					if (modifableStat.Value.Configurable)
					{
						if (modifableStat.Value.IsInt)
						{
							modifableStat.Value.CfgInt = ConfigBinder.BindServerConfig(category, $"{resourceDefinition.DisplayName}-{modifableStat.Key}", (int)modifableStat.Value.Default_value, $"Value for {modifableStat.Key} on {resourceDefinition.Name}", advanced: true, (int)modifableStat.Value.Min, (int)modifableStat.Value.Max);
						}
						else
						{
							modifableStat.Value.Cfg = ConfigBinder.BindServerConfig(category, $"{resourceDefinition.DisplayName}-{modifableStat.Key}", modifableStat.Value.Default_value, $"Value for {modifableStat.Key} on {resourceDefinition.Name}", advanced: true, modifableStat.Value.Min, modifableStat.Value.Max);
						}
					}
				}
				if (resourceDefinition.DamageMods != null)
				{
					foreach (KeyValuePair<DamageType, HitCustomDamageMod> damageMod in resourceDefinition.DamageMods)
					{
						damageMod.Value.DmgModCfg = ConfigBinder.BindServerConfig(category, $"{resourceDefinition.DisplayName}-{damageMod.Key}-DamageModifier", ((object)damageMod.Value.DamageModifier/*cast due to .constrained prefix*/).ToString(), $"Damage modifier for {damageMod.Key} on {resourceDefinition.Name}", allowedModifiers, advanced: true);
					}
				}
				resourceDefinition.Recipe.RecipeConfig = ConfigBinder.BindServerConfig(category, resourceDefinition.DisplayName + "-recipe", BuildStringRecipeFromItemDef(resourceDefinition), "Recipe for " + resourceDefinition.Name + ". Should be in the format of Prefab,Amount,AmountPerLevel|Prefab,Amount,AmountPerLevel eg: Wood,12,2|Stone,2,0");
				if (!ValidateRecipeConfig(resourceDefinition))
				{
					BuildRecipeReqsFromDefault(resourceDefinition);
				}
				ItemConfigDrawer.Attach(resourceDefinition);
			}
			return true;
		}

		private bool SetupOnChange()
		{
			foreach (ItemDefinition resourceDefinition in resourceDefinitions)
			{
				ItemDefinition itemdef = resourceDefinition;
				itemdef.CraftableCfg.SettingChanged += delegate
				{
					ConfigChangeDebouncer.Schedule(itemdef.CraftableCfg, delegate
					{
						EnableDisableItemInDB(itemdef, itemdef.CraftableCfg.Value);
					});
				};
				itemdef.StationLVLCfg.SettingChanged += delegate
				{
					ConfigChangeDebouncer.Schedule(itemdef.StationLVLCfg, delegate
					{
						ModifyItemRecipeLevel(itemdef, itemdef.StationLVLCfg.Value);
					});
				};
				itemdef.CraftedAtCfg.SettingChanged += delegate
				{
					ConfigChangeDebouncer.Schedule(itemdef.CraftedAtCfg, delegate
					{
						ModifyItemRecipeCraftedAt(itemdef);
					});
				};
				itemdef.CraftAmountCfg.SettingChanged += delegate
				{
					ConfigChangeDebouncer.Schedule(itemdef.CraftAmountCfg, delegate
					{
						ModifyItemRecipeCraftAmount(itemdef, itemdef.CraftAmountCfg.Value);
					});
				};
				foreach (KeyValuePair<ItemStat, ItemStatConfig> modifableStat in itemdef.ModifableStats)
				{
					KeyValuePair<ItemStat, ItemStatConfig> stat = modifableStat;
					object statKey;
					if (stat.Value.Configurable)
					{
						statKey = (stat.Value.IsInt ? ((object)stat.Value.CfgInt) : ((object)stat.Value.Cfg));
						if (stat.Value.IsInt)
						{
							stat.Value.CfgInt.SettingChanged += UpdateFromConfig;
						}
						else
						{
							stat.Value.Cfg.SettingChanged += UpdateFromConfig;
						}
					}
					void UpdateFromConfig(object sender, EventArgs args)
					{
						ConfigChangeDebouncer.Schedule(statKey, delegate
						{
							if (!((Object)(object)ZNet.instance == (Object)null) && ((Behaviour)ZNet.instance).enabled)
							{
								stat.Value.Default_value = (stat.Value.IsInt ? ((float)stat.Value.CfgInt.Value) : stat.Value.Cfg.Value);
								UpdateItemInPlayerInventory(itemdef.Prefab, delegate(ItemData item)
								{
									ItemDataConfigModifier(stat.Key, stat.Value.Default_value, item);
								});
								EnqueueWorldUpdate(itemdef.Prefab, delegate(ItemData item)
								{
									ItemDataConfigModifier(stat.Key, stat.Value.Default_value, item);
								});
							}
						});
					}
				}
				itemdef.Recipe.RecipeConfig.SettingChanged += delegate
				{
					ConfigChangeDebouncer.Schedule(itemdef.Recipe.RecipeConfig, delegate
					{
						if (ValidateRecipeConfig(itemdef))
						{
							ModifyItemRecipeInODB(itemdef);
						}
					});
				};
				if (itemdef.DamageMods == null)
				{
					continue;
				}
				foreach (KeyValuePair<DamageType, HitCustomDamageMod> dmgmod in itemdef.DamageMods)
				{
					dmgmod.Value.DmgModCfg.SettingChanged += delegate
					{
						ConfigChangeDebouncer.Schedule(dmgmod.Value.DmgModCfg, delegate
						{
							//IL_004c: 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)
							if (!((Object)(object)ZNet.instance == (Object)null) && ((Behaviour)ZNet.instance).enabled)
							{
								DamageModifier modifier = (DamageModifier)Enum.Parse(typeof(DamageModifier), dmgmod.Value.DmgModCfg.Value);
								UpdateItemInPlayerInventory(itemdef.Prefab, delegate(ItemData item)
								{
									//IL_0001: Unknown result type (might be due to invalid IL or missing references)
									//IL_0011: Unknown result type (might be due to invalid IL or missing references)
									SetItemDamageModifier(modifier, dmgmod.Key, item);
								});
								EnqueueWorldUpdate(itemdef.Prefab, delegate(ItemData item)
								{
									//IL_0001: Unknown result type (might be due to invalid IL or missing references)
									//IL_0011: Unknown result type (might be due to invalid IL or missing references)
									SetItemDamageModifier(modifier, dmgmod.Key, item);
								});
							}
						});
					};
				}
			}
			return true;
		}

		private static void ReapplyAllRecipeConfig()
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null)
			{
				return;
			}
			foreach (ItemDefinition resourceDefinition in resourceDefinitions)
			{
				EnsureRecipeInDB(resourceDefinition);
				if (ValidateRecipeConfig(resourceDefinition))
				{
					ModifyItemRecipeInODB(resourceDefinition);
				}
				ModifyItemRecipeLevel(resourceDefinition, resourceDefinition.StationLVLCfg.Value);
				ModifyItemRecipeCraftedAt(resourceDefinition);
				ModifyItemRecipeCraftAmount(resourceDefinition, resourceDefinition.CraftAmountCfg.Value);
				EnableDisableItemInDB(resourceDefinition, resourceDefinition.CraftableCfg.Value);
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				Player.m_localPlayer.UpdateKnownRecipesList();
			}
		}

		private static void OnModConfigsChanged(object sender, ConfigurationSynchronizationEventArgs e)
		{
			if (e.UpdatedPluginGUIDs == null || e.UpdatedPluginGUIDs.Count <= 0 || e.UpdatedPluginGUIDs.Contains(ModContext.PluginGuid))
			{
				ReapplyAllRecipeConfig();
			}
		}

		private static T LoadBundleAsset<T>(string pathFormat, string bareName, params object[] formatArgs) where T : Object
		{
			if (!string.IsNullOrEmpty(pathFormat))
			{
				T val = Assets.LoadAsset<T>(string.Format(pathFormat, formatArgs));
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return Assets.LoadAsset<T>(bareName);
		}

		private static bool BatchAddItems()
		{
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Expected O, but got Unknown
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemDefinition resourceDefinition in resourceDefinitions)
			{
				GameObject val = LoadBundleAsset<GameObject>(PrefabPathFormat, resourceDefinition.Prefab, new object[2] { resourceDefinition.Category, resourceDefinition.Prefab });
				if ((Object)(object)val == (Object)null)
				{
					ModLogger.LogError("Could not find prefab '" + resourceDefinition.Prefab + "' for " + resourceDefinition.Name + " in the asset bundle; skipping.");
					continue;
				}
				Sprite val2 = (string.IsNullOrEmpty(resourceDefinition.Icon) ? null : LoadBundleAsset<Sprite>(IconPathFormat, resourceDefinition.Icon, new object[1] { resourceDefinition.Icon }));
				ItemDrop component = val.GetComponent<ItemDrop>();
				foreach (KeyValuePair<ItemStat, ItemStatConfig> modifableStat in resourceDefinition.ModifableStats)
				{
					if (!modifableStat.Value.Configurable)
					{
						ItemDataConfigModifier(modifableStat.Key, modifableStat.Value.Default_value, component.m_itemData);
					}
					else if (modifableStat.Value.IsInt)
					{
						ItemDataConfigModifier(modifableStat.Key, modifableStat.Value.CfgInt.Value, component.m_itemData);
					}
					else
					{
						ItemDataConfigModifier(modifableStat.Key, modifableStat.Value.Cfg.Value, component.m_itemData);
					}
				}
				if (resourceDefinition.DamageMods != null)
				{
					foreach (KeyValuePair<DamageType, HitCustomDamageMod> damageMod in resourceDefinition.DamageMods)
					{
						if (damageMod.Value.Configurable && damageMod.Value.DmgModCfg != null)
						{
							SetItemDamageModifier((DamageModifier)Enum.Parse(typeof(DamageModifier), damageMod.Value.DmgModCfg.Value), damageMod.Key, component.m_itemData);
						}
					}
				}
				if (resourceDefinition.Recipe.RecipeReqs == null || resourceDefinition.Recipe.RecipeReqs.Count == 0)
				{
					ModLogger.LogError("Item '" + resourceDefinition.Name + "' has no valid recipe requirements; registering it without a crafting recipe.");
					ItemManager.Instance.AddItem(new CustomItem(val, FixReferences));
				}
				else
				{
					ItemConfig val3 = new ItemConfig();
					val3.Amount = resourceDefinition.CraftAmountCfg.Value;
					val3.CraftingStation = resourceDefinition.CraftedAtCfg.Value ?? "";
					val3.MinStationLevel = resourceDefinition.StationLVLCfg.Value;
					val3.Enabled = true;
					val3.Icons = (Sprite[])(object)((!((Object)(object)val2 != (Object)null)) ? null : new Sprite[1] { val2 });
					val3.Requirements = resourceDefinition.Recipe.RecipeReqs.ToArray();
					ItemConfig val4 = val3;
					ItemManager.Instance.AddItem(new CustomItem(val, FixReferences, val4));
				}
				if (resourceDefinition.Category == ItemCategory.Arrows)
				{
					ArcheryAmmoToAdd.Add(resourceDefinition.Prefab);
				}
			}
			return true;
		}

		private static void ItemDataConfigModifier(ItemStat target_attribute, float updatedValue, ItemData itemData)
		{
			if (itemData != null)
			{
				switch (target_attribute)
				{
				case ItemStat.slash:
					itemData.m_shared.m_damages.m_slash = updatedValue;
					break;
				case ItemStat.slash_per_level:
					itemData.m_shared.m_damagesPerLevel.m_slash = updatedValue;
					break;
				case ItemStat.blunt:
					itemData.m_shared.m_damages.m_blunt = updatedValue;
					break;
				case ItemStat.blunt_per_level:
					itemData.m_shared.m_damagesPerLevel.m_blunt = updatedValue;
					break;
				case ItemStat.pierce:
					itemData.m_shared.m_damages.m_pierce = updatedValue;
					break;
				case ItemStat.pierce_per_level:
					itemData.m_shared.m_damagesPerLevel.m_pierce = updatedValue;
					break;
				case ItemStat.pickaxe:
					itemData.m_shared.m_damages.m_pickaxe = updatedValue;
					break;
				case ItemStat.pickaxe_per_level:
					itemData.m_shared.m_damagesPerLevel.m_pickaxe = updatedValue;
					break;
				case ItemStat.chop:
					itemData.m_shared.m_damages.m_chop = updatedValue;
					break;
				case ItemStat.chop_per_level:
					itemData.m_shared.m_damagesPerLevel.m_chop = updatedValue;
					break;
				case ItemStat.attack_force:
					itemData.m_shared.m_attackForce = updatedValue;
					break;
				case ItemStat.secondary_attack_force_multiply:
					itemData.m_shared.m_secondaryAttack.m_forceMultiplier = updatedValue;
					break;
				case ItemStat.primary_attack_force_multiply:
					itemData.m_shared.m_attack.m_forceMultiplier = updatedValue;
					break;
				case ItemStat.fire:
					itemData.m_shared.m_damages.m_fire = updatedValue;
					break;
				case ItemStat.fire_per_level:
					itemData.m_shared.m_damagesPerLevel.m_fire = updatedValue;
					break;
				case ItemStat.lightning:
					itemData.m_shared.m_damages.m_lightning = updatedValue;
					break;
				case ItemStat.lightning_per_level:
					itemData.m_shared.m_damagesPerLevel.m_lightning = updatedValue;
					break;
				case ItemStat.frost:
					itemData.m_shared.m_damages.m_frost = updatedValue;
					break;
				case ItemStat.frost_per_level:
					itemData.m_shared.m_damagesPerLevel.m_frost = updatedValue;
					break;
				case ItemStat.poison:
					itemData.m_shared.m_damages.m_poison = updatedValue;
					break;
				case ItemStat.poison_per_level:
					itemData.m_shared.m_damagesPerLevel.m_poison = updatedValue;
					break;
				case ItemStat.spirit:
					itemData.m_shared.m_damages.m_spirit = updatedValue;
					break;
				case ItemStat.spirit_per_level:
					itemData.m_shared.m_damagesPerLevel.m_spirit = updatedValue;
					break;
				case ItemStat.block_armor:
					itemData.m_shared.m_blockPower = updatedValue;
					break;
				case ItemStat.block_armor_per_level:
					itemData.m_shared.m_blockPowerPerLevel = updatedValue;
					break;
				case ItemStat.parry:
					itemData.m_shared.m_timedBlockBonus = updatedValue;
					break;
				case ItemStat.block_force:
					itemData.m_shared.m_deflectionForce = updatedValue;
					break;
				case ItemStat.block_force_per_level:
					itemData.m_shared.m_deflectionForcePerLevel = updatedValue;
					break;
				case ItemStat.primary_attack_stamina:
					itemData.m_shared.m_attack.m_attackStamina = updatedValue;
					break;
				case ItemStat.primary_attack_eitr:
					itemData.m_shared.m_attack.m_attackEitr = updatedValue;
					break;
				case ItemStat.primary_attack_flat_health_cost:
					itemData.m_shared.m_attack.m_attackHealth = updatedValue;
					break;
				case ItemStat.primary_attack_percent_health_cost:
					itemData.m_shared.m_attack.m_attackHealthPercentage = updatedValue;
					break;
				case ItemStat.primary_attack_health_returned:
					itemData.m_shared.m_attack.m_attackHealthReturnHit = updatedValue;
					break;
				case ItemStat.primary_attack_damage_bonus_per_missing_hp:
					itemData.m_shared.m_attack.m_damageMultiplierPerMissingHP = updatedValue;
					break;
				case ItemStat.primary_attack_projectile_count:
					itemData.m_shared.m_attack.m_projectiles = (int)updatedValue;
					break;
				case ItemStat.secondary_attack_stamina:
					itemData.m_shared.m_secondaryAttack.m_attackStamina = updatedValue;
					break;
				case ItemStat.secondary_attack_eitr:
					itemData.m_shared.m_secondaryAttack.m_attackEitr = updatedValue;
					break;
				case ItemStat.secondary_attack_flat_health_cost:
					itemData.m_shared.m_secondaryAttack.m_attackHealth = updatedValue;
					break;
				case ItemStat.secondary_attack_percent_health_cost:
					itemData.m_shared.m_secondaryAttack.m_attackHealthPercentage = updatedValue;
					break;
				case ItemStat.movement_speed:
					itemData.m_shared.m_movementModifier = updatedValue;
					break;
				case ItemStat.bow_draw_speed:
					itemData.m_shared.m_attack.m_drawDurationMin = updatedValue;
					break;
				case ItemStat.crossbow_reload_speed:
					itemData.m_shared.m_attack.m_reloadTime = updatedValue;
					break;
				case ItemStat.crossbow_reload_stamina_drain:
					itemData.m_shared.m_attack.m_reloadStaminaDrain = updatedValue;
					break;
				case ItemStat.draw_stamina_drain:
					itemData.m_shared.m_attack.m_drawStaminaDrain = updatedValue;
					break;
				case ItemStat.projectile_velocity:
					itemData.m_shared.m_attack.m_projectileVel = updatedValue;
					break;
				case ItemStat.projectile_accuracy_max:
					itemData.m_shared.m_attack.m_projectileAccuracy = 100f - updatedValue;
					break;
				case ItemStat.durability:
					itemData.m_shared.m_maxDurability = updatedValue;
					break;
				case ItemStat.durability_per_level:
					itemData.m_shared.m_durabilityPerLevel = updatedValue;
					break;
				case ItemStat.max_item_level:
					itemData.m_shared.m_maxQuality = (int)updatedValue;
					break;
				case ItemStat.amount:
					itemData.m_shared.m_maxStackSize = (int)updatedValue;
					break;
				case ItemStat.tool_level:
					itemData.m_shared.m_toolTier = (int)updatedValue;
					break;
				case ItemStat.food_health:
					itemData.m_shared.m_food = updatedValue;
					break;
				case ItemStat.food_stamina:
					itemData.m_shared.m_foodStamina = updatedValue;
					break;
				case ItemStat.food_eitr:
					itemData.m_shared.m_foodEitr = updatedValue;
					break;
				case ItemStat.food_regen:
					itemData.m_shared.m_foodRegen = updatedValue;
					break;
				case ItemStat.food_duration:
					itemData.m_shared.m_foodBurnTime = updatedValue;
					break;
				default:
					ModLogger.LogWarning($"Unknown item stat {target_attribute} for {itemData.m_shared.m_name}");
					break;
				}
			}
		}

		private static bool ValidateRecipeConfig(ItemDefinition itemdef)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			List<RequirementConfig> list = new List<RequirementConfig>();
			try
			{
				string[] array = itemdef.Recipe.RecipeConfig.Value.Split(new char[1] { '|' });
				foreach (string text in array)
				{
					string[] array2 = text.Split(new char[1] { ',' });
					if (array2.Length == 1)
					{
						return false;
					}
					if (array2.Length != 3)
					{
						ModLogger.LogWarning("Invalid (" + itemdef.Name + ") recipe config detected: " + text + ". Needs three entries eg: Wood,1,1");
						return false;
					}
					list.Add(new RequirementConfig
					{
						Item = array2[0],
						Amount = int.Parse(array2[1]),
						AmountPerLevel = int.Parse(array2[2])
					});
				}
				itemdef.Recipe.RecipeReqs = list;
				return true;
			}
			catch
			{
				ModLogger.LogWarning("Recipe is Invalid. Should have the format of Wood,1,1|Stone,2,0 - Prefab,cost,upgrade.");
				return false;
			}
		}

		private static void BuildRecipeReqsFromDefault(ItemDefinition itemdef)
		{
			//IL_0022: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			List<RequirementConfig> list = new List<RequirementConfig>();
			foreach (RecipeIngredient recipeItem in itemdef.Recipe.RecipeItems)
			{
				list.Add(new RequirementConfig
				{
					Item = recipeItem.Prefab,
					Amount = recipeItem.Amount,
					AmountPerLevel = recipeItem.UpgradeCost
				});
			}
			itemdef.Recipe.RecipeReqs = list;
		}

		private static string BuildStringRecipeFromItemDef(ItemDefinition itemdef)
		{
			List<string> list = new List<string>();
			foreach (RecipeIngredient recipeItem in itemdef.Recipe.RecipeItems)
			{
				list.Add($"{recipeItem.Prefab},{recipeItem.Amount},{recipeItem.UpgradeCost}");
			}
			return string.Join("|", list.ToArray());
		}

		private static bool ModifyItemRecipeCraftedAt(ItemDefinition itemdef)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null)
			{
				return false;
			}
			int recipeIndexByPrefab = GetRecipeIndexByPrefab(itemdef.Prefab);
			if (recipeIndexByPrefab == -1)
			{
				ModLogger.LogWarning("Recipe of " + itemdef.Prefab + " not found in ObjectDB, recipe will not be modified.");
				return false;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(itemdef.CraftedAtCfg.Value);
			CraftingStation val = ((prefab != null) ? prefab.GetComponent<CraftingStation>() : null);
			if ((Object)(object)val == (Object)null)
			{
				ModLogger.LogWarning("Crafting Station " + itemdef.CraftedAtCfg.Value + " prefab not found, or does not have a crafting station componet.");
				return false;
			}
			ObjectDB.instance.m_recipes[recipeIndexByPrefab].m_craftingStation = val;
			ObjectDB.instance.m_recipes[recipeIndexByPrefab].m_repairStation = val;
			return true;
		}

		private static void ModifyItemRecipeInODB(ItemDefinition itemdef)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null)
			{
				return;
			}
			int recipeIndexByPrefab = GetRecipeIndexByPrefab(itemdef.Prefab);
			if (recipeIndexByPrefab == -1)
			{
				ModLogger.LogWarning("Recipe of " + itemdef.Prefab + " not found in ObjectDB, Recipe will not be modified.");
				return;
			}
			Recipe val = ObjectDB.instance.m_recipes[recipeIndexByPrefab];
			Recipe val2 = val;
			List<Requirement> list = new List<Requirement>();
			foreach (RequirementConfig recipeReq in itemdef.Recipe.RecipeReqs)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(recipeReq.Item);
				if ((Object)(object)itemPrefab == (Object)null)
				{
					ModLogger.LogWarning("Recipe for " + itemdef.Prefab + " has an invalid requirement " + recipeReq.Item + ".");
					return;
				}
				list.Add(new Requirement
				{
					m_resItem = itemPrefab.GetComponent<ItemDrop>(),
					m_amount = recipeReq.Amount,
					m_amountPerLevel = recipeReq.AmountPerLevel
				});
			}
			val2.m_resources = list.ToArray();
			int num = ObjectDB.instance.m_recipes.IndexOf(val);
			if (num > -1)
			{
				ObjectDB.instance.m_recipes[num] = val2;
				itemdef.Recipe.ResolvedRecipe = val2;
			}
			else
			{
				ModLogger.LogWarning("Recipe " + ((Object)val).name + " not found in ObjectDB.");
			}
		}

		private static void EnsureRecipeInDB(ItemDefinition itemdef)
		{
			if (!((Object)(object)ObjectDB.instance == (Object)null) && ObjectDB.instance.m_recipes != null && GetRecipeIndexByPrefab(itemdef.Prefab) == -1 && (Object)(object)itemdef.Recipe.ResolvedRecipe != (Object)null)
			{
				ObjectDB.instance.m_recipes.Add(itemdef.Recipe.ResolvedRecipe);
			}
		}

		private static void EnableDisableItemInDB(ItemDefinition itemdef, bool enable)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null)
			{
				return;
			}
			int recipeIndexByPrefab = GetRecipeIndexByPrefab(itemdef.Prefab);
			if (recipeIndexByPrefab == -1)
			{
				if ((Object)(object)itemdef.Recipe.ResolvedRecipe != (Object)null)
				{
					itemdef.Recipe.ResolvedRecipe.m_enabled = enable;
					ObjectDB.instance.m_recipes.Add(itemdef.Recipe.ResolvedRecipe);
				}
				else
				{
					ModLogger.LogWarning("Recipe of " + itemdef.Prefab + " not found in ObjectDB and no cached recipe to re-add.");
				}
			}
			else
			{
				ObjectDB.instance.m_recipes[recipeIndexByPrefab].m_enabled = enable;
				itemdef.Recipe.ResolvedRecipe = ObjectDB.instance.m_recipes[recipeIndexByPrefab];
			}
		}

		private static void ModifyItemRecipeLevel(ItemDefinition itemdef, int level)
		{
			if (!((Object)(object)ObjectDB.instance == (Object)null) && ObjectDB.instance.m_recipes != null)
			{
				int recipeIndexByPrefab = GetRecipeIndexByPrefab(itemdef.Prefab);
				if (recipeIndexByPrefab == -1)
				{
					ModLogger.LogWarning("Recipe of " + itemdef.Prefab + " not found in ObjectDB, required level will not be modified.");
					return;
				}
				ObjectDB.instance.m_recipes[recipeIndexByPrefab].m_minStationLevel = level;
				itemdef.Recipe.ResolvedRecipe = ObjectDB.instance.m_recipes[recipeIndexByPrefab];
			}
		}

		private static void ModifyItemRecipeCraftAmount(ItemDefinition itemdef, int amount)
		{
			if (!((Object)(object)ObjectDB.instance == (Object)null) && ObjectDB.instance.m_recipes != null)
			{
				int recipeIndexByPrefab = GetRecipeIndexByPrefab(itemdef.Prefab);
				if (recipeIndexByPrefab == -1)
				{
					ModLogger.LogWarning("Recipe of " + itemdef.Prefab + " not found in ObjectDB, craft amount will not be modified.");
					return;
				}
				ObjectDB.instance.m_recipes[recipeIndexByPrefab].m_amount = amount;
				itemdef.Recipe.ResolvedRecipe = ObjectDB.instance.m_recipes[recipeIndexByPrefab];
			}
		}

		private static int GetRecipeIndexByPrefab(string prefab)
		{
			return ObjectDB.instance.m_recipes.FindIndex((Recipe m) => (Object)(object)m.m_item != (Object)null && ((Object)m.m_item).name == prefab);
		}

		private static void SetItemDamageModifier(DamageModifier modifier, DamageType type, ItemData itemData)
		{
			//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_0079: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_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_006f: Unknown result type (might be due to invalid IL or missing references)
			List<DamageModPair> list = itemData.m_shared.m_damageModifiers.Where((DamageModPair entry) => entry.m_type != type).ToList();
			if (list.Count == 0)
			{
				itemData.m_shared.m_damageModifiers.Clear();
				itemData.m_shared.m_damageModifiers.Add(new DamageModPair
				{
					m_modifier = modifier,
					m_type = type
				});
			}
			else
			{
				list.Add(new DamageModPair
				{
					m_modifier = modifier,
					m_type = type
				});
				itemData.m_shared.m_damageModifiers = list;
			}
		}

		private static void UpdateItemInPlayerInventory(string prefab, Action<ItemData> callback)
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).m_inventory.GetAllItems())
			{
				if (allItem != null && !((Object)(object)allItem.m_dropPrefab == (Object)null) && !(((Object)allItem.m_dropPrefab).name != prefab))
				{
					callback(allItem);
				}
			}
		}

		private static void EnqueueWorldUpdate(string prefab, Action<ItemData> callback)
		{
			ThreadingHelper instance = ThreadingHelper.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				pendingWorldUpdates.Add(new KeyValuePair<string, Action<ItemData>>(prefab, callback));
				if (!worldUpdateScheduled)
				{
					worldUpdateScheduled = true;
					((MonoBehaviour)instance).StartCoroutine(DrainWorldUpdates());
				}
			}
		}

		private static IEnumerator DrainWorldUpdates()
		{
			yield return null;
			try
			{
				if (pendingWorldUpdates.Count <= 0)
				{
					yield break;
				}
				GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
				ItemDrop val2 = default(ItemDrop);
				foreach (GameObject val in array)
				{
					if ((Object)(object)val == (Object)null || !val.TryGetComponent<ItemDrop>(ref val2))
					{
						continue;
					}
					foreach (KeyValuePair<string, Action<ItemData>> pendingWorldUpdate in pendingWorldUpdates)
					{
						if (((Object)val).name == pendingWorldUpdate.Key || ((Object)val).name == pendingWorldUpdate.Key + "(Clone)")
						{
							pendingWorldUpdate.Value(val2.m_itemData);
						}
					}
				}
			}
			finally
			{
				pendingWorldUpdates.Clear();
				worldUpdateScheduled = false;
			}
		}

		private static void AddAmmoItemsToArcheryTarget()
		{
			if (ArcheryAmmoToAdd.Count == 0)
			{
				return;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab("piece_ArcheryTarget");
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			ArcheryTarget componentInChildren = prefab.GetComponentInChildren<ArcheryTarget>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return;
			}
			foreach (string item in ArcheryAmmoToAdd)
			{
				ModLogger.LogDebug("Adding " + item + " to Archery Target Ammo Return.");
				GameObject prefab2 = PrefabManager.Instance.GetPrefab(item);
				ItemDrop val = ((prefab2 != null) ? prefab2.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val != (Object)null && !componentInChildren.m_returnAmmo.Contains(val))
				{
					componentInChildren.m_returnAmmo.Add(val);
				}
			}
		}
	}
	public enum ItemStat
	{
		slash,
		slash_per_level,
		blunt,
		blunt_per_level,
		pierce,
		pierce_per_level,
		pickaxe,
		pickaxe_per_level,
		chop,
		chop_per_level,
		attack_force,
		fire,
		fire_per_level,
		lightning,
		lightning_per_level,
		frost,
		frost_per_level,
		poison,
		poison_per_level,
		spirit,
		spirit_per_level,
		block_armor,
		block_armor_per_level,
		parry,
		block_force,
		block_force_per_level,
		primary_attack_stamina,
		primary_attack_eitr,
		primary_attack_flat_health_cost,
		primary_attack_percent_health_cost,
		primary_attack_health_returned,
		primary_attack_damage_bonus_per_missing_hp,
		primary_attack_projectile_count,
		primary_attack_force_multiply,
		secondary_attack_stamina,
		secondary_attack_eitr,
		secondary_attack_force_multiply,
		secondary_attack_flat_health_cost,
		secondary_attack_percent_health_cost,
		movement_speed,
		bow_draw_speed,
		crossbow_reload_speed,
		crossbow_reload_stamina_drain,
		draw_stamina_drain,
		projectile_velocity,
		projectile_accuracy_max,
		durability,
		durability_per_level,
		max_item_level,
		amount,
		tool_level,
		food_health,
		food_stamina,
		food_eitr,
		food_regen,
		food_duration
	}
	public enum ItemCategory
	{
		Arrows,
		Atgeirs,
		Axes,
		Hammers,
		Shields,
		Swords,
		Bows,
		Spears,
		Knives,
		Maces,
		Fists,
		Pickaxes,
		Magics,
		Misc,
		Food
	}
	public class ItemDefinition
	{
		public string Name { get; set; }

		public string DisplayName { get; set; }

		public ItemCategory Category { get; set; }

		public string Prefab { get; set; }

		public string Icon { get; set; }

		public string CraftedAt { get; set; }

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

		public int ReqStationlevel { get; set; }

		public int CraftAmount { get; set; }

		public Dictionary<ItemStat, ItemStatConfig> ModifableStats { get; set; } = new Dictionary<ItemStat, ItemStatConfig>();

		public Dictionary<DamageType, HitCustomDamageMod> DamageMods { get; set; }

		public RecipeDefinition Recipe { get; set; }

		public ConfigEntry<string> CraftedAtCfg { get; set; }

		public ConfigEntry<bool> CraftableCfg { get; set; }

		public ConfigEntry<int> StationLVLCfg { get; set; }

		public ConfigEntry<int> CraftAmountCfg { get; set; }
	}
	public class HitCustomDamageMod
	{
		public bool Configurable { get; set; } = true;

		public DamageModifier DamageModifier { get; set; }

		public ConfigEntry<string> DmgModCfg { get; set; }
	}
	public class ItemStatConfig
	{
		public bool Configurable { get; set; } = true;

		public bool IsInt { get; set; }

		public float Default_value { get; set; }

		public float Min { get; set; }

		public float Max { get; set; } = 400f;

		public ConfigEntry<float> Cfg { get; set; }

		public ConfigEntry<int> CfgInt { get; set; }
	}
	public class RecipeDefinition
	{
		public ConfigEntry<string> RecipeConfig { get; set; }

		public List<RecipeIngredient> RecipeItems { get; set; }

		public List<RequirementConfig> RecipeReqs { get; set; }

		public Recipe ResolvedRecipe { get; set; }
	}
	public class RecipeIngredient
	{
		public string Prefab { get; set; }

		public int Amount { get; set; }

		public int UpgradeCost { get; set; }
	}
	public static class ModContext
	{
		public static ManualLogSource Log { get; private set; }

		public static ConfigFile Cfg { get; private set; }

		public static string PluginGuid { get; private set; }

		public static string ConfigFolder { get; private set; }

		public static AssetBundle AssetBundle { get; set; }

		public static CustomLocalization Localization { get; set; }

		public static ConfigEntry<bool> EnableDebugMode { get; private set; }

		public static ConfigEntry<float> ConfigApplyDelay { get; private set; }

		public static bool Initialized { get; private set; }

		public static bool DebugEnabled
		{
			get
			{
				if (EnableDebugMode != null)
				{
					return EnableDebugMode.Value;
				}
				return false;
			}
		}

		public static void Initialize(BaseUnityPlugin plugin, ManualLogSource log, string configFolder, AssetBundle assetBundle = null, CustomLocalization localization = null, string configSection = "Common")
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			if ((Object)(object)plugin == (Object)null)
			{
				throw new ArgumentNullException("plugin");
			}
			Log = log;
			Cfg = plugin.Config;
			PluginInfo info = plugin.Info;
			object obj;
			if (info == null)
			{
				obj = null;
			}
			else
			{
				BepInPlugin metadata = info.Metadata;
				obj = ((metadata != null) ? metadata.GUID : null);
			}
			if (obj == null)
			{
				obj = configFolder;
			}
			PluginGuid = (string)obj;
			ConfigFolder = configFolder;
			if ((Object)(object)assetBundle != (Object)null)
			{
				AssetBundle = assetBundle;
			}
			if (localization != null)
			{
				Localization = localization;
			}
			Cfg.SaveOnConfigSet = true;
			EnableDebugMode = Cfg.Bind<bool>(configSection, "EnableDebugMode", false, new ConfigDescription("Enables verbose debug logging for the shared item/piece loaders.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdvanced = true
			} }));
			EnableDebugMode.SettingChanged += ModLogger.OnDebugModeChanged;
			ConfigApplyDelay = ConfigBinder.BindServerConfig(configSection, "Config Apply Delay", 1f, "Delay in seconds before a changed config entry is applied in-game. Coalesces a burst of rapid edits (typing, file reloads, server sync) into a single apply. Set to 0 to apply instantly.", advanced: true, 0f, 10f);
			Initialized = true;
			ModLogger.RefreshLevel();
		}

		public static void UseDebugEntry(ConfigEntry<bool> entry)
		{
			if (entry != null)
			{
				if (EnableDebugMode != null)
				{
					EnableDebugMode.SettingChanged -= ModLogger.OnDebugModeChanged;
				}
				EnableDebugMode = entry;
				EnableDebugMode.SettingChanged += ModLogger.OnDebugModeChanged;
				ModLogger.RefreshLevel();
			}
		}

		public static void SaveOnSet(bool enabled)
		{
			if (Cfg != null)
			{
				Cfg.SaveOnConfigSet = enabled;
				Cfg.Save();
			}
		}
	}
	public static class ModLocalization
	{
		public static string LocalizationFolder = "Localizations";

		public static void AddLocalizations(Assembly assembly = null)
		{
			if (assembly == null)
			{
				assembly = Assembly.GetExecutingAssembly();
			}
			CustomLocalization val = (ModContext.Localization = ModContext.Localization ?? LocalizationManager.Instance.GetLocalization());
			string text = Path.Combine(Paths.ConfigPath, ModContext.ConfigFolder ?? assembly.GetName().Name, LocalizationFolder);
			Directory.CreateDirectory(text);
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			foreach (string text2 in manifestResourceNames)
			{
				if (text2.IndexOf(LocalizationFolder, StringComparison.OrdinalIgnoreCase) < 0 || !text2.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				string text3 = LanguageFromResourceName(text2);
				if (string.IsNullOrEmpty(text3))
				{
					ModLogger.LogWarning("Could not derive a language name from '" + text2 + "', skipping.");
					continue;
				}
				string text4 = Regex.Replace(ReadEmbeddedResourceFile(text2, assembly), "\\/\\/.*", "");
				string text5 = Path.Combine(text, text3 + ".json");
				string text6 = text4;
				if (File.Exists(text5))
				{
					try
					{
						Dictionary<string, string> shipped = SimpleJson.DeserializeObject<Dictionary<string, string>>(text4);
						Dictionary<string, string> dictionary = SimpleJson.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(text5));
						ReconcileKeys(shipped, dictionary);
						text6 = SimpleJson.SerializeObject((object)dictionary);
					}
					catch (Exception ex)
					{
						ModLogger.LogWarning("Could not merge '" + text5 + "' (" + ex.Message + "); replacing it with the shipped localization.");
						text6 = text4;
					}
				}
				File.WriteAllText(text5, text6);
				val.AddJsonFile(text3, text6);
				ModLogger.LogDebug("Added localization '" + text3 + "' from " + text2);
			}
		}

		private static string LanguageFromResourceName(string embeddedResource)
		{
			return embeddedResource.Substring(0, embeddedResource.Length - ".json".Length).Split(new char[1] { '.' }).LastOrDefault();
		}

		private static void ReconcileKeys(Dictionary<string, string> shipped, Dictionary<string, string> onDisk)
		{
			List<string> list = onDisk.Keys.Where((string key) => !shipped.ContainsKey(key)).ToList();
			foreach (KeyValuePair<string, string> item in shipped)
			{
				if (!onDisk.ContainsKey(item.Key))
				{
					ModLogger.LogDebug("Adding missing localization key " + item.Key);
					onDisk.Add(item.Key, item.Value);
				}
			}
			if (list.Count <= 0)
			{
				return;
			}
			ModLogger.LogDebug("Removing extra keys " + string.Join(",", list.ToArray()) + ".");
			foreach (string item2 in list)
			{
				onDisk.Remove(item2);
			}
		}

		private static string ReadEmbeddedResourceFile(string filename, Assembly assembly)
		{
			using Stream stream = assembly.GetManifestResourceStream(filename);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}
	}
	public static class ModLogger
	{
		public static LogLevel Level = (LogLevel)16;

		internal static void OnDebugModeChanged(object sender, EventArgs e)
		{
			RefreshLevel();
		}

		public static void RefreshLevel()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Level = (LogLevel)(ModContext.DebugEnabled ? 32 : 16);
		}

		public static void SetDebugLogging(bool state)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Level = (LogLevel)(state ? 32 : 16);
		}

		public static void LogDebug(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 32)
			{
				Write((LogLevel)16, "[DEBUG]" + message);
			}
		}

		public static void LogInfo(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 16)
			{
				Write((LogLevel)16, message);
			}
		}

		public static void LogWarning(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 4)
			{
				Write((LogLevel)4, message);
			}
		}

		public static void LogError(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 2)
			{
				Write((LogLevel)2, message);
			}
		}

		private static void Write(LogLevel level, string message)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			ManualLogSource log = ModContext.Log;
			if (log == null)
			{
				Debug.Log((object)$"[Common][{level}] {message}");
			}
			else
			{
				log.Log(level, (object)message);
			}
		}
	}
	public static class PieceLoader
	{
		public class LoadedGameObjects
		{
			public GameObject Prefab { get; set; }

			public Sprite Sprite { get; set; }

			public GameObject ScenePrefab { get; set; }

			public Piece ScenePiece { get; set; }
		}

		public class PieceCost
		{
			public string Prefab { get; set; }

			public int Amount { get; set; }

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

		public class PieceConfigs
		{
			public ConfigEntry<bool> Enabled { get; set; }

			public ConfigEntry<bool> RequiresWorkbench { get; set; }

			public ConfigEntry<string> Workbench { get; set; }

			public ConfigEntry<string> PieceCategory { get; set; }

			public ConfigEntry<string> PieceCost { get; set; }

			public List<PieceCost> UpdatedCost { get; set; } = new List<PieceCost>();
		}

		public class BuildPiece
		{
			public string Name { get; set; }

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

			public string Prefab { get; set; }

			public string Sprite { get; set; }

			public string Category { get; set; } = PieceCategories.Misc;

			public string PieceTable { get; set; } = PieceTables.Hammer;

			public string Workbench { get; set; } = "piece_workbench";

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

			public bool AllowedInDungeons { get; set; }

			public List<PieceCost> PieceCost { get; set; } = new List<PieceCost>();

			public LoadedGameObjects Objs { get; set; }

			public PieceConfigs Cfgs { get; set; }
		}

		private static readonly List<BuildPiece> BuildPieces = new List<BuildPiece>();

		private static bool PiecesReady = false;

		public static void Register(BuildPiece jbuildpiece, AssetBundle assetBundle = null)
		{
			AssetBundle val = assetBundle ?? ModContext.AssetBundle;
			if ((Object)(object)val == (Object)null)
			{
				ModLogger.LogError("No asset bundle available; piece '" + jbuildpiece.Name + "' will not be registered.");
				return;
			}
			LoadedGameObjects loadedGameObjects = new LoadedGameObjects();
			loadedGameObjects.Prefab = LoadBundleAsset<GameObject>(val, jbuildpiece.Prefab, ".prefab");
			if ((Object)(object)loadedGameObjects.Prefab == (Object)null)
			{
				ModLogger.LogError("Could not find prefab '" + jbuildpiece.Prefab + "' in the asset bundle; piece '" + jbuildpiece.Name + "' will not be registered.");
				return;
			}
			if (!string.IsNullOrEmpty(jbuildpiece.Sprite))
			{
				loadedGameObjects.Sprite = LoadBundleAsset<Sprite>(val, jbuildpiece.Sprite, ".png");
			}
			jbuildpiece.Objs = loadedGameObjects;
			jbuildpiece.Cfgs = new PieceConfigs();
			InitialPieceSetup(jbuildpiece);
			BuildPieces.Add(jbuildpiece);
			PrefabManager.OnPrefabsRegistered += ResolveAndApplyScenePrefab;
			void ResolveAndApplyScenePrefab()
			{
				GameObject val2 = ResolveScenePrefab(jbuildpiece.Prefab);
				if ((Object)(object)val2 == (Object)null)
				{
					ModLogger.LogWarning("Could not find a scene prefab named '" + jbuildpiece.Prefab + "' with a Piece component after prefab registration; skipping in-place setup for " + jbuildpiece.Name + ".");
				}
				else
				{
					jbuildpiece.Objs.ScenePrefab = val2;
					jbuildpiece.Objs.ScenePiece = val2.GetComponent<Piece>();
					PiecesReady = true;
					ApplyWorkbench(jbuildpiece);
					ApplyCategory(jbuildpiece);
					ApplyRecipe(jbuildpiece);
				}
			}
		}

		private static GameObject ResolveScenePrefab(string prefabName)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName);
			if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<Piece>() != (Object)null)
			{
				return prefab;
			}
			List<GameObject> list = (from obj in Resources.FindObjectsOfTypeAll<GameObject>()
				where ((Object)obj).name == prefabName && (Object)(object)obj.GetComponent<Piece>() != (Object)null
				select obj).ToList();
			if (ModContext.DebugEnabled)
			{
				ModLogger.LogInfo($"Found {list.Count} scene object(s) named '{prefabName}' with a Piece component.");
			}
			return list.FirstOrDefault();
		}

		private static T LoadBundleAsset<T>(AssetBundle bundle, string name, string suffix) where T : Object
		{
			T val = bundle.LoadAsset<T>(name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			if (!name.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
			{
				return bundle.LoadAsset<T>(name + suffix);
			}
			return default(T);
		}

		private static void InitialPieceSetup(BuildPiece jbuildpiece)
		{
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Expected O, but got Unknown
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Expected O, but got Unknown
			//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Expected O, but got Unknown
			jbuildpiece.Cfgs.RequiresWorkbench = ConfigBinder.BindServerConfig(jbuildpiece.Name, "Requires Workbench", jbuildpiece.RequiresWorkbench, "Whether " + jbuildpiece.Name + " requires a crafting station to be built at all.");
			jbuildpiece.Cfgs.RequiresWorkbench.SettingChanged += RequiredBench_SettingChanged;
			jbuildpiece.Cfgs.Workbench = ConfigBinder.BindServerConfig(jbuildpiece.Name, "Workbench", jbuildpiece.Workbench, "The table required to allow building this piece, eg: 'forge', 'piece_workbench', 'blackforge', 'piece_artisanstation'.");
			jbuildpiece.Cfgs.Workbench.SettingChanged += RequiredBench_SettingChanged;
			jbuildpiece.Cfgs.Enabled = ConfigBinder.BindServerConfig(jbuildpiece.Name, "Enabled", jbuildpiece.Enabled, "Enable/Disable the " + jbuildpiece.Name + ".");
			jbuildpiece.Cfgs.Enabled.SettingChanged += BuildRecipeChanged_SettingChanged;
			jbuildpiece.Cfgs.PieceCategory = ConfigBinder.BindServerConfig(jbuildpiece.Name, "Piece Category", jbuildpiece.Category, "Piece category for building.", PieceCategories.GetAcceptableValueList());
			jbuildpiece.Cfgs.PieceCategory.SettingChanged += CraftingCategory_SettingChanged;
			List<string> list = new List<string>();
			foreach (PieceCost item in jbuildpiece.PieceCost)
			{
				list.Add($"{item.Prefab},{item.Amount},{item.Refundable}");
			}
			string text = string.Join("|", list.ToArray());
			jbuildpiece.Cfgs.PieceCost = ConfigBinder.BindServerConfig(jbuildpiece.Name, "Building Cost", text, "Cost to build. Find item ids: https://valheim.fandom.com/wiki/Item_IDs Format: resouce_id,amount,refund eg: Wood,8,true|LeatherScraps,4,false", (AcceptableValueList<string>)null, advanced: true);
			if (!PieceRecipeConfigUpdater(jbuildpiece, jbuildpiece.Cfgs.PieceCost.Value, during_runtime: false))
			{
				ModLogger.LogWarning(jbuildpiece.Name + " has an invalid piece cost. The default will be used instead.");
				PieceRecipeConfigUpdater(jbuildpiece, text, during_runtime: false);
			}
			jbuildpiece.Cfgs.PieceCost.SettingChanged += BuildRecipeChanged_SettingChanged;
			PieceConfigDrawer.Attach(jbuildpiece);
			if (jbuildpiece.Cfgs.UpdatedCost.Count == 0)
			{
				ModLogger.LogError(jbuildpiece.Name + " has no valid build cost (empty or unparseable PieceCost); skipping registration so it cannot be built for free.");
				return;
			}
			List<RequirementConfig> list2 = new List<RequirementConfig>();
			foreach (PieceCost item2 in jbuildpiece.Cfgs.UpdatedCost)
			{
				list2.Add(new RequirementConfig
				{
					Item = item2.Prefab,
					Amount = item2.Amount,
					Recover = item2.Refundable
				});
			}
			PieceConfig val = new PieceConfig
			{
				CraftingStation = ResolveWorkbenchName(jbuildpiece),
				PieceTable = jbuildpiece.PieceTable,
				Category = jbuildpiece.Cfgs.PieceCategory.Value,
				AllowedInDungeons = jbuildpiece.AllowedInDungeons,
				Icon = jbuildpiece.Objs.Sprite,
				Requirements = list2.ToArray()
			};
			PieceManager.Instance.AddPiece(new CustomPiece(jbuildpiece.Objs.Prefab, true, val));
			void BuildRecipeChanged_SettingChanged(object sender, EventArgs e)
			{
				if (PiecesReady && !((Object)(object)jbuildpiece.Objs.ScenePiece == (Object)null))
				{
					ConfigChangeDebouncer.Schedule(sender, delegate
					{
						if (sender is ConfigEntry<string> val2)
						{
							if (ModContext.DebugEnabled)
							{
								ModLogger.LogInfo("Recieved new piece config " + val2.Value);
							}
							if (!PieceRecipeConfigUpdater(jbuildpiece, val2.Value))
							{
								return;
							}
						}
						ApplyRecipe(jbuildpiece);
					});
				}
			}
			void CraftingCategory_SettingChanged(object sender, EventArgs e)
			{
				if (PiecesReady && !((Object)(object)jbuildpiece.Objs.ScenePiece == (Object)null))
				{
					ConfigChangeDebouncer.Schedule(jbuildpiece.Cfgs.PieceCategory, delegate
					{
						ApplyCategory(jbuildpiece);
					});
				}
			}
			void RequiredBench_SettingChanged(object sender, EventArgs e)
			{
				if (PiecesReady && !((Object)(object)jbuildpiece.Objs.ScenePiece == (Object)null))
				{
					ConfigChangeDebouncer.Schedule(jbuildpiece.Cfgs.Workbench, delegate
					{
						ApplyWorkbench(jbuildpiece);
					});
				}
			}
		}

		private static string ResolveWorkbenchName(BuildPiece jbuildpiece)
		{
			bool num = jbuildpiece.Cfgs.RequiresWorkbench?.Value ?? true;
			string value = jbuildpiece.Cfgs.Workbench.Value;
			if (!num || string.IsNullOrEmpty(value) || value.ToLower() == "none")
			{
				return null;
			}
			return value;
		}

		private static void ApplyWorkbench(BuildPiece jbuildpiece)
		{
			Piece scenePiece = jbuildpiece.Objs.ScenePiece;
			if ((Object)(object)scenePiece == (Object)null)
			{
				return;
			}
			string text = ResolveWorkbenchName(jbuildpiece);
			if (text == null)
			{
				if (ModContext.DebugEnabled)
				{
					ModLogger.LogInfo("Setting required crafting station for " + jbuildpiece.Name + " to none.");
				}
				scenePiece.m_craftingStation = null;
				return;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(text);
			CraftingStation val = ((prefab != null) ? prefab.GetComponent<CraftingStation>() : null);
			if ((Object)(object)val == (Object)null)
			{
				ModLogger.LogWarning("Required crafting station does not exist or does not have a crafting station component, check your prefab name (" + text + ").");
				return;
			}
			if (ModContext.DebugEnabled)
			{
				ModLogger.LogInfo("Setting crafting station to " + text + ".");
			}
			scenePiece.m_craftingStation = val;
		}

		private static void ApplyCategory(BuildPiece jbuildpiece)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Piece scenePiece = jbuildpiece.Objs.ScenePiece;
			if (!((Object)(object)scenePiece == (Object)null))
			{
				PieceCategory? val = PieceManager.Instance.GetPieceCategory(jbuildpiece.Cfgs.PieceCategory.Value);
				if (!val.HasValue)
				{
					val = PieceManager.Instance.AddPieceCategory(jbuildpiece.Cfgs.PieceCategory.Value);
				}
				scenePiece.m_category = val.Value;
			}
		}

		private static void ApplyRecipe(BuildPiece jbuildpiece)
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			Piece scenePiece = jbuildpiece.Objs.ScenePiece;
			if ((Object)(object)scenePiece == (Object)null)
			{
				return;
			}
			if (!jbuildpiece.Cfgs.Enabled.Value)
			{
				scenePiece.m_enabled = false;
				return;
			}
			List<RequirementConfig> list = new List<RequirementConfig>();
			if (ModContext.DebugEnabled)
			{
				ModLogger.LogInfo("Validating and building requirementsConfig");
			}
			foreach (PieceCost item in jbuildpiece.Cfgs.UpdatedCost)
			{
				if ((Object)(object)PrefabManager.Instance.GetPrefab(item.Prefab) == (Object)null)
				{
					if (ModContext.DebugEnabled)
					{
						ModLogger.LogInfo(item.Prefab + " is not a valid prefab, skipping recipe update.");
					}
					return;
				}
				if (ModContext.DebugEnabled)
				{
					ModLogger.LogInfo($"Checking entry {item.