Decompiled source of CustomItemRegistry v0.6.2

CustomItemRegistry.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("BreakoutMods")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.6.2.0")]
[assembly: AssemblyInformationalVersion("0.6.2")]
[assembly: AssemblyProduct("CustomItemRegistry")]
[assembly: AssemblyTitle("CustomItemRegistry")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/BreakoutMods/CIR-CustomItemRegistry")]
[assembly: AssemblyVersion("0.6.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimCustomItemRegistry
{
	public struct Ingredient
	{
		public string itemName;

		public int amount;

		public int amountPerLevel;

		public bool recover;

		internal string SourceModGuid;

		internal bool IsVanilla;

		internal string HelperValidationError;

		public Ingredient(string itemName, int amount, int amountPerLevel = 0, bool recover = true)
		{
			this.itemName = itemName;
			this.amount = amount;
			this.amountPerLevel = amountPerLevel;
			this.recover = recover;
			SourceModGuid = null;
			IsVanilla = false;
			HelperValidationError = null;
		}

		public static Ingredient From(VanillaItem item, int amount, int amountPerLevel = 0, bool recover = true)
		{
			return From(ItemRef.Vanilla(item), amount, amountPerLevel, recover);
		}

		public static Ingredient From(ItemRef item, int amount, int amountPerLevel = 0, bool recover = true)
		{
			Ingredient result = new Ingredient(item.PrefabName, amount, amountPerLevel, recover);
			result.SourceModGuid = item.SourceModGuid;
			result.IsVanilla = item.IsVanilla;
			result.HelperValidationError = item.ValidationError;
			return result;
		}
	}
	public struct CraftingRecipe
	{
		public List<Ingredient> ingredients;

		public string craftingStation;

		public string repairStation;

		public int amount;

		public int minStationLevel;

		public bool? enabled;

		public bool requireOnlyOneIngredient;

		public int qualityResultAmountMultiplier;

		internal string CraftingStationValidationError;

		internal string RepairStationValidationError;

		public CraftingRecipe(List<Ingredient> ingredients, string craftingStation, int amount = 1, string repairStation = null, int minStationLevel = 1, bool enabled = true, bool requireOnlyOneIngredient = false, int qualityResultAmountMultiplier = 1)
		{
			this.ingredients = ingredients;
			this.craftingStation = craftingStation;
			this.repairStation = repairStation;
			this.amount = amount;
			this.minStationLevel = minStationLevel;
			this.enabled = enabled;
			this.requireOnlyOneIngredient = requireOnlyOneIngredient;
			this.qualityResultAmountMultiplier = qualityResultAmountMultiplier;
			CraftingStationValidationError = null;
			RepairStationValidationError = null;
		}
	}
	public sealed class CustomItemDefinition
	{
		public DamageTypes Damages;

		public DamageTypes DamagesPerLevel;

		public string ItemName { get; set; }

		public string AssetBundlePath { get; set; }

		public AssetBundle AssetBundle { get; set; }

		public string PrefabName { get; set; }

		public string DisplayName { get; set; }

		public string Description { get; set; }

		public string IconAssetName { get; set; }

		public Sprite Icon { get; set; }

		public PrefabPreparationOptions PrefabPreparation { get; set; }

		public CraftingRecipe Recipe { get; set; }

		public bool HasRecipe { get; set; }

		public ItemType? ItemType { get; set; }

		public float? Weight { get; set; }

		public int? StackSize { get; set; }

		public float? MaxDurability { get; set; }

		public float? DurabilityPerLevel { get; set; }

		public int? MaxQuality { get; set; }

		public int? ToolTier { get; set; }

		public float? Armor { get; set; }

		public float? ArmorPerLevel { get; set; }

		public float? BlockPower { get; set; }

		public float? BlockPowerPerLevel { get; set; }

		public float? DeflectionForce { get; set; }

		public float? DeflectionForcePerLevel { get; set; }

		public float? MovementModifier { get; set; }

		public bool? Teleportable { get; set; }

		public bool? CanBeRepaired { get; set; }

		public bool HasDamages { get; set; }

		public bool HasDamagesPerLevel { get; set; }

		public IList<Action<SharedData>> SharedDataConfigurators { get; private set; }

		internal string TemplateName { get; set; }

		internal bool TemplateRequiresDamage { get; set; }

		internal bool TemplateRequiresBlockPower { get; set; }

		internal bool TemplateRequiresArmor { get; set; }

		internal bool TemplateRequiresFoodStats { get; set; }

		internal bool TemplateHasFoodStats { get; set; }

		public CustomItemDefinition()
		{
			SharedDataConfigurators = new List<Action<SharedData>>();
			PrefabPreparation = new PrefabPreparationOptions();
		}

		public CustomItemDefinition(string itemName)
			: this()
		{
			ItemName = itemName;
		}
	}
	public sealed class CustomItemRegistrationException : Exception
	{
		public string ItemName { get; private set; }

		public string AssetBundlePath { get; private set; }

		public string PrefabName { get; private set; }

		public CustomItemRegistrationException(string message)
			: base(message)
		{
		}

		public CustomItemRegistrationException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		internal CustomItemRegistrationException(CustomItemDefinition definition, string message)
			: base(BuildMessage(definition, message))
		{
			Capture(definition);
		}

		internal CustomItemRegistrationException(CustomItemDefinition definition, string message, Exception innerException)
			: base(BuildMessage(definition, message), innerException)
		{
			Capture(definition);
		}

		private void Capture(CustomItemDefinition definition)
		{
			if (definition != null)
			{
				ItemName = definition.ItemName;
				AssetBundlePath = definition.AssetBundlePath;
				PrefabName = definition.PrefabName;
			}
		}

		private static string BuildMessage(CustomItemDefinition definition, string message)
		{
			if (definition == null)
			{
				return message;
			}
			string text = definition.AssetBundlePath ?? (Object.op_Implicit((Object)(object)definition.AssetBundle) ? ((Object)definition.AssetBundle).name : "<null>");
			return "Item '" + (definition.ItemName ?? "<null>") + "' from bundle '" + text + "' prefab '" + (definition.PrefabName ?? "<null>") + "': " + message;
		}
	}
	public static class CustomItemRegistry
	{
		private sealed class RegisteredItem
		{
			public readonly string ItemName;

			public readonly GameObject Prefab;

			public readonly CustomItem CustomItem;

			public RegisteredItem(string itemName, GameObject prefab, CustomItem customItem)
			{
				ItemName = itemName;
				Prefab = prefab;
				CustomItem = customItem;
			}
		}

		private sealed class PrefabPreparationReport
		{
			public readonly List<string> AddedComponents = new List<string>();

			public readonly List<string> Warnings = new List<string>();

			public bool CreatedItemDrop;
		}

		private static readonly Dictionary<string, RegisteredItem> RegisteredItems = new Dictionary<string, RegisteredItem>();

		private static readonly Dictionary<string, AssetBundle> LoadedAssetBundles = new Dictionary<string, AssetBundle>();

		private static ManualLogSource logger;

		public static CustomItemBuilder Item(string itemName)
		{
			return new CustomItemBuilder(itemName);
		}

		public static void RegisterItem(string itemName, string assetBundlePath, string prefabName, CraftingRecipe recipe)
		{
			if (RegisteredItems.ContainsKey(itemName))
			{
				LogWarning("Item '" + itemName + "' is already registered");
				return;
			}
			RegisterItem(new CustomItemDefinition(itemName)
			{
				AssetBundlePath = assetBundlePath,
				PrefabName = prefabName,
				Recipe = recipe,
				HasRecipe = true
			});
		}

		public static ItemRegistrationResult RegisterItem(CustomItemDefinition definition)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			GameObject val = null;
			try
			{
				ValidateDefinition(definition);
				AssetBundle assetBundle = GetAssetBundle(definition);
				GameObject val2 = assetBundle.LoadAsset<GameObject>(definition.PrefabName);
				if (!Object.op_Implicit((Object)(object)val2))
				{
					throw new CustomItemRegistrationException(definition, CreateMissingAssetMessage(definition, assetBundle, definition.PrefabName, "prefab"));
				}
				ItemDrop component = val2.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null)
				{
					bool flag = component.m_itemData == null;
					if (flag)
					{
						component.m_itemData = new ItemData();
					}
					bool flag2 = component.m_itemData.m_shared == null;
					if (flag2)
					{
						component.m_itemData.m_shared = new SharedData();
					}
					if (flag || flag2)
					{
						string text = (flag ? "m_itemData and m_itemData.m_shared" : "m_itemData.m_shared");
						LogWarning("Prefab '" + definition.PrefabName + "' for item '" + definition.ItemName + "' has an ItemDrop component with uninitialized " + text + ". CIR initialized them to prevent a crash in ItemDrop.Awake(). Set up the ItemDrop component in Unity to remove this warning.");
					}
				}
				val = Object.Instantiate<GameObject>(val2);
				((Object)val).name = definition.ItemName;
				val.SetActive(false);
				PrefabPreparationReport preparationReport = PrepareItemPrefab(definition, val);
				string iconSource = LoadIcon(definition, assetBundle);
				ItemConfig val3 = CreateItemConfig(definition);
				CustomItem val4 = new CustomItem(val, true, val3);
				ApplyGearMetadata(definition, val);
				ApplySharedDataConfigurators(definition, val);
				ValidatePreparedItem(definition, val, val4);
				WarnForMissingIngredients(definition);
				if (!ItemManager.Instance.AddItem(val4))
				{
					throw new CustomItemRegistrationException(definition, "Jotunn rejected the custom item");
				}
				RegisteredItems.Add(definition.ItemName, new RegisteredItem(definition.ItemName, val, val4));
				FlushLiveRegistrations();
				ItemRegistrationResult result = ItemRegistrationResult.Registered(definition, val, val4);
				LogRegistrationSuccess(definition, val, iconSource, preparationReport);
				return result;
			}
			catch (Exception ex)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
				CustomItemRegistrationException obj = ((ex is CustomItemRegistrationException ex2 && !string.IsNullOrEmpty(ex2.ItemName)) ? ex2 : new CustomItemRegistrationException(definition, ex.Message, ex));
				LogWarning(obj.Message);
				throw obj;
			}
		}

		public static bool TryRegisterItem(CustomItemDefinition definition, out ItemRegistrationResult result)
		{
			try
			{
				result = RegisterItem(definition);
				return true;
			}
			catch (Exception exception)
			{
				result = ItemRegistrationResult.Failed(definition, exception);
				return false;
			}
		}

		public static IReadOnlyList<ItemRegistrationResult> RegisterItems(IEnumerable<CustomItemDefinition> definitions)
		{
			if (definitions == null)
			{
				throw new ArgumentNullException("definitions");
			}
			List<ItemRegistrationResult> list = new List<ItemRegistrationResult>();
			foreach (CustomItemDefinition definition in definitions)
			{
				list.Add(RegisterItem(definition));
			}
			return list;
		}

		public static ItemPackLoadResult LoadItemPacks()
		{
			return ItemPackLoader.LoadDefault(null);
		}

		public static ItemPackLoadResult LoadItemPacksFromDirectory(string directory, ItemPackLoadOptions options = null)
		{
			return ItemPackLoader.LoadDirectory(directory, options);
		}

		public static ItemPackLoadResult LoadItemPack(string filePath, ItemPackLoadOptions options = null)
		{
			return ItemPackLoader.LoadFile(filePath, options);
		}

		public static ItemPackParserStatus GetItemPackParserStatus()
		{
			return ItemPackLoader.GetParserStatus();
		}

		internal static void SetLogger(ManualLogSource manualLogSource)
		{
			logger = manualLogSource;
		}

		internal static void FlushLiveRegistrations(ObjectDB objectDB = null, ZNetScene zNetScene = null)
		{
			if (RegisteredItems.Count == 0)
			{
				return;
			}
			ObjectDB val = (Object.op_Implicit((Object)(object)objectDB) ? objectDB : ObjectDB.instance);
			ZNetScene val2 = (Object.op_Implicit((Object)(object)zNetScene) ? zNetScene : ZNetScene.instance);
			foreach (RegisteredItem value in RegisteredItems.Values)
			{
				if (Object.op_Implicit((Object)(object)val2))
				{
					PrefabManager.Instance.RegisterToZNetScene(value.Prefab);
				}
				if (Object.op_Implicit((Object)(object)val))
				{
					RegisterPrefabInObjectDB(value);
					RegisterRecipeInObjectDB(val, value);
				}
			}
		}

		internal static bool PrepareItemPrefabForTest(CustomItemDefinition definition, GameObject itemPrefab, out IReadOnlyList<string> addedComponents, out IReadOnlyList<string> warnings, out string error)
		{
			addedComponents = Array.Empty<string>();
			warnings = Array.Empty<string>();
			error = null;
			try
			{
				PrefabPreparationReport prefabPreparationReport = PrepareItemPrefab(definition, itemPrefab);
				addedComponents = prefabPreparationReport.AddedComponents;
				warnings = prefabPreparationReport.Warnings;
				return true;
			}
			catch (Exception ex)
			{
				error = ex.Message;
				return false;
			}
		}

		internal static void UnloadAssetBundles()
		{
			foreach (AssetBundle value in LoadedAssetBundles.Values)
			{
				if (Object.op_Implicit((Object)(object)value))
				{
					value.Unload(false);
				}
			}
			LoadedAssetBundles.Clear();
		}

		private static void ValidateDefinition(CustomItemDefinition definition)
		{
			if (definition == null)
			{
				throw new CustomItemRegistrationException("Custom item definition is required");
			}
			if (string.IsNullOrWhiteSpace(definition.ItemName))
			{
				throw new CustomItemRegistrationException(definition, "Item name is required");
			}
			if (!Object.op_Implicit((Object)(object)definition.AssetBundle) && string.IsNullOrWhiteSpace(definition.AssetBundlePath))
			{
				throw new CustomItemRegistrationException(definition, "AssetBundle path is required");
			}
			if (string.IsNullOrWhiteSpace(definition.PrefabName))
			{
				throw new CustomItemRegistrationException(definition, "Prefab name is required");
			}
			if (RegisteredItems.ContainsKey(definition.ItemName))
			{
				throw new CustomItemRegistrationException(definition, "Item name is already registered");
			}
			ValidateRecipe(definition);
			ValidateGear(definition);
		}

		private static void ValidateRecipe(CustomItemDefinition definition)
		{
			if (!definition.HasRecipe)
			{
				return;
			}
			CraftingRecipe recipe = definition.Recipe;
			if (!string.IsNullOrEmpty(recipe.CraftingStationValidationError))
			{
				throw new CustomItemRegistrationException(definition, recipe.CraftingStationValidationError);
			}
			if (!string.IsNullOrEmpty(recipe.RepairStationValidationError))
			{
				throw new CustomItemRegistrationException(definition, recipe.RepairStationValidationError);
			}
			if (recipe.amount <= 0)
			{
				throw new CustomItemRegistrationException(definition, "Recipe amount must be greater than zero");
			}
			if (recipe.minStationLevel < 0)
			{
				throw new CustomItemRegistrationException(definition, "Recipe minimum station level cannot be negative");
			}
			if (recipe.qualityResultAmountMultiplier < 0)
			{
				throw new CustomItemRegistrationException(definition, "Recipe quality result amount multiplier cannot be negative");
			}
			if (recipe.ingredients == null)
			{
				return;
			}
			foreach (Ingredient ingredient in recipe.ingredients)
			{
				if (!string.IsNullOrEmpty(ingredient.HelperValidationError))
				{
					throw new CustomItemRegistrationException(definition, ingredient.HelperValidationError);
				}
				if (string.IsNullOrWhiteSpace(ingredient.itemName))
				{
					throw new CustomItemRegistrationException(definition, "Recipe contains an ingredient with an empty item name");
				}
				if (ingredient.amount < 0)
				{
					throw new CustomItemRegistrationException(definition, "Recipe ingredient '" + ingredient.itemName + "' amount cannot be negative");
				}
				if (ingredient.amountPerLevel < 0)
				{
					throw new CustomItemRegistrationException(definition, "Recipe ingredient '" + ingredient.itemName + "' amount per level cannot be negative");
				}
				if (ingredient.amount == 0 && ingredient.amountPerLevel == 0)
				{
					throw new CustomItemRegistrationException(definition, "Recipe ingredient '" + ingredient.itemName + "' must have a craft amount or upgrade amount per level");
				}
			}
		}

		private static void ValidateGear(CustomItemDefinition definition)
		{
			if (definition.Weight.HasValue && definition.Weight.Value < 0f)
			{
				throw new CustomItemRegistrationException(definition, "Weight cannot be negative");
			}
			if (definition.StackSize.HasValue && definition.StackSize.Value < 1)
			{
				throw new CustomItemRegistrationException(definition, "Stack size must be greater than zero");
			}
			if (definition.MaxDurability.HasValue && definition.MaxDurability.Value < 0f)
			{
				throw new CustomItemRegistrationException(definition, "Durability cannot be negative");
			}
			if (definition.MaxQuality.HasValue && definition.MaxQuality.Value < 1)
			{
				throw new CustomItemRegistrationException(definition, "Max quality must be greater than zero");
			}
			ValidateTemplate(definition);
		}

		private static void ValidateTemplate(CustomItemDefinition definition)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(definition.TemplateName))
			{
				string text = "Template '" + definition.TemplateName + "'";
				if (definition.TemplateRequiresDamage && !HasAnyDamage(definition.Damages) && !HasAnyDamage(definition.DamagesPerLevel))
				{
					throw new CustomItemRegistrationException(definition, text + " requires at least one damage value");
				}
				if (definition.TemplateRequiresBlockPower && (!definition.BlockPower.HasValue || definition.BlockPower.Value <= 0f))
				{
					throw new CustomItemRegistrationException(definition, text + " requires block power");
				}
				if (definition.TemplateRequiresArmor && (!definition.Armor.HasValue || definition.Armor.Value <= 0f))
				{
					throw new CustomItemRegistrationException(definition, text + " requires armor value");
				}
				if (definition.TemplateRequiresFoodStats && !definition.TemplateHasFoodStats)
				{
					throw new CustomItemRegistrationException(definition, text + " requires health, stamina, or eitr food stats");
				}
			}
		}

		private static bool HasAnyDamage(DamageTypes damages)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!(damages.m_damage > 0f) && !(damages.m_blunt > 0f) && !(damages.m_slash > 0f) && !(damages.m_pierce > 0f) && !(damages.m_chop > 0f) && !(damages.m_pickaxe > 0f) && !(damages.m_fire > 0f) && !(damages.m_frost > 0f) && !(damages.m_lightning > 0f) && !(damages.m_poison > 0f))
			{
				return damages.m_spirit > 0f;
			}
			return true;
		}

		private static AssetBundle LoadAssetBundle(string assetBundlePath)
		{
			string text = ResolveAssetBundlePath(assetBundlePath);
			if (!File.Exists(text))
			{
				throw new FileNotFoundException("AssetBundle not found at '" + text + "'", text);
			}
			if (LoadedAssetBundles.TryGetValue(text, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			AssetBundle val = AssetBundle.LoadFromFile(text);
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Failed to load AssetBundle '" + text + "'");
			}
			LoadedAssetBundles[text] = val;
			LogInfo("Loaded AssetBundle '" + text + "'");
			return val;
		}

		private static AssetBundle GetAssetBundle(CustomItemDefinition definition)
		{
			if (Object.op_Implicit((Object)(object)definition.AssetBundle))
			{
				return definition.AssetBundle;
			}
			return LoadAssetBundle(definition.AssetBundlePath);
		}

		private static string ResolveAssetBundlePath(string assetBundlePath)
		{
			if (Path.IsPathRooted(assetBundlePath))
			{
				return Path.GetFullPath(assetBundlePath);
			}
			string path = Path.Combine(Paths.PluginPath, assetBundlePath);
			if (File.Exists(path))
			{
				return Path.GetFullPath(path);
			}
			return Path.GetFullPath(assetBundlePath);
		}

		private static PrefabPreparationReport PrepareItemPrefab(CustomItemDefinition definition, GameObject itemPrefab)
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Expected O, but got Unknown
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			PrefabPreparationOptions prefabPreparationOptions = definition.PrefabPreparation ?? new PrefabPreparationOptions();
			PrefabPreparationReport prefabPreparationReport = new PrefabPreparationReport();
			List<string> list = new List<string>();
			ItemDrop val = itemPrefab.GetComponent<ItemDrop>();
			if (!Object.op_Implicit((Object)(object)val))
			{
				if (prefabPreparationOptions.RequireExistingItemDrop || !prefabPreparationOptions.AutoAddItemDrop)
				{
					list.Add("ItemDrop");
				}
				else
				{
					val = itemPrefab.AddComponent<ItemDrop>();
					prefabPreparationReport.AddedComponents.Add("ItemDrop");
					prefabPreparationReport.CreatedItemDrop = true;
				}
			}
			Rigidbody component = itemPrefab.GetComponent<Rigidbody>();
			ZNetView val2 = itemPrefab.GetComponent<ZNetView>();
			ZSyncTransform component2 = itemPrefab.GetComponent<ZSyncTransform>();
			bool flag = itemPrefab.GetComponentsInChildren<Collider>(true).Length != 0;
			if (!prefabPreparationOptions.AutoAddPhysics)
			{
				if (!Object.op_Implicit((Object)(object)component))
				{
					list.Add("Rigidbody");
				}
				if (!Object.op_Implicit((Object)(object)val2))
				{
					list.Add("ZNetView");
				}
				if (!Object.op_Implicit((Object)(object)component2))
				{
					list.Add("ZSyncTransform");
				}
			}
			if (!flag && !prefabPreparationOptions.WarnOnMissingCollider)
			{
				list.Add("Collider");
			}
			if (list.Count > 0)
			{
				throw new CustomItemRegistrationException(definition, "Prefab '" + definition.PrefabName + "' is missing required components: " + string.Join(", ", list.ToArray()) + ". Add them in Unity, or opt into CIR auto-preparation with .PrefabPreparation(prep => prep.AutoAddItemDrop().AutoAddPhysics().WarnOnMissingCollider().AllowTextureIconFallback()).");
			}
			if (val.m_itemData == null)
			{
				val.m_itemData = new ItemData();
			}
			if (val.m_itemData.m_shared == null)
			{
				val.m_itemData.m_shared = new SharedData();
			}
			if (string.IsNullOrEmpty(val.m_itemData.m_shared.m_name))
			{
				val.m_itemData.m_shared.m_name = ((!string.IsNullOrWhiteSpace(definition.DisplayName)) ? definition.DisplayName : ("$" + definition.ItemName.ToLowerInvariant()));
			}
			if (string.IsNullOrEmpty(val.m_itemData.m_shared.m_description) && !string.IsNullOrWhiteSpace(definition.Description))
			{
				val.m_itemData.m_shared.m_description = definition.Description;
			}
			if (prefabPreparationReport.CreatedItemDrop)
			{
				if (!definition.ItemType.HasValue)
				{
					val.m_itemData.m_shared.m_itemType = (ItemType)1;
				}
				if (val.m_itemData.m_shared.m_maxStackSize < 1)
				{
					val.m_itemData.m_shared.m_maxStackSize = 1;
				}
				if (val.m_itemData.m_shared.m_weight <= 0f)
				{
					val.m_itemData.m_shared.m_weight = 1f;
				}
				val.m_itemData.m_shared.m_teleportable = true;
			}
			val.m_itemData.m_dropPrefab = itemPrefab;
			if (prefabPreparationOptions.AutoAddPhysics)
			{
				if (!Object.op_Implicit((Object)(object)component))
				{
					component = itemPrefab.AddComponent<Rigidbody>();
					prefabPreparationReport.AddedComponents.Add("Rigidbody");
				}
				if (!Object.op_Implicit((Object)(object)val2))
				{
					val2 = itemPrefab.AddComponent<ZNetView>();
					prefabPreparationReport.AddedComponents.Add("ZNetView");
				}
				val2.m_persistent = true;
				if (!Object.op_Implicit((Object)(object)component2))
				{
					component2 = itemPrefab.AddComponent<ZSyncTransform>();
					prefabPreparationReport.AddedComponents.Add("ZSyncTransform");
				}
			}
			else if (Object.op_Implicit((Object)(object)val2))
			{
				val2.m_persistent = true;
			}
			if (prefabPreparationOptions.WarnOnMissingCollider && !flag)
			{
				string text = "Item '" + definition.ItemName + "' prefab '" + definition.PrefabName + "' has no Collider. CIR will not add a guessed collider; add one in Unity for reliable pickup/drop physics.";
				prefabPreparationReport.Warnings.Add(text);
				LogWarning(text);
			}
			return prefabPreparationReport;
		}

		private static string LoadIcon(CustomItemDefinition definition, AssetBundle assetBundle)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)definition.Icon))
			{
				return "direct Sprite";
			}
			if (string.IsNullOrWhiteSpace(definition.IconAssetName))
			{
				return "prefab/shared data";
			}
			Sprite val = assetBundle.LoadAsset<Sprite>(definition.IconAssetName);
			if (Object.op_Implicit((Object)(object)val))
			{
				definition.Icon = val;
				return "Sprite '" + definition.IconAssetName + "'";
			}
			PrefabPreparationOptions prefabPreparationOptions = definition.PrefabPreparation ?? new PrefabPreparationOptions();
			if (prefabPreparationOptions.AllowTextureIconFallback)
			{
				Texture2D val2 = assetBundle.LoadAsset<Texture2D>(definition.IconAssetName);
				if (Object.op_Implicit((Object)(object)val2))
				{
					definition.Icon = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f));
					((Object)definition.Icon).name = definition.IconAssetName;
					return "Texture2D '" + definition.IconAssetName + "' converted to Sprite";
				}
			}
			throw new CustomItemRegistrationException(definition, CreateMissingAssetMessage(definition, assetBundle, definition.IconAssetName, prefabPreparationOptions.AllowTextureIconFallback ? "icon Sprite or Texture2D" : "icon Sprite"));
		}

		private static ItemConfig CreateItemConfig(CustomItemDefinition definition)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			CraftingRecipe recipe = definition.Recipe;
			List<Ingredient> source = ((definition.HasRecipe && recipe.ingredients != null) ? recipe.ingredients : new List<Ingredient>());
			return new ItemConfig
			{
				Name = definition.DisplayName,
				Description = definition.Description,
				Icon = definition.Icon,
				Amount = ((!definition.HasRecipe) ? 1 : recipe.amount),
				Enabled = (!definition.HasRecipe || recipe.enabled.GetValueOrDefault(true)),
				CraftingStation = (definition.HasRecipe ? recipe.craftingStation : null),
				RepairStation = (definition.HasRecipe ? recipe.repairStation : null),
				MinStationLevel = ((!definition.HasRecipe || recipe.minStationLevel <= 0) ? 1 : recipe.minStationLevel),
				RequireOnlyOneIngredient = (definition.HasRecipe && recipe.requireOnlyOneIngredient),
				QualityResultAmountMultiplier = ((!definition.HasRecipe || recipe.qualityResultAmountMultiplier <= 0) ? 1 : recipe.qualityResultAmountMultiplier),
				Weight = definition.Weight.GetValueOrDefault(-1f),
				StackSize = definition.StackSize.GetValueOrDefault(-1),
				Requirements = ((IEnumerable<Ingredient>)source).Select((Func<Ingredient, RequirementConfig>)((Ingredient ingredient) => new RequirementConfig(ingredient.itemName, ingredient.amount, ingredient.amountPerLevel, ingredient.recover))).ToArray()
			};
		}

		private static void ApplyGearMetadata(CustomItemDefinition definition, GameObject itemPrefab)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: 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)
			SharedData shared = itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared;
			if (definition.ItemType.HasValue)
			{
				shared.m_itemType = definition.ItemType.Value;
			}
			if (definition.Weight.HasValue)
			{
				shared.m_weight = definition.Weight.Value;
			}
			if (definition.StackSize.HasValue)
			{
				shared.m_maxStackSize = definition.StackSize.Value;
			}
			if (definition.MaxDurability.HasValue)
			{
				shared.m_maxDurability = definition.MaxDurability.Value;
				shared.m_useDurability = definition.MaxDurability.Value > 0f;
			}
			if (definition.DurabilityPerLevel.HasValue)
			{
				shared.m_durabilityPerLevel = definition.DurabilityPerLevel.Value;
			}
			if (definition.MaxQuality.HasValue)
			{
				shared.m_maxQuality = definition.MaxQuality.Value;
			}
			if (definition.ToolTier.HasValue)
			{
				shared.m_toolTier = definition.ToolTier.Value;
			}
			if (definition.Armor.HasValue)
			{
				shared.m_armor = definition.Armor.Value;
			}
			if (definition.ArmorPerLevel.HasValue)
			{
				shared.m_armorPerLevel = definition.ArmorPerLevel.Value;
			}
			if (definition.BlockPower.HasValue)
			{
				shared.m_blockPower = definition.BlockPower.Value;
			}
			if (definition.BlockPowerPerLevel.HasValue)
			{
				shared.m_blockPowerPerLevel = definition.BlockPowerPerLevel.Value;
			}
			if (definition.DeflectionForce.HasValue)
			{
				shared.m_deflectionForce = definition.DeflectionForce.Value;
			}
			if (definition.DeflectionForcePerLevel.HasValue)
			{
				shared.m_deflectionForcePerLevel = definition.DeflectionForcePerLevel.Value;
			}
			if (definition.MovementModifier.HasValue)
			{
				shared.m_movementModifier = definition.MovementModifier.Value;
			}
			if (definition.Teleportable.HasValue)
			{
				shared.m_teleportable = definition.Teleportable.Value;
			}
			if (definition.CanBeRepaired.HasValue)
			{
				shared.m_canBeReparied = definition.CanBeRepaired.Value;
			}
			if (definition.HasDamages)
			{
				shared.m_damages = definition.Damages;
			}
			if (definition.HasDamagesPerLevel)
			{
				shared.m_damagesPerLevel = definition.DamagesPerLevel;
			}
		}

		private static void ApplySharedDataConfigurators(CustomItemDefinition definition, GameObject itemPrefab)
		{
			if (definition.SharedDataConfigurators.Count == 0)
			{
				return;
			}
			SharedData shared = itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared;
			foreach (Action<SharedData> sharedDataConfigurator in definition.SharedDataConfigurators)
			{
				sharedDataConfigurator(shared);
			}
		}

		private static void ValidatePreparedItem(CustomItemDefinition definition, GameObject itemPrefab, CustomItem customItem)
		{
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				throw new CustomItemRegistrationException(definition, "Prepared prefab is missing ItemDrop");
			}
			if (CreatesRecipe(definition))
			{
				Sprite[] array = component.m_itemData?.m_shared?.m_icons;
				if (array == null || array.Length == 0 || !Object.op_Implicit((Object)(object)array[0]))
				{
					throw new CustomItemRegistrationException(definition, "Craftable items must have an icon; set it in the prefab or call .Icon(...)");
				}
			}
			if (customItem == null || (Object)(object)customItem.ItemPrefab == (Object)null)
			{
				throw new CustomItemRegistrationException(definition, "Jotunn custom item wrapper was not created");
			}
			if ((definition.PrefabPreparation ?? new PrefabPreparationOptions()).ValidateWearableVisuals)
			{
				ValidateWearableVisuals(definition, itemPrefab, component.m_itemData?.m_shared);
			}
		}

		private static void ValidateWearableVisuals(CustomItemDefinition definition, GameObject itemPrefab, SharedData shared)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			if (shared == null || !IsWearableArmor(shared.m_itemType))
			{
				return;
			}
			SkinnedMeshRenderer[] componentsInChildren = itemPrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				throw new CustomItemRegistrationException(definition, $"Wearable item prefab '{definition.PrefabName}' is type '{shared.m_itemType}' but has no SkinnedMeshRenderer. Valheim wearable armor needs a skinned visual setup; a normal static mesh can register as a material, but will fail or crash when equipped in SetupVisEquipment.");
			}
			SkinnedMeshRenderer[] array = componentsInChildren;
			foreach (SkinnedMeshRenderer val in array)
			{
				string transformPath = GetTransformPath(((Component)val).transform, itemPrefab.transform);
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					throw new CustomItemRegistrationException(definition, "Wearable item prefab '" + definition.PrefabName + "' has SkinnedMeshRenderer '" + transformPath + "' without a mesh.");
				}
				if ((Object)(object)val.rootBone == (Object)null)
				{
					throw new CustomItemRegistrationException(definition, "Wearable item prefab '" + definition.PrefabName + "' has SkinnedMeshRenderer '" + transformPath + "' without rootBone.");
				}
				if (val.bones == null || val.bones.Length == 0)
				{
					throw new CustomItemRegistrationException(definition, "Wearable item prefab '" + definition.PrefabName + "' has SkinnedMeshRenderer '" + transformPath + "' without bones.");
				}
				if (val.bones.Any((Transform bone) => (Object)(object)bone == (Object)null))
				{
					throw new CustomItemRegistrationException(definition, "Wearable item prefab '" + definition.PrefabName + "' has SkinnedMeshRenderer '" + transformPath + "' with one or more missing bone references.");
				}
				Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0 || sharedMaterials.Any((Material material) => (Object)(object)material == (Object)null))
				{
					LogWarning("Wearable item '" + definition.ItemName + "' prefab '" + definition.PrefabName + "' renderer '" + transformPath + "' has missing material references. The item may equip but render incorrectly.");
				}
			}
			if (RequiresAttachSkinHint(shared.m_itemType) && !HasAttachSkinChild(itemPrefab))
			{
				LogWarning("Wearable item '" + definition.ItemName + "' prefab '" + definition.PrefabName + "' has skinned renderers but no 'attach_skin...' child. If the item crashes or appears wrong when equipped, base the hierarchy on a vanilla armor prefab and consider Jotunn BoneReorder.ApplyOnEquipmentChanged() for imported armor meshes.");
			}
		}

		private static bool IsWearableArmor(ItemType itemType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if ((int)itemType != 7 && (int)itemType != 11 && (int)itemType != 6)
			{
				return (int)itemType == 17;
			}
			return true;
		}

		private static bool RequiresAttachSkinHint(ItemType itemType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if ((int)itemType != 7 && (int)itemType != 11)
			{
				return (int)itemType == 17;
			}
			return true;
		}

		private static bool HasAttachSkinChild(GameObject itemPrefab)
		{
			return itemPrefab.GetComponentsInChildren<Transform>(true).Any((Transform child) => ((Object)child).name.StartsWith("attach_skin", StringComparison.OrdinalIgnoreCase));
		}

		private static string GetTransformPath(Transform transform, Transform root)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "<missing transform>";
			}
			Stack<string> stack = new Stack<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				stack.Push(((Object)val).name);
				if ((Object)(object)val == (Object)(object)root)
				{
					break;
				}
				val = val.parent;
			}
			return string.Join("/", stack.ToArray());
		}

		private static bool CreatesRecipe(CustomItemDefinition definition)
		{
			if (definition.HasRecipe && definition.Recipe.ingredients != null)
			{
				return definition.Recipe.ingredients.Count > 0;
			}
			return false;
		}

		private static void WarnForMissingIngredients(CustomItemDefinition definition)
		{
			if (!CreatesRecipe(definition) || (!Object.op_Implicit((Object)(object)ObjectDB.instance) && !Object.op_Implicit((Object)(object)ZNetScene.instance)))
			{
				return;
			}
			foreach (Ingredient ingredient in definition.Recipe.ingredients)
			{
				if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab(ingredient.itemName)))
				{
					if (!string.IsNullOrWhiteSpace(ingredient.SourceModGuid))
					{
						LogWarning($"Item '{definition.ItemName}' recipe ingredient '{ingredient.itemName}' from mod '{ingredient.SourceModGuid}' was not found in loaded prefab databases (amount {ingredient.amount}, amount per level {ingredient.amountPerLevel}). Jotunn may still resolve it later if that mod registers it.");
					}
					else
					{
						LogWarning("Item '" + definition.ItemName + "' recipe ingredient '" + ingredient.itemName + "' was not found in loaded prefab databases. Jotunn may still resolve it later if another mod registers it.");
					}
				}
			}
		}

		private static void RegisterPrefabInObjectDB(RegisteredItem item)
		{
			if (Object.op_Implicit((Object)(object)ObjectDB.instance) && Object.op_Implicit((Object)(object)item.Prefab))
			{
				ItemManager.Instance.RegisterItemInObjectDB(item.Prefab);
			}
		}

		private static void RegisterRecipeInObjectDB(ObjectDB objectDB, RegisteredItem item)
		{
			CustomRecipe recipe2 = item.CustomItem.Recipe;
			Recipe recipe = ((recipe2 != null) ? recipe2.Recipe : null);
			if (Object.op_Implicit((Object)(object)objectDB) && Object.op_Implicit((Object)(object)recipe) && !objectDB.m_recipes.Any((Recipe existing) => Object.op_Implicit((Object)(object)existing) && ((Object)existing).name == ((Object)recipe).name))
			{
				if (recipe2.FixReference || recipe2.FixRequirementReferences)
				{
					PrefabExtension.FixReferences((object)recipe);
					recipe2.FixReference = false;
					recipe2.FixRequirementReferences = false;
				}
				objectDB.m_recipes.Add(recipe);
				LogInfo("Added recipe '" + ((Object)recipe).name + "' to ObjectDB");
			}
		}

		private static string CreateMissingAssetMessage(CustomItemDefinition definition, AssetBundle assetBundle, string assetName, string assetKind)
		{
			string text = CreateAssetCandidateMessage(assetBundle, assetName);
			return "AssetBundle '" + GetBundleLabel(definition) + "' does not contain " + assetKind + " '" + assetName + "' for item '" + definition.ItemName + "' prefab '" + definition.PrefabName + "'. Asset names are case-sensitive." + text;
		}

		private static string CreateAssetCandidateMessage(AssetBundle assetBundle, string assetName)
		{
			string[] assetNames = GetAssetNames(assetBundle);
			if (assetNames.Length == 0)
			{
				return string.Empty;
			}
			string normalizedNeedle = assetName ?? string.Empty;
			List<string> list = (from name in (from name in assetNames.Select(PrettyAssetName)
					where !string.IsNullOrWhiteSpace(name)
					select name).Distinct<string>(StringComparer.OrdinalIgnoreCase)
				where name.IndexOf(normalizedNeedle, StringComparison.OrdinalIgnoreCase) >= 0 || normalizedNeedle.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0 || string.Equals(name, normalizedNeedle, StringComparison.OrdinalIgnoreCase)
				select name).Take(12).ToList();
			if (list.Count == 0)
			{
				list = (from name in assetNames.Select(PrettyAssetName)
					where !string.IsNullOrWhiteSpace(name)
					select name).Distinct<string>(StringComparer.OrdinalIgnoreCase).Take(12).ToList();
			}
			if (list.Count != 0)
			{
				return " Candidate assets include: " + string.Join(", ", list.ToArray()) + ".";
			}
			return string.Empty;
		}

		private static string[] GetAssetNames(AssetBundle assetBundle)
		{
			if (!Object.op_Implicit((Object)(object)assetBundle))
			{
				return Array.Empty<string>();
			}
			try
			{
				return assetBundle.GetAllAssetNames() ?? Array.Empty<string>();
			}
			catch (Exception ex)
			{
				LogWarning("Could not inspect AssetBundle asset names: " + ex.Message);
				return Array.Empty<string>();
			}
		}

		private static string PrettyAssetName(string assetPath)
		{
			if (string.IsNullOrWhiteSpace(assetPath))
			{
				return string.Empty;
			}
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(assetPath);
			if (!string.IsNullOrWhiteSpace(fileNameWithoutExtension))
			{
				return fileNameWithoutExtension;
			}
			return assetPath;
		}

		private static string GetBundleLabel(CustomItemDefinition definition)
		{
			if (!string.IsNullOrWhiteSpace(definition.AssetBundlePath))
			{
				return definition.AssetBundlePath;
			}
			if (!Object.op_Implicit((Object)(object)definition.AssetBundle))
			{
				return "<unknown>";
			}
			return ((Object)definition.AssetBundle).name;
		}

		private static void LogRegistrationSuccess(CustomItemDefinition definition, GameObject itemPrefab, string iconSource, PrefabPreparationReport preparationReport)
		{
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			string text = ((Object.op_Implicit((Object)(object)component) && component.m_itemData != null && component.m_itemData.m_shared != null) ? ((object)(ItemType)(ref component.m_itemData.m_shared.m_itemType)).ToString() : "unknown");
			string text2 = ((preparationReport.AddedComponents.Count == 0) ? "none" : string.Join(", ", preparationReport.AddedComponents.ToArray()));
			string text3 = ((!definition.HasRecipe) ? "none" : (string.IsNullOrWhiteSpace(definition.Recipe.craftingStation) ? "none" : definition.Recipe.craftingStation));
			LogInfo($"Registered custom item '{definition.ItemName}' from bundle '{GetBundleLabel(definition)}' prefab '{definition.PrefabName}'. Type={text}; icon={iconSource}; recipeStation={text3}; addedComponents={text2}; warnings={preparationReport.Warnings.Count}");
		}

		internal static void LogInfo(string message)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			ManualLogSource obj = logger;
			if (obj != null)
			{
				obj.LogWarning((object)message);
			}
		}
	}
	public sealed class ItemRegistrationResult
	{
		public bool Success { get; private set; }

		public string ItemName { get; private set; }

		public string AssetBundlePath { get; private set; }

		public string PrefabName { get; private set; }

		public GameObject Prefab { get; private set; }

		public CustomItem CustomItem { get; private set; }

		public Exception Exception { get; private set; }

		public string ErrorMessage => Exception?.Message;

		internal static ItemRegistrationResult Registered(CustomItemDefinition definition, GameObject prefab, CustomItem customItem)
		{
			return new ItemRegistrationResult
			{
				Success = true,
				ItemName = definition.ItemName,
				AssetBundlePath = definition.AssetBundlePath,
				PrefabName = definition.PrefabName,
				Prefab = prefab,
				CustomItem = customItem
			};
		}

		internal static ItemRegistrationResult Failed(CustomItemDefinition definition, Exception exception)
		{
			return new ItemRegistrationResult
			{
				Success = false,
				ItemName = definition?.ItemName,
				AssetBundlePath = definition?.AssetBundlePath,
				PrefabName = definition?.PrefabName,
				Exception = exception
			};
		}
	}
	public sealed class PrefabPreparationOptions
	{
		public bool RequireExistingItemDrop { get; set; }

		public bool AutoAddItemDrop { get; set; }

		public bool AutoAddPhysics { get; set; }

		public bool WarnOnMissingCollider { get; set; }

		public bool AllowTextureIconFallback { get; set; }

		public bool ValidateWearableVisuals { get; set; }

		public PrefabPreparationOptions()
		{
			RequireExistingItemDrop = true;
			AutoAddItemDrop = false;
			AutoAddPhysics = false;
			WarnOnMissingCollider = false;
			AllowTextureIconFallback = false;
			ValidateWearableVisuals = true;
		}
	}
	public sealed class CustomItemBuilder
	{
		private readonly CustomItemDefinition definition;

		internal CustomItemBuilder(string itemName)
		{
			definition = new CustomItemDefinition(itemName);
		}

		public CustomItemBuilder FromBundle(string assetBundlePath, string prefabName)
		{
			definition.AssetBundlePath = assetBundlePath;
			definition.AssetBundle = null;
			definition.PrefabName = prefabName;
			return this;
		}

		public CustomItemBuilder FromAssetBundle(AssetBundle assetBundle, string prefabName)
		{
			definition.AssetBundle = assetBundle;
			definition.AssetBundlePath = null;
			definition.PrefabName = prefabName;
			return this;
		}

		public CustomItemBuilder FromEmbeddedResource(string resourceName, Assembly assembly, string prefabName)
		{
			definition.AssetBundle = AssetUtils.LoadAssetBundleFromResources(resourceName, assembly);
			definition.AssetBundlePath = resourceName;
			definition.PrefabName = prefabName;
			return this;
		}

		public CustomItemBuilder DisplayName(string displayName)
		{
			definition.DisplayName = displayName;
			return this;
		}

		public CustomItemBuilder Description(string description)
		{
			definition.Description = description;
			return this;
		}

		public CustomItemBuilder Icon(string assetName)
		{
			definition.IconAssetName = assetName;
			return this;
		}

		public CustomItemBuilder Icon(Sprite sprite)
		{
			definition.Icon = sprite;
			return this;
		}

		public CustomItemBuilder PrefabPreparation(Action<PrefabPreparationBuilder> configure)
		{
			PrefabPreparationBuilder obj = new PrefabPreparationBuilder(definition.PrefabPreparation);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder Recipe(Action<RecipeBuilder> configure)
		{
			RecipeBuilder recipeBuilder = new RecipeBuilder();
			configure?.Invoke(recipeBuilder);
			definition.Recipe = recipeBuilder.Build();
			definition.HasRecipe = true;
			return this;
		}

		public CustomItemBuilder Gear(Action<GearBuilder> configure)
		{
			GearBuilder obj = new GearBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsSword(Action<WeaponTemplateBuilder> configure)
		{
			WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Sword", (ItemType)3);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsAxe(Action<WeaponTemplateBuilder> configure)
		{
			WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Axe", (ItemType)3);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsMace(Action<WeaponTemplateBuilder> configure)
		{
			WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Mace", (ItemType)3);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsSpear(Action<WeaponTemplateBuilder> configure)
		{
			WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Spear", (ItemType)3);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsKnife(Action<WeaponTemplateBuilder> configure)
		{
			WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Knife", (ItemType)3);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsAtgeir(Action<WeaponTemplateBuilder> configure)
		{
			WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Atgeir", (ItemType)14);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsBow(Action<BowTemplateBuilder> configure)
		{
			BowTemplateBuilder obj = new BowTemplateBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsArrow(Action<AmmoTemplateBuilder> configure)
		{
			AmmoTemplateBuilder obj = new AmmoTemplateBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsShield(Action<ShieldTemplateBuilder> configure)
		{
			ShieldTemplateBuilder obj = new ShieldTemplateBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsArmorChest(Action<ArmorTemplateBuilder> configure)
		{
			ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "ArmorChest", (ItemType)7);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsArmorLegs(Action<ArmorTemplateBuilder> configure)
		{
			ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "ArmorLegs", (ItemType)11);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsHelmet(Action<ArmorTemplateBuilder> configure)
		{
			ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "Helmet", (ItemType)6);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsCape(Action<ArmorTemplateBuilder> configure)
		{
			ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "Cape", (ItemType)17);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsTool(Action<ToolTemplateBuilder> configure)
		{
			ToolTemplateBuilder obj = new ToolTemplateBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsFood(Action<FoodTemplateBuilder> configure)
		{
			FoodTemplateBuilder obj = new FoodTemplateBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder AsMaterial(Action<MaterialTemplateBuilder> configure = null)
		{
			MaterialTemplateBuilder obj = new MaterialTemplateBuilder(definition);
			configure?.Invoke(obj);
			return this;
		}

		public CustomItemBuilder ConfigureSharedData(Action<SharedData> configure)
		{
			if (configure != null)
			{
				definition.SharedDataConfigurators.Add(configure);
			}
			return this;
		}

		public CustomItemDefinition Build()
		{
			return definition;
		}

		public ItemRegistrationResult Register()
		{
			return CustomItemRegistry.RegisterItem(definition);
		}
	}
	public sealed class GearBuilder
	{
		private readonly CustomItemDefinition definition;

		internal GearBuilder(CustomItemDefinition definition)
		{
			this.definition = definition;
		}

		public GearBuilder OneHandedWeapon()
		{
			return Type((ItemType)3);
		}

		public GearBuilder TwoHandedWeapon()
		{
			return Type((ItemType)14);
		}

		public GearBuilder TwoHandedWeaponLeft()
		{
			return Type((ItemType)22);
		}

		public GearBuilder Shield()
		{
			return Type((ItemType)5);
		}

		public GearBuilder Bow()
		{
			return Type((ItemType)4);
		}

		public GearBuilder Ammo()
		{
			return Type((ItemType)9);
		}

		public GearBuilder AmmoNonEquipable()
		{
			return Type((ItemType)23);
		}

		public GearBuilder Material()
		{
			return Type((ItemType)1);
		}

		public GearBuilder Consumable()
		{
			return Type((ItemType)2);
		}

		public GearBuilder Torch()
		{
			return Type((ItemType)15);
		}

		public GearBuilder Tool()
		{
			return Type((ItemType)19);
		}

		public GearBuilder Armor()
		{
			return Type((ItemType)7);
		}

		public GearBuilder Helmet()
		{
			return Type((ItemType)6);
		}

		public GearBuilder Chest()
		{
			return Type((ItemType)7);
		}

		public GearBuilder Legs()
		{
			return Type((ItemType)11);
		}

		public GearBuilder Shoulder()
		{
			return Type((ItemType)17);
		}

		public GearBuilder Utility()
		{
			return Type((ItemType)18);
		}

		public GearBuilder Trinket()
		{
			return Type((ItemType)24);
		}

		public GearBuilder Type(ItemType itemType)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			definition.ItemType = itemType;
			return this;
		}

		public GearBuilder Weight(float value)
		{
			definition.Weight = value;
			return this;
		}

		public GearBuilder StackSize(int value)
		{
			definition.StackSize = value;
			return this;
		}

		public GearBuilder Durability(float value)
		{
			definition.MaxDurability = value;
			return this;
		}

		public GearBuilder DurabilityPerLevel(float value)
		{
			definition.DurabilityPerLevel = value;
			return this;
		}

		public GearBuilder MaxQuality(int value)
		{
			definition.MaxQuality = value;
			return this;
		}

		public GearBuilder ToolTier(int value)
		{
			definition.ToolTier = value;
			return this;
		}

		public GearBuilder ArmorValue(float value)
		{
			definition.Armor = value;
			return this;
		}

		public GearBuilder ArmorPerLevel(float value)
		{
			definition.ArmorPerLevel = value;
			return this;
		}

		public GearBuilder BlockPower(float value)
		{
			definition.BlockPower = value;
			return this;
		}

		public GearBuilder BlockPowerPerLevel(float value)
		{
			definition.BlockPowerPerLevel = value;
			return this;
		}

		public GearBuilder BlockForce(float value)
		{
			definition.DeflectionForce = value;
			return this;
		}

		public GearBuilder BlockForcePerLevel(float value)
		{
			definition.DeflectionForcePerLevel = value;
			return this;
		}

		public GearBuilder Parry(float value)
		{
			definition.SharedDataConfigurators.Add(delegate(SharedData shared)
			{
				shared.m_timedBlockBonus = value;
			});
			return this;
		}

		public GearBuilder AttackForce(float value)
		{
			definition.SharedDataConfigurators.Add(delegate(SharedData shared)
			{
				shared.m_attackForce = value;
			});
			return this;
		}

		public GearBuilder MovementModifier(float value)
		{
			definition.MovementModifier = value;
			return this;
		}

		public GearBuilder Teleportable(bool value = true)
		{
			definition.Teleportable = value;
			return this;
		}

		public GearBuilder Repairable(bool value = true)
		{
			definition.CanBeRepaired = value;
			return this;
		}

		public GearBuilder BluntDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_blunt = value;
				return d;
			});
		}

		public GearBuilder SlashDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_slash = value;
				return d;
			});
		}

		public GearBuilder PierceDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_pierce = value;
				return d;
			});
		}

		public GearBuilder FireDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_fire = value;
				return d;
			});
		}

		public GearBuilder FrostDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_frost = value;
				return d;
			});
		}

		public GearBuilder LightningDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_lightning = value;
				return d;
			});
		}

		public GearBuilder PoisonDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_poison = value;
				return d;
			});
		}

		public GearBuilder SpiritDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_spirit = value;
				return d;
			});
		}

		public GearBuilder ChopDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_chop = value;
				return d;
			});
		}

		public GearBuilder PickaxeDamage(float value)
		{
			return Damage(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_pickaxe = value;
				return d;
			});
		}

		public GearBuilder BluntDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_blunt = value;
				return d;
			});
		}

		public GearBuilder SlashDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_slash = value;
				return d;
			});
		}

		public GearBuilder PierceDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_pierce = value;
				return d;
			});
		}

		public GearBuilder FireDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_fire = value;
				return d;
			});
		}

		public GearBuilder FrostDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_frost = value;
				return d;
			});
		}

		public GearBuilder LightningDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_lightning = value;
				return d;
			});
		}

		public GearBuilder PoisonDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_poison = value;
				return d;
			});
		}

		public GearBuilder SpiritDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_spirit = value;
				return d;
			});
		}

		public GearBuilder ChopDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_chop = value;
				return d;
			});
		}

		public GearBuilder PickaxeDamagePerLevel(float value)
		{
			return DamagePerLevel(delegate(DamageTypes d)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				d.m_pickaxe = value;
				return d;
			});
		}

		public GearBuilder DamageModifier(DamageType damageType, DamageModifier modifier)
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			definition.SharedDataConfigurators.Add(delegate(SharedData shared)
			{
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				if (shared.m_damageModifiers == null)
				{
					shared.m_damageModifiers = new List<DamageModPair>();
				}
				shared.m_damageModifiers.RemoveAll((DamageModPair entry) => entry.m_type == damageType);
				shared.m_damageModifiers.Add(new DamageModPair
				{
					m_type = damageType,
					m_modifier = modifier
				});
			});
			return this;
		}

		public GearBuilder PrimaryAttackStamina(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_attackStamina = value;
			});
		}

		public GearBuilder PrimaryAttackEitr(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_attackEitr = value;
			});
		}

		public GearBuilder PrimaryAttackHealth(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_attackHealth = value;
			});
		}

		public GearBuilder PrimaryAttackHealthPercentage(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_attackHealthPercentage = value;
			});
		}

		public GearBuilder PrimaryAttackHealthReturnHit(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_attackHealthReturnHit = value;
			});
		}

		public GearBuilder PrimaryAttackDamageMultiplierPerMissingHp(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_damageMultiplierPerMissingHP = value;
			});
		}

		public GearBuilder PrimaryAttackForceMultiplier(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_forceMultiplier = value;
			});
		}

		public GearBuilder PrimaryAttackProjectileCount(int value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_projectiles = value;
			});
		}

		public GearBuilder ProjectileVelocity(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_projectileVel = value;
			});
		}

		public GearBuilder ProjectileAccuracy(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_projectileAccuracy = value;
			});
		}

		public GearBuilder DrawDuration(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_drawDurationMin = value;
			});
		}

		public GearBuilder DrawStaminaDrain(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_drawStaminaDrain = value;
			});
		}

		public GearBuilder ReloadTime(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_reloadTime = value;
			});
		}

		public GearBuilder ReloadStaminaDrain(float value)
		{
			return PrimaryAttack(delegate(Attack attack)
			{
				attack.m_reloadStaminaDrain = value;
			});
		}

		public GearBuilder SecondaryAttackStamina(float value)
		{
			return SecondaryAttack(delegate(Attack attack)
			{
				attack.m_attackStamina = value;
			});
		}

		public GearBuilder SecondaryAttackEitr(float value)
		{
			return SecondaryAttack(delegate(Attack attack)
			{
				attack.m_attackEitr = value;
			});
		}

		public GearBuilder SecondaryAttackHealth(float value)
		{
			return SecondaryAttack(delegate(Attack attack)
			{
				attack.m_attackHealth = value;
			});
		}

		public GearBuilder SecondaryAttackHealthPercentage(float value)
		{
			return SecondaryAttack(delegate(Attack attack)
			{
				attack.m_attackHealthPercentage = value;
			});
		}

		public GearBuilder SecondaryAttackForceMultiplier(float value)
		{
			return SecondaryAttack(delegate(Attack attack)
			{
				attack.m_forceMultiplier = value;
			});
		}

		private GearBuilder Damage(Func<DamageTypes, DamageTypes> configure)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			definition.Damages = configure(definition.Damages);
			definition.HasDamages = true;
			return this;
		}

		private GearBuilder DamagePerLevel(Func<DamageTypes, DamageTypes> configure)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			definition.DamagesPerLevel = configure(definition.DamagesPerLevel);
			definition.HasDamagesPerLevel = true;
			return this;
		}

		private GearBuilder PrimaryAttack(Action<Attack> configure)
		{
			definition.SharedDataConfigurators.Add(delegate(SharedData shared)
			{
				ConfigureAttack(shared.m_attack, "primary", shared.m_name, configure);
			});
			return this;
		}

		private GearBuilder SecondaryAttack(Action<Attack> configure)
		{
			definition.SharedDataConfigurators.Add(delegate(SharedData shared)
			{
				ConfigureAttack(shared.m_secondaryAttack, "secondary", shared.m_name, configure);
			});
			return this;
		}

		private static void ConfigureAttack(Attack attack, string label, string itemName, Action<Attack> configure)
		{
			if (attack == null)
			{
				throw new CustomItemRegistrationException("Item '" + itemName + "' has no " + label + " attack to configure");
			}
			configure(attack);
		}
	}
	public sealed class PrefabPreparationBuilder
	{
		private readonly PrefabPreparationOptions options;

		internal PrefabPreparationBuilder(PrefabPreparationOptions options)
		{
			this.options = options;
		}

		public PrefabPreparationBuilder RequireItemDrop()
		{
			options.RequireExistingItemDrop = true;
			options.AutoAddItemDrop = false;
			return this;
		}

		public PrefabPreparationBuilder AutoAddItemDrop(bool value = true)
		{
			options.AutoAddItemDrop = value;
			if (value)
			{
				options.RequireExistingItemDrop = false;
			}
			return this;
		}

		public PrefabPreparationBuilder AutoAddPhysics(bool value = true)
		{
			options.AutoAddPhysics = value;
			return this;
		}

		public PrefabPreparationBuilder WarnOnMissingCollider(bool value = true)
		{
			options.WarnOnMissingCollider = value;
			return this;
		}

		public PrefabPreparationBuilder AllowTextureIconFallback(bool value = true)
		{
			options.AllowTextureIconFallback = value;
			return this;
		}

		public PrefabPreparationBuilder ValidateWearableVisuals(bool value = true)
		{
			options.ValidateWearableVisuals = value;
			return this;
		}
	}
	public sealed class RecipeBuilder
	{
		private readonly List<Ingredient> ingredients = new List<Ingredient>();

		private string craftingStation;

		private string repairStation;

		private int amount = 1;

		private int minStationLevel = 1;

		private bool enabled = true;

		private bool requireOnlyOneIngredient;

		private int qualityResultAmountMultiplier = 1;

		private string craftingStationValidationError;

		private string repairStationValidationError;

		public RecipeBuilder At(string station)
		{
			craftingStation = station;
			craftingStationValidationError = null;
			return this;
		}

		public RecipeBuilder At(CraftingStation station)
		{
			if (CraftingStationExtensions.TryToPrefabName(station, out var prefabName))
			{
				craftingStation = prefabName;
				craftingStationValidationError = null;
			}
			else
			{
				craftingStation = null;
				craftingStationValidationError = $"Invalid CraftingStation value '{(int)station}' for crafting station";
			}
			return this;
		}

		public RecipeBuilder RepairAt(string station)
		{
			repairStation = station;
			repairStationValidationError = null;
			return this;
		}

		public RecipeBuilder RepairAt(CraftingStation station)
		{
			if (CraftingStationExtensions.TryToPrefabName(station, out var prefabName))
			{
				repairStation = prefabName;
				repairStationValidationError = null;
			}
			else
			{
				repairStation = null;
				repairStationValidationError = $"Invalid CraftingStation value '{(int)station}' for repair station";
			}
			return this;
		}

		public RecipeBuilder StationLevel(int level)
		{
			minStationLevel = level;
			return this;
		}

		public RecipeBuilder Amount(int craftedAmount)
		{
			amount = craftedAmount;
			return this;
		}

		public RecipeBuilder Enabled(bool isEnabled = true)
		{
			enabled = isEnabled;
			return this;
		}

		public RecipeBuilder RequireOnlyOneIngredient(bool value = true)
		{
			requireOnlyOneIngredient = value;
			return this;
		}

		public RecipeBuilder QualityResultAmountMultiplier(int multiplier)
		{
			qualityResultAmountMultiplier = multiplier;
			return this;
		}

		public RecipeBuilder Requires(string itemName, int amount, int amountPerLevel = 0, bool recover = true)
		{
			ingredients.Add(new Ingredient(itemName, amount, amountPerLevel, recover));
			return this;
		}

		public RecipeBuilder Requires(VanillaItem item, int amount, int amountPerLevel = 0, bool recover = true)
		{
			ingredients.Add(Ingredient.From(item, amount, amountPerLevel, recover));
			return this;
		}

		public RecipeBuilder Requires(ItemRef item, int amount, int amountPerLevel = 0, bool recover = true)
		{
			ingredients.Add(Ingredient.From(item, amount, amountPerLevel, recover));
			return this;
		}

		internal CraftingRecipe Build()
		{
			CraftingRecipe result = new CraftingRecipe(ingredients, craftingStation, amount, repairStation, minStationLevel, enabled, requireOnlyOneIngredient, qualityResultAmountMultiplier);
			result.CraftingStationValidationError = craftingStationValidationError;
			result.RepairStationValidationError = repairStationValidationError;
			return result;
		}
	}
	public enum CraftingStation
	{
		None,
		Workbench,
		Forge,
		Stonecutter,
		Cauldron,
		ArtisanTable,
		BlackForge,
		GaldrTable,
		EitrRefinery
	}
	public static class CraftingStationExtensions
	{
		public static string ToPrefabName(this CraftingStation station)
		{
			if (TryToPrefabName(station, out var prefabName))
			{
				return prefabName;
			}
			throw new ArgumentOutOfRangeException("station", station, "Unknown CraftingStation value");
		}

		internal static bool TryToPrefabName(CraftingStation station, out string prefabName)
		{
			switch (station)
			{
			case CraftingStation.None:
				prefabName = null;
				return true;
			case CraftingStation.Workbench:
				prefabName = "piece_workbench";
				return true;
			case CraftingStation.Forge:
				prefabName = "forge";
				return true;
			case CraftingStation.Stonecutter:
				prefabName = "piece_stonecutter";
				return true;
			case CraftingStation.Cauldron:
				prefabName = "piece_cauldron";
				return true;
			case CraftingStation.ArtisanTable:
				prefabName = "piece_artisanstation";
				return true;
			case CraftingStation.BlackForge:
				prefabName = "blackforge";
				return true;
			case CraftingStation.GaldrTable:
				prefabName = "piece_magetable";
				return true;
			case CraftingStation.EitrRefinery:
				prefabName = "piece_eitrrefinery";
				return true;
			default:
				prefabName = null;
				return false;
			}
		}
	}
	public readonly struct ItemRef
	{
		public string PrefabName { get; }

		public string SourceModGuid { get; }

		public bool IsVanilla { get; }

		internal string ValidationError { get; }

		private ItemRef(string prefabName, string sourceModGuid, bool isVanilla, string validationError)
		{
			PrefabName = prefabName;
			SourceModGuid = sourceModGuid;
			IsVanilla = isVanilla;
			ValidationError = validationError;
		}

		public static ItemRef Vanilla(VanillaItem item)
		{
			if (!VanillaItemExtensions.TryToPrefabName(item, out var prefabName))
			{
				return new ItemRef(null, null, isVanilla: true, $"Invalid VanillaItem value '{(int)item}'");
			}
			return new ItemRef(prefabName, null, isVanilla: true, null);
		}

		public static ItemRef Prefab(string prefabName)
		{
			if (!string.IsNullOrWhiteSpace(prefabName))
			{
				return new ItemRef(prefabName, null, isVanilla: false, null);
			}
			return new ItemRef(prefabName, null, isVanilla: false, "ItemRef prefab name is required");
		}

		public static ItemRef Modded(string sourceModGuid, string prefabName)
		{
			if (string.IsNullOrWhiteSpace(prefabName))
			{
				return new ItemRef(prefabName, sourceModGuid, isVanilla: false, "Modded ItemRef prefab name is required");
			}
			return new ItemRef(prefabName, sourceModGuid, isVanilla: false, null);
		}

		public static ItemRef FromRegisteredCIRItem(string itemName)
		{
			if (!string.IsNullOrWhiteSpace(itemName))
			{
				return new ItemRef(itemName, "com.valheimcustomitemregistry.api", isVanilla: false, null);
			}
			return new ItemRef(itemName, "com.valheimcustomitemregistry.api", isVanilla: false, "Registered CIR item name is required");
		}
	}
	public static class ItemRefs
	{
		public static ItemRef Vanilla(VanillaItem item)
		{
			return ItemRef.Vanilla(item);
		}

		public static ItemRef Prefab(string prefabName)
		{
			return ItemRef.Prefab(prefabName);
		}

		public static ItemRef Modded(string sourceModGuid, string prefabName)
		{
			return ItemRef.Modded(sourceModGuid, prefabName);
		}

		public static ItemRef RegisteredCIRItem(string itemName)
		{
			return ItemRef.FromRegisteredCIRItem(itemName);
		}
	}
	public enum VanillaItem
	{
		Wood,
		FineWood,
		RoundLog,
		ElderBark,
		YggdrasilWood,
		Stone,
		Flint,
		Coal,
		Resin,
		Amber,
		AmberPearl,
		Ruby,
		Crystal,
		Coins,
		SurtlingCore,
		BlackCore,
		CopperOre,
		Copper,
		TinOre,
		Tin,
		Bronze,
		IronScrap,
		Iron,
		SilverOre,
		Silver,
		BlackMetalScrap,
		BlackMetal,
		FlametalOre,
		Flametal,
		LeatherScraps,
		DeerHide,
		TrollHide,
		WolfPelt,
		LoxPelt,
		ScaleHide,
		Carapace,
		Feathers,
		BoneFragments,
		WitheredBone,
		HardAntler,
		DragonEgg,
		Wishbone,
		YmirRemains,
		QueenDrop,
		Mushroom,
		MushroomYellow,
		MushroomBlue,
		MushroomMagecap,
		MushroomJotunPuffs,
		Raspberry,
		Blueberries,
		Cloudberry,
		Honey,
		Carrot,
		Turnip,
		Onion,
		Barley,
		BarleyFlour,
		Flax,
		Sap,
		RoyalJelly,
		Dandelion,
		Thistle,
		Entrails,
		Bloodbag,
		Ooze,
		Guck,
		Tar,
		WolfFang,
		WolfClaw,
		Needle,
		Obsidian,
		Chitin,
		SerpentScale,
		BoarMeat,
		DeerMeat,
		WolfMeat,
		LoxMeat,
		SerpentMeat,
		HareMeat,
		ChickenMeat,
		BugMeat,
		FishRaw,
		ArrowWood,
		ArrowFire,
		ArrowFlint,
		ArrowIron,
		ArrowObsidian,
		ArrowPoison,
		ArrowSilver,
		ArrowNeedle,
		ArrowCarapace,
		BoltBone,
		BoltBlackmetal,
		BoltCarapace,
		TrophyBoar,
		TrophyDeer,
		TrophyEikthyr,
		TrophyTheElder,
		TrophyBonemass,
		TrophyDragonQueen,
		TrophyGoblinKing,
		TrophySeekerQueen
	}
	public static class VanillaItemExtensions
	{
		public static string ToPrefabName(this VanillaItem item)
		{
			if (TryToPrefabName(item, out var prefabName))
			{
				return prefabName;
			}
			throw new ArgumentOutOfRangeException("item", item, "Unknown VanillaItem value");
		}

		internal static bool TryToPrefabName(VanillaItem item, out string prefabName)
		{
			switch (item)
			{
			case VanillaItem.Wood:
				prefabName = "Wood";
				return true;
			case VanillaItem.FineWood:
				prefabName = "FineWood";
				return true;
			case VanillaItem.RoundLog:
				prefabName = "RoundLog";
				return true;
			case VanillaItem.ElderBark:
				prefabName = "ElderBark";
				return true;
			case VanillaItem.YggdrasilWood:
				prefabName = "YggdrasilWood";
				return true;
			case VanillaItem.Stone:
				prefabName = "Stone";
				return true;
			case VanillaItem.Flint:
				prefabName = "Flint";
				return true;
			case VanillaItem.Coal:
				prefabName = "Coal";
				return true;
			case VanillaItem.Resin:
				prefabName = "Resin";
				return true;
			case VanillaItem.Amber:
				prefabName = "Amber";
				return true;
			case VanillaItem.AmberPearl:
				prefabName = "AmberPearl";
				return true;
			case VanillaItem.Ruby:
				prefabName = "Ruby";
				return true;
			case VanillaItem.Crystal:
				prefabName = "Crystal";
				return true;
			case VanillaItem.Coins:
				prefabName = "Coins";
				return true;
			case VanillaItem.SurtlingCore:
				prefabName = "SurtlingCore";
				return true;
			case VanillaItem.BlackCore:
				prefabName = "BlackCore";
				return true;
			case VanillaItem.CopperOre:
				prefabName = "CopperOre";
				return true;
			case VanillaItem.Copper:
				prefabName = "Copper";
				return true;
			case VanillaItem.TinOre:
				prefabName = "TinOre";
				return true;
			case VanillaItem.Tin:
				prefabName = "Tin";
				return true;
			case VanillaItem.Bronze:
				prefabName = "Bronze";
				return true;
			case VanillaItem.IronScrap:
				prefabName = "IronScrap";
				return true;
			case VanillaItem.Iron:
				prefabName = "Iron";
				return true;
			case VanillaItem.SilverOre:
				prefabName = "SilverOre";
				return true;
			case VanillaItem.Silver:
				prefabName = "Silver";
				return true;
			case VanillaItem.BlackMetalScrap:
				prefabName = "BlackMetalScrap";
				return true;
			case VanillaItem.BlackMetal:
				prefabName = "BlackMetal";
				return true;
			case VanillaItem.FlametalOre:
				prefabName = "FlametalOreNew";
				return true;
			case VanillaItem.Flametal:
				prefabName = "FlametalNew";
				return true;
			case VanillaItem.LeatherScraps:
				prefabName = "LeatherScraps";
				return true;
			case VanillaItem.DeerHide:
				prefabName = "DeerHide";
				return true;
			case VanillaItem.TrollHide:
				prefabName = "TrollHide";
				return true;
			case VanillaItem.WolfPelt:
				prefabName = "WolfPelt";
				return true;
			case VanillaItem.LoxPelt:
				prefabName = "LoxPelt";
				return true;
			case VanillaItem.ScaleHide:
				prefabName = "ScaleHide";
				return true;
			case VanillaItem.Carapace:
				prefabName = "Carapace";
				return true;
			case VanillaItem.Feathers:
				prefabName = "Feathers";
				return true;
			case VanillaItem.BoneFragments:
				prefabName = "BoneFragments";
				return true;
			case VanillaItem.WitheredBone:
				prefabName = "WitheredBone";
				return true;
			case VanillaItem.HardAntler:
				prefabName = "HardAntler";
				return true;
			case VanillaItem.DragonEgg:
				prefabName = "DragonEgg";
				return true;
			case VanillaItem.Wishbone:
				prefabName = "Wishbone";
				return true;
			case VanillaItem.YmirRemains:
				prefabName = "YmirRemains";
				return true;
			case VanillaItem.QueenDrop:
				prefabName = "QueenDrop";
				return true;
			case VanillaItem.Mushroom:
				prefabName = "Mushroom";
				return true;
			case VanillaItem.MushroomYellow:
				prefabName = "MushroomYellow";
				return true;
			case VanillaItem.MushroomBlue:
				prefabName = "MushroomBlue";
				return true;
			case VanillaItem.MushroomMagecap:
				prefabName = "MushroomMagecap";
				return true;
			case VanillaItem.MushroomJotunPuffs:
				prefabName = "MushroomJotunPuffs";
				return true;
			case VanillaItem.Raspberry:
				prefabName = "Raspberry";
				return true;
			case VanillaItem.Blueberries:
				prefabName = "Blueberries";
				return true;
			case VanillaItem.Cloudberry:
				prefabName = "Cloudberry";
				return true;
			case VanillaItem.Honey:
				prefabName = "Honey";
				return true;
			case VanillaItem.Carrot:
				prefabName = "Carrot";
				return true;
			case VanillaItem.Turnip:
				prefabName = "Turnip";
				return true;
			case VanillaItem.Onion:
				prefabName = "Onion";
				return true;
			case VanillaItem.Barley:
				prefabName = "Barley";
				return true;
			case VanillaItem.BarleyFlour:
				prefabName = "BarleyFlour";
				return true;
			case VanillaItem.Flax:
				prefabName = "Flax";
				return true;
			case VanillaItem.Sap:
				prefabName = "Sap";
				return true;
			case VanillaItem.RoyalJelly:
				prefabName = "RoyalJelly";
				return true;
			case VanillaItem.Dandelion:
				prefabName = "Dandelion";
				return true;
			case VanillaItem.Thistle:
				prefabName = "Thistle";
				return true;
			case VanillaItem.Entrails:
				prefabName = "Entrails";
				return true;
			case VanillaItem.Bloodbag:
				prefabName = "Bloodbag";
				return true;
			case VanillaItem.Ooze:
				prefabName = "Ooze";
				return true;
			case VanillaItem.Guck:
				prefabName = "Guck";
				return true;
			case VanillaItem.Tar:
				prefabName = "Tar";
				return true;
			case VanillaItem.WolfFang:
				prefabName = "WolfFang";
				return true;
			case VanillaItem.WolfClaw:
				prefabName = "WolfClaw";
				return true;
			case VanillaItem.Needle:
				prefabName = "Needle";
				return true;
			case VanillaItem.Obsidian:
				prefabName = "Obsidian";
				return true;
			case VanillaItem.Chitin:
				prefabName = "Chitin";
				return true;
			case VanillaItem.SerpentScale:
				prefabName = "SerpentScale";
				return true;
			case VanillaItem.BoarMeat:
				prefabName = "RawMeat";
				return true;
			case VanillaItem.DeerMeat:
				prefabName = "DeerMeat";
				return true;
			case VanillaItem.WolfMeat:
				prefabName = "WolfMeat";
				return true;
			case VanillaItem.LoxMeat:
				prefabName = "LoxMeat";
				return true;
			case VanillaItem.SerpentMeat:
				prefabName = "SerpentMeat";
				return true;
			case VanillaItem.HareMeat:
				prefabName = "HareMeat";
				return true;
			case VanillaItem.ChickenMeat:
				prefabName = "ChickenMeat";
				return true;
			case VanillaItem.BugMeat:
				prefabName = "BugMeat";
				return true;
			case VanillaItem.FishRaw:
				prefabName = "FishRaw";
				return true;
			case VanillaItem.ArrowWood:
				prefabName = "ArrowWood";
				return true;
			case VanillaItem.ArrowFire:
				prefabName = "ArrowFire";
				return true;
			case VanillaItem.ArrowFlint:
				prefabName = "ArrowFlint";
				return true;
			case VanillaItem.ArrowIron:
				prefabName = "ArrowIron";
				return true;
			case VanillaItem.ArrowObsidian:
				prefabName = "ArrowObsidian";
				return true;
			case VanillaItem.ArrowPoison:
				prefabName = "ArrowPoison";
				return true;
			case VanillaItem.ArrowSilver:
				prefabName = "ArrowSilver";
				return true;
			case VanillaItem.ArrowNeedle:
				prefabName = "ArrowNeedle";
				return true;
			case VanillaItem.ArrowCarapace:
				prefabName = "ArrowCarapace";
				return true;
			case VanillaItem.BoltBone:
				prefabName = "BoltBone";
				return true;
			case VanillaItem.BoltBlackmetal:
				prefabName = "BoltBlackmetal";
				return true;
			case VanillaItem.BoltCarapace:
				prefabName = "BoltCarapace";
				return true;
			case VanillaItem.TrophyBoar:
				prefabName = "TrophyBoar";
				return true;
			case VanillaItem.TrophyDeer:
				prefabName = "TrophyDeer";
				return true;
			case VanillaItem.TrophyEikthyr:
				prefabName = "TrophyEikthyr";
				return true;
			case VanillaItem.TrophyTheElder:
				prefabName = "TrophyTheElder";
				return true;
			case VanillaItem.TrophyBonemass:
				prefabName = "TrophyBonemass";
				return true;
			case VanillaItem.TrophyDragonQueen:
				prefabName = "TrophyDragonQueen";
				return true;
			case VanillaItem.TrophyGoblinKing:
				prefabName = "TrophyGoblinKing";
				return true;
			case VanillaItem.TrophySeekerQueen:
				prefabName = "TrophySeekerQueen";
				return true;
			default:
				prefabName = null;
				return false;
			}
		}
	}
	internal interface IItemPackParser
	{
		string FormatName { get; }

		string MissingDependencyMessage { get; }

		bool IsAvailable { get; }

		bool CanParse(string filePath);

		ItemPackDto Parse(string text);
	}
	internal sealed class ItemPackDto
	{
		public string Name { get; set; }

		public string Version { get; set; }

		public List<ItemPackItemDto> Items { get; set; }
	}
	internal sealed class ItemPackItemDto
	{
		public string ItemName { get; set; }

		public string AssetBundle { get; set; }

		public string AssetBundlePath { get; set; }

		public string PrefabName { get; set; }

		public string DisplayName { get; set; }

		public string Description { get; set; }

		public string Icon { get; set; }

		public string ItemType { get; set; }

		public float? Weight { get; set; }

		public int? StackSize { get; set; }

		public bool? Teleportable { get; set; }

		public float? Durability { get; set; }

		public float? DurabilityPerLevel { get; set; }

		public int? MaxQuality { get; set; }

		public int? ToolTier { get; set; }

		public float? Armor { get; set; }

		public float? ArmorPerLevel { get; set; }

		public float? MovementModifier { get; set; }

		public ItemPackDamageDto Damages { get; set; }

		public ItemPackDamageDto DamagesPerLevel { get; set; }

		public ItemPackRecipeDto Recipe { get; set; }

		public ItemPackPrefabPreparationDto PrefabPreparation { get; set; }
	}
	internal sealed class ItemPackDamageDto
	{
		public float? Blunt { get; set; }

		public float? Slash { get; set; }

		public float? Pierce { get; set; }

		public float? Fire { get; set; }

		public float? Frost { get; set; }

		public float? Lightning { get; set; }

		public float? Poison { get; set; }

		public float? Spirit { get; set; }

		public float? Chop { get; set; }

		public float? Pickaxe { get; set; }
	}
	internal sealed class ItemPackRecipeDto
	{
		public bool? Enabled { get; set; }

		public string CraftingStation { get; set; }

		public string RepairStation { get; set; }

		public int? MinStationLevel { get; set; }

		public int? Amount { get; set; }

		public bool? RequireOnlyOneIngredient { get; set; }

		public int? QualityResultAmountMultiplier { get; set; }

		public List<ItemPackIngredientDto> Ingredients { get; set; }
	}
	internal sealed class ItemPackIngredientDto
	{
		public string Item { get; set; }

		public int? Amount { get; set; }

		public int? AmountPerLevel { get; set; }

		public bool? Recover { get; set; }

		public string SourceModGuid { get; set; }
	}
	internal sealed class ItemPackPrefabPreparationDto
	{
		public bool? AutoAddItemDrop { get; set; }

		public bool? AutoAddPhysics { get; set; }

		public bool? WarnOnMissingCollider { get; set; }

		public bool? AllowTextureIconFallback { get; set; }

		public bool? ValidateWearableVisuals { get; set; }
	}
	public sealed class ItemPackFileResult
	{
		public string FilePath { get; internal set; }

		public string Format { get; internal set; }

		public string PackName { get; internal set; }

		public string PackVersion { get; internal set; }

		public bool Skipped { get; internal set; }

		public string SkipReason { get; internal set; }

		public List<ItemRegistrationResult> Items { get; private set; }

		public List<ItemPackRegistrationError> Errors { get; private set; }

		public ItemPackFileResult()
		{
			Items = new List<ItemRegistrationResult>();
			Errors = new List<ItemPackRegistrationError>();
		}
	}
	internal static class ItemPackLoader
	{
		private static readonly IItemPackParser[] Parsers = new IItemPackParser[2]
		{
			new YamlItemPackParser(),
			new JsonItemPackParser()
		};

		public static string DefaultPackDirectory => Path.Combine(Paths.ConfigPath, "CustomItemRegistry", "packs");

		public static ItemPackParserStatus GetParserStatus()
		{
			return ItemPackParserStatus.Create();
		}

		public static ItemPackLoadResult LoadDefault(ItemPackLoadOptions options)
		{
			return LoadDirectory(DefaultPackDirectory, options);
		}

		public static ItemPackLoadResult LoadDirectory(string directory, ItemPackLoadOptions options)
		{
			options = options ?? new ItemPackLoadOptions();
			ItemPackLoadResult itemPackLoadResult = new ItemPackLoadResult
			{
				SourcePath = directory
			};
			if (string.IsNullOrWhiteSpace(directory) || !Directory.Exists(directory))
			{
				return itemPackLoadResult;
			}
			SearchOption searchOption = (options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
			foreach (string item in Directory.EnumerateFiles(directory, "*.*", searchOption).Where(IsSupportedExtension).OrderBy<string, string>((string path) => path, StringComparer.OrdinalIgnoreCase))
			{
				itemPackLoadResult.Add(LoadFile(item, options));
			}
			LogSummary(itemPackLoadResult, options);
			return itemPackLoadResult;
		}

		public static ItemPackLoadResult LoadFile(string filePath, ItemPackLoadOptions options)
		{
			options = options ?? new ItemPackLoadOptions();
			ItemPackLoadResult itemPackLoadResult = new ItemPackLoadResult
			{
				SourcePath = filePath
			};
			ItemPackFileResult itemPackFileResult = new ItemPackFileResult
			{
				FilePath = filePath
			};
			itemPackLoadResult.Files.Add(itemPackFileResult);
			IItemPackParser itemPackParser = Parsers.FirstOrDefault((IItemPackParser candidate) => candidate.CanParse(filePath));
			if (itemPackParser == null)
			{
				itemPackFileResult.Skipped = true;
				itemPackFileResult.SkipReason = "Unsupported item-pack file extension";
				return itemPackLoadResult;
			}
			itemPackFileResult.Format = itemPackParser.FormatName;
			if (!itemPackParser.IsAvailable)
			{
				itemPackFileResult.Skipped = true;
				itemPackFileResult.SkipReason = itemPackParser.MissingDependencyMessage;
				CustomItemRegistry.LogWarning(itemPackParser.MissingDependencyMessage + " Skipping '" + filePath + "'.");
				return itemPackLoadResult;
			}
			try
			{
				ItemPackDto itemPackDto = itemPackParser.Parse(File.ReadAllText(filePath));
				itemPackFileResult.PackName = itemPackDto?.Name;
				itemPackFileResult.PackVersion = itemPackDto?.Version;
				if (itemPackDto?.Items == null || itemPackDto.Items.Count == 0)
				{
					itemPackFileResult.Errors.Add(new ItemPackRegistrationError(filePath, null, "Item pack contains no items"));
					return itemPackLoadResult;
				}
				foreach (ItemPackItemDto item in itemPackDto.Items)
				{
					RegisterItem(filePath, options, itemPackFileResult, item);
				}
			}
			catch (Exception exception)
			{
				string message = Unwrap(exception).Message;
				itemPackFileResult.Errors.Add(new ItemPackRegistrationError(filePath, null, message, exception));
				CustomItemRegistry.LogWarning("Could not load item pack '" + filePath + "': " + message);
			}
			return itemPackLoadResult;
		}

		private static void RegisterItem(string filePath, ItemPackLoadOptions options, ItemPackFileResult fileResult, ItemPackItemDto item)
		{
			CustomItemDefinition customItemDefinition = null;
			try
			{
				customItemDefinition = ItemPackMapper.ToDefinition(item, filePath, options);
				if (options.RegisterItems)
				{
					CustomItemRegistry.TryRegisterItem(customItemDefinition, out var result);
					fileResult.Items.Add(result);
					if (!result.Success)
					{
						fileResult.Errors.Add(new ItemPackRegistrationError(filePath, customItemDefinition.ItemName, result.ErrorMessage, result.Exception));
					}
				}
			}
			catch (Exception exception)
			{
				string text = customItemDefinition?.ItemName ?? item?.ItemName;
				string message = Unwrap(exception).Message;
				fileResult.Errors.Add(new ItemPackRegistrationError(filePath, text, message, exception));
				CustomItemRegistry.LogWarning("Could not register item-pack item '" + (text ?? "<unknown>") + "' from '" + filePath + "': " + message);
			}
		}

		private static bool IsSupportedExtension(string filePath)
		{
			return Parsers.Any((IItemPackParser parser) => parser.CanParse(filePath));
		}

		private static Exception Unwrap(Exception exception)
		{
			if (!(exception is TargetInvocationException ex) || ex.InnerException == null)
			{
				return exception;
			}
			return ex.InnerException;
		}

		private static void LogSummary(ItemPackLoadResult result, ItemPackLoadOptions options)
		{
			if (options.LogSummary && result.Files.Count != 0)
			{
				CustomItemRegistry.LogInfo($"Loaded CIR item packs from '{result.SourcePath}'. Files={result.Files.Count}; registered={result.RegisteredItemCount}; skipped={result.SkippedFileCount}; errors={result.FailedItemCount}.");
			}
		}
	}
	public sealed class ItemPackLoadOptions
	{
		public bool Recursive { get; set; }

		public bool RegisterItems { get; set; }

		public bool LogSummary { get; set; }

		public string AssetBundleBaseDirectory { get; set; }

		public ItemPackLoadOptions()
		{
			Recursive = true;
			RegisterItems = true;
			LogSummary = true;
		}
	}
	public sealed class ItemPackLoadResult
	{
		public string SourcePath { get; internal set; }

		public List<ItemPackFileResult> Files { get; private set; }

		public int RegisteredItemCount => Files.Sum((ItemPackFileResult file) => file.Items.Count((ItemRegistrationResult item) => item.Success));

		public int FailedItemCount => Files.Sum((ItemPackFileResult file) => file.Items.Count((ItemRegistrationResult item) => !item.Success)) + Files.Sum((ItemPackFileResult file) => file.Errors.Count);

		public int SkippedFileCount => Files.Count((ItemPackFileResult file) => file.Skipped);

		public ItemPackLoadResult()
		{
			Files = new List<ItemPackFileResult>();
		}

		internal void Add(ItemPackLoadResult other)
		{
			if (other != null)
			{
				Files.AddRange(other.Files);
			}
		}
	}
	internal static class ItemPackMapper
	{
		public static CustomItemDefinition ToDefinition(ItemPackItemDto item, string filePath, ItemPackLoadOptions options)
		{
			if (item == null)
			{
				throw new InvalidOperationException("Item entry is empty");
			}
			CustomItemDefinition obj = new CustomItemDefinition(item.ItemName)
			{
				AssetBundlePath = ResolveAssetBundlePath(item.AssetBundle ?? item.AssetBundlePath, filePath, options),
				PrefabName = item.PrefabName,
				DisplayName = item.DisplayName,
				Description = item.Description,
				IconAssetName = item.Icon,
				Weight = item.Weight,
				StackSize = item.StackSize,
				Teleportable = item.Teleportable,
				MaxDurability = item.Durability,
				DurabilityPerLevel = item.DurabilityPerLevel,
				MaxQuality = item.MaxQuality,
				ToolTier = item.ToolTier,
				Armor = item.Armor,
				ArmorPerLevel = item.ArmorPerLevel,
				MovementModifier = item.MovementModifier
			};
			ApplyItemType(obj, item.ItemType);
			ApplyDamages(obj, item.Damages, perLevel: false);
			ApplyDamages(obj, item.DamagesPerLevel, perLevel: true);
			ApplyRecipe(obj, item.Recipe);
			ApplyPrefabPreparation(obj, item.PrefabPreparation);
			return obj;
		}

		private static string ResolveAssetBundlePath(string assetBundle, string filePath, ItemPackLoadOptions options)
		{
			if (string.IsNullOrWhiteSpace(assetBundle))
			{
				return assetBundle;
			}
			if (Path.IsPathRooted(assetBundle))
			{
				return assetBundle;
			}
			string text = ((!string.IsNullOrWhiteSpace(options?.AssetBundleBaseDirectory)) ? options.AssetBundleBaseDirectory : Path.GetDirectoryName(filePath));
			string text2 = (string.IsNullOrWhiteSpace(text) ? assetBundle : Path.GetFullPath(Path.Combine(text, assetBundle)));
			if (File.Exists(text2))
			{
				return text2;
			}
			string fullPath = Path.GetFullPath(Path.Combine(Paths.PluginPath, assetBundle));
			if (!File.Exists(fullPath))
			{
				return text2;
			}
			return fullPath;
		}

		private static void ApplyItemType(CustomItemDefinition definition, string itemType)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrWhiteSpace(itemType))
			{
				if (!Enum.TryParse<ItemType>(itemType, ignoreCase: true, out ItemType result))
				{
					throw new InvalidOperationException("Invalid itemType '" + itemType + "'");
				}
				definition.ItemType = result;
			}
		}

		private static void ApplyDamages(CustomItemDefinition definition, ItemPackDamageDto dto, bool perLevel)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (dto != null)
			{
				DamageTypes val = default(DamageTypes);
				val.m_blunt = dto.Blunt.GetValueOrDefault();
				val.m_slash = dto.Slash.GetValueOrDefault();
				val.m_pierce = dto.Pierce.GetValueOrDefault();
				val.m_fire = dto.Fire.GetValueOrDefault();
				val.m_frost = dto.Frost.GetValueOrDefault();
				val.m_lightning = dto.Lightning.GetValueOrDefault();
				val.m_poison = dto.Poison.GetValueOrDefault();
				val.m_spirit = dto.Spirit.GetValueOrDefault();
				val.m_chop = dto.Chop.GetValueOrDefault();
				val.m_pickaxe = dto.Pickaxe.GetValueOrDefault();
				DamageTypes val2 = val;
				if (perLevel)
				{
					definition.DamagesPerLevel = val2;
					definition.HasDamagesPerLevel = true;
				}
				else
				{
					definition.Damages = val2;
					definition.HasDamages = true;
				}
			}
		}

		private static void ApplyRecipe(CustomItemDefinition definition, ItemPackRecipeDto dto)
		{
			if (dto != null)
			{
				string validationError;
				string validationError2;
				CraftingRecipe recipe = new CraftingRecipe(BuildIngredients(dto.Ingredients), ResolveStation(dto.CraftingStation, out validationError), dto.Amount.GetValueOrDefault(1), ResolveStation(dto.RepairStation, out validationError2), dto.MinStationLevel.GetValueOrDefault(1), dto.Enabled.GetValueOrDefault(true), dto.RequireOnlyOneIngredient.GetValueOrDefault(), dto.QualityResultAmountMultiplier.GetValueOrDefault(1));
				recipe.CraftingStationValidationError = validationError;
				recipe.RepairStationValidationError = validationError2;
				definition.Recipe = recipe;
				definition.HasRecipe = true;
			}
		}

		private static List<Ingredient> BuildIngredients(List<ItemPackIngredientDto> dtos)
		{
			List<Ingredient> list = new List<Ingredient>();
			if (dtos == null)
			{
				return list;
			}
			foreach (ItemPackIngredientDto dto in dtos)
			{
				Ingredient ingredient = new Ingredient(dto?.Item, (dto?.Amount).GetValueOrDefault(), (dto?.AmountPerLevel).GetValueOrDefault(), (dto?.Recover).GetValueOrDefault(true));
				ingredient.SourceModGuid = dto?.SourceModGuid;
				Ingredient item = ingredient;
				list.Add(item);
			}
			return list;
		}

		private static string ResolveStation(string station, out string validationError)
		{
			validationError = null;
			if (string.IsNullOrWhiteSpace(station))
			{
				return station;
			}
			if (!Enum.TryParse<CraftingStation>(s