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 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 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> 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>(); 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 : ""); return "Item '" + (definition.ItemName ?? "") + "' from bundle '" + text + "' prefab '" + (definition.PrefabName ?? "") + "': " + 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 AddedComponents = new List(); public readonly List Warnings = new List(); public bool CreatedItemDrop; } private static readonly Dictionary RegisteredItems = new Dictionary(); private static readonly Dictionary LoadedAssetBundles = new Dictionary(); 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(definition.PrefabName); if (!Object.op_Implicit((Object)(object)val2)) { throw new CustomItemRegistrationException(definition, CreateMissingAssetMessage(definition, assetBundle, definition.PrefabName, "prefab")); } ItemDrop component = val2.GetComponent(); 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(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 RegisterItems(IEnumerable definitions) { if (definitions == null) { throw new ArgumentNullException("definitions"); } List list = new List(); 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 addedComponents, out IReadOnlyList warnings, out string error) { addedComponents = Array.Empty(); warnings = Array.Empty(); 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 list = new List(); ItemDrop val = itemPrefab.GetComponent(); if (!Object.op_Implicit((Object)(object)val)) { if (prefabPreparationOptions.RequireExistingItemDrop || !prefabPreparationOptions.AutoAddItemDrop) { list.Add("ItemDrop"); } else { val = itemPrefab.AddComponent(); prefabPreparationReport.AddedComponents.Add("ItemDrop"); prefabPreparationReport.CreatedItemDrop = true; } } Rigidbody component = itemPrefab.GetComponent(); ZNetView val2 = itemPrefab.GetComponent(); ZSyncTransform component2 = itemPrefab.GetComponent(); bool flag = itemPrefab.GetComponentsInChildren(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(); prefabPreparationReport.AddedComponents.Add("Rigidbody"); } if (!Object.op_Implicit((Object)(object)val2)) { val2 = itemPrefab.AddComponent(); prefabPreparationReport.AddedComponents.Add("ZNetView"); } val2.m_persistent = true; if (!Object.op_Implicit((Object)(object)component2)) { component2 = itemPrefab.AddComponent(); 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(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(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 source = ((definition.HasRecipe && recipe.ingredients != null) ? recipe.ingredients : new List()); 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)source).Select((Func)((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().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().m_itemData.m_shared; foreach (Action sharedDataConfigurator in definition.SharedDataConfigurators) { sharedDataConfigurator(shared); } } private static void ValidatePreparedItem(CustomItemDefinition definition, GameObject itemPrefab, CustomItem customItem) { ItemDrop component = itemPrefab.GetComponent(); 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(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(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 ""; } Stack stack = new Stack(); 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 list = (from name in (from name in assetNames.Select(PrettyAssetName) where !string.IsNullOrWhiteSpace(name) select name).Distinct(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(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(); } try { return assetBundle.GetAllAssetNames() ?? Array.Empty(); } catch (Exception ex) { LogWarning("Could not inspect AssetBundle asset names: " + ex.Message); return Array.Empty(); } } 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 ""; } return ((Object)definition.AssetBundle).name; } private static void LogRegistrationSuccess(CustomItemDefinition definition, GameObject itemPrefab, string iconSource, PrefabPreparationReport preparationReport) { ItemDrop component = itemPrefab.GetComponent(); 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 configure) { PrefabPreparationBuilder obj = new PrefabPreparationBuilder(definition.PrefabPreparation); configure?.Invoke(obj); return this; } public CustomItemBuilder Recipe(Action configure) { RecipeBuilder recipeBuilder = new RecipeBuilder(); configure?.Invoke(recipeBuilder); definition.Recipe = recipeBuilder.Build(); definition.HasRecipe = true; return this; } public CustomItemBuilder Gear(Action configure) { GearBuilder obj = new GearBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder AsSword(Action configure) { WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Sword", (ItemType)3); configure?.Invoke(obj); return this; } public CustomItemBuilder AsAxe(Action configure) { WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Axe", (ItemType)3); configure?.Invoke(obj); return this; } public CustomItemBuilder AsMace(Action configure) { WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Mace", (ItemType)3); configure?.Invoke(obj); return this; } public CustomItemBuilder AsSpear(Action configure) { WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Spear", (ItemType)3); configure?.Invoke(obj); return this; } public CustomItemBuilder AsKnife(Action configure) { WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Knife", (ItemType)3); configure?.Invoke(obj); return this; } public CustomItemBuilder AsAtgeir(Action configure) { WeaponTemplateBuilder obj = new WeaponTemplateBuilder(definition, "Atgeir", (ItemType)14); configure?.Invoke(obj); return this; } public CustomItemBuilder AsBow(Action configure) { BowTemplateBuilder obj = new BowTemplateBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder AsArrow(Action configure) { AmmoTemplateBuilder obj = new AmmoTemplateBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder AsShield(Action configure) { ShieldTemplateBuilder obj = new ShieldTemplateBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder AsArmorChest(Action configure) { ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "ArmorChest", (ItemType)7); configure?.Invoke(obj); return this; } public CustomItemBuilder AsArmorLegs(Action configure) { ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "ArmorLegs", (ItemType)11); configure?.Invoke(obj); return this; } public CustomItemBuilder AsHelmet(Action configure) { ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "Helmet", (ItemType)6); configure?.Invoke(obj); return this; } public CustomItemBuilder AsCape(Action configure) { ArmorTemplateBuilder obj = new ArmorTemplateBuilder(definition, "Cape", (ItemType)17); configure?.Invoke(obj); return this; } public CustomItemBuilder AsTool(Action configure) { ToolTemplateBuilder obj = new ToolTemplateBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder AsFood(Action configure) { FoodTemplateBuilder obj = new FoodTemplateBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder AsMaterial(Action configure = null) { MaterialTemplateBuilder obj = new MaterialTemplateBuilder(definition); configure?.Invoke(obj); return this; } public CustomItemBuilder ConfigureSharedData(Action 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(); } 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 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 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 configure) { definition.SharedDataConfigurators.Add(delegate(SharedData shared) { ConfigureAttack(shared.m_attack, "primary", shared.m_name, configure); }); return this; } private GearBuilder SecondaryAttack(Action 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 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 ingredients = new List(); 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 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 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 Items { get; private set; } public List Errors { get; private set; } public ItemPackFileResult() { Items = new List(); Errors = new List(); } } 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 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 ?? "") + "' 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 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(); } 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, 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 BuildIngredients(List dtos) { List list = new List(); 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(station, ignoreCase: true, out var result)) { return station; } if (CraftingStationExtensions.TryToPrefabName(result, out var prefabName)) { return prefabName; } validationError = "Invalid CraftingStation value '" + station + "'"; return null; } private static void ApplyPrefabPreparation(CustomItemDefinition definition, ItemPackPrefabPreparationDto dto) { if (dto == null) { return; } PrefabPreparationOptions prefabPreparationOptions = definition.PrefabPreparation ?? new PrefabPreparationOptions(); if (dto.AutoAddItemDrop.HasValue) { prefabPreparationOptions.AutoAddItemDrop = dto.AutoAddItemDrop.Value; if (dto.AutoAddItemDrop.Value) { prefabPreparationOptions.RequireExistingItemDrop = false; } } if (dto.AutoAddPhysics.HasValue) { prefabPreparationOptions.AutoAddPhysics = dto.AutoAddPhysics.Value; } if (dto.WarnOnMissingCollider.HasValue) { prefabPreparationOptions.WarnOnMissingCollider = dto.WarnOnMissingCollider.Value; } if (dto.AllowTextureIconFallback.HasValue) { prefabPreparationOptions.AllowTextureIconFallback = dto.AllowTextureIconFallback.Value; } if (dto.ValidateWearableVisuals.HasValue) { prefabPreparationOptions.ValidateWearableVisuals = dto.ValidateWearableVisuals.Value; } definition.PrefabPreparation = prefabPreparationOptions; } } public sealed class ItemPackParserStatus { public bool YamlAvailable { get; private set; } public string YamlAssemblyVersion { get; private set; } public string YamlAssemblyLocation { get; private set; } public bool JsonAvailable { get; private set; } public string JsonAssemblyVersion { get; private set; } public string JsonAssemblyLocation { get; private set; } internal static ItemPackParserStatus Create() { ItemPackParserStatus itemPackParserStatus = new ItemPackParserStatus(); itemPackParserStatus.Capture("YamlDotNet", yaml: true); itemPackParserStatus.Capture("Newtonsoft.Json", yaml: false); return itemPackParserStatus; } private void Capture(string assemblyName, bool yaml) { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly candidate) => candidate.GetName().Name == assemblyName); if (yaml) { YamlAvailable = assembly != null; YamlAssemblyVersion = assembly?.GetName().Version?.ToString(); YamlAssemblyLocation = assembly?.Location; } else { JsonAvailable = assembly != null; JsonAssemblyVersion = assembly?.GetName().Version?.ToString(); JsonAssemblyLocation = assembly?.Location; } } } public sealed class ItemPackRegistrationError { public string FilePath { get; private set; } public string ItemName { get; private set; } public string Message { get; private set; } public Exception Exception { get; private set; } public ItemPackRegistrationError(string filePath, string itemName, string message, Exception exception = null) { FilePath = filePath; ItemName = itemName; Message = message; Exception = exception; } } internal sealed class JsonItemPackParser : IItemPackParser { private const string AssemblyName = "Newtonsoft.Json"; public string FormatName => "JSON"; public string MissingDependencyMessage => "JSON item packs require ValheimModding-JsonDotNET (Newtonsoft.Json)."; public bool IsAvailable => GetJsonConvertType() != null; public bool CanParse(string filePath) { return string.Equals(Path.GetExtension(filePath), ".json", StringComparison.OrdinalIgnoreCase); } public ItemPackDto Parse(string text) { if (!IsAvailable) { throw new InvalidOperationException(MissingDependencyMessage); } return (ItemPackDto)GetJsonConvertType().GetMethods(BindingFlags.Static | BindingFlags.Public).First((MethodInfo candidate) => candidate.Name == "DeserializeObject" && !candidate.IsGenericMethod && candidate.GetParameters().Length == 2 && candidate.GetParameters()[0].ParameterType == typeof(string) && candidate.GetParameters()[1].ParameterType == typeof(Type)).Invoke(null, new object[2] { text, typeof(ItemPackDto) }); } private static Type GetJsonConvertType() { return FindAssembly("Newtonsoft.Json")?.GetType("Newtonsoft.Json.JsonConvert"); } private static Assembly FindAssembly(string assemblyName) { return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly candidate) => candidate.GetName().Name == assemblyName); } } internal sealed class YamlItemPackParser : IItemPackParser { private const string AssemblyName = "YamlDotNet"; public string FormatName => "YAML"; public string MissingDependencyMessage => "YAML item packs require ValheimModding-YamlDotNet."; public bool IsAvailable => GetBuilderType() != null; public bool CanParse(string filePath) { string extension = Path.GetExtension(filePath); if (!string.Equals(extension, ".yaml", StringComparison.OrdinalIgnoreCase)) { return string.Equals(extension, ".yml", StringComparison.OrdinalIgnoreCase); } return true; } public ItemPackDto Parse(string text) { if (!IsAvailable) { throw new InvalidOperationException(MissingDependencyMessage); } Type builderType = GetBuilderType(); Assembly assembly = FindAssembly("YamlDotNet"); object target = Activator.CreateInstance(builderType); target = InvokeIfAvailable(target, "IgnoreUnmatchedProperties"); target = WithCamelCaseNamingConvention(target, assembly); object obj = builderType.GetMethod("Build", Type.EmptyTypes).Invoke(target, null); MethodInfo methodInfo = FindDeserializeMethod(obj.GetType()); if (methodInfo.IsGenericMethodDefinition) { return (ItemPackDto)methodInfo.MakeGenericMethod(typeof(ItemPackDto)).Invoke(obj, new object[1] { text }); } return (ItemPackDto)methodInfo.Invoke(obj, new object[2] { text, typeof(ItemPackDto) }); } private static object WithCamelCaseNamingConvention(object builder, Assembly assembly) { object obj = (assembly?.GetType("YamlDotNet.Serialization.NamingConventions.CamelCaseNamingConvention"))?.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null, null); if (obj == null) { return builder; } MethodInfo methodInfo = builder.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo candidate) => candidate.Name == "WithNamingConvention" && candidate.GetParameters().Length == 1); if (!(methodInfo == null)) { return methodInfo.Invoke(builder, new object[1] { obj }); } return builder; } private static object InvokeIfAvailable(object target, string methodName) { MethodInfo method = target.GetType().GetMethod(methodName, Type.EmptyTypes); if (!(method == null)) { return method.Invoke(target, null); } return target; } private static MethodInfo FindDeserializeMethod(Type deserializerType) { MethodInfo methodInfo = deserializerType.GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo candidate) => candidate.Name == "Deserialize" && candidate.IsGenericMethodDefinition && candidate.GetParameters().Length == 1 && candidate.GetParameters()[0].ParameterType == typeof(string)); if (methodInfo != null) { return methodInfo; } return deserializerType.GetMethods(BindingFlags.Instance | BindingFlags.Public).First((MethodInfo candidate) => candidate.Name == "Deserialize" && !candidate.IsGenericMethod && candidate.GetParameters().Length == 2 && candidate.GetParameters()[0].ParameterType == typeof(string) && candidate.GetParameters()[1].ParameterType == typeof(Type)); } private static Assembly FindAssembly(string assemblyName) { return AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly candidate) => candidate.GetName().Name == assemblyName); } private static Type GetBuilderType() { return FindAssembly("YamlDotNet")?.GetType("YamlDotNet.Serialization.DeserializerBuilder"); } } internal static class HarmonyPatches { [HarmonyPatch(typeof(ItemDrop), "Awake")] private static class ItemDropAwakePatch { [HarmonyPrefix] private static bool Prefix(ItemDrop __instance) { ZNetView component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || component.GetZDO() == null) { return false; } return true; } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDBCopyOtherDBPatch { [HarmonyPrefix] [HarmonyPriority(0)] private static void Prefix(ObjectDB other) { CustomItemRegistry.FlushLiveRegistrations(other); } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ObjectDB __instance, ObjectDB other) { CustomItemRegistry.FlushLiveRegistrations(__instance); CustomItemRegistry.FlushLiveRegistrations(other); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetSceneAwakePatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ZNetScene __instance) { CustomItemRegistry.FlushLiveRegistrations(null, __instance); } } } [BepInPlugin("com.valheimcustomitemregistry.api", "Custom Item Registry", "0.6.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class CustomItemRegistryPlugin : BaseUnityPlugin { public const string PluginGuid = "com.valheimcustomitemregistry.api"; public const string PluginName = "Custom Item Registry"; public const string PluginVersion = "0.6.2"; private Harmony harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; CustomItemRegistry.SetLogger(((BaseUnityPlugin)this).Logger); harmony = new Harmony("com.valheimcustomitemregistry.api"); harmony.PatchAll(); CustomItemRegistry.LoadItemPacks(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom Item Registry 0.6.2 loaded"); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } CustomItemRegistry.UnloadAssetBundles(); } } public sealed class AmmoTemplateBuilder : TemplateBuilderBase { internal AmmoTemplateBuilder(CustomItemDefinition definition) : base(definition, "Arrow") { definition.ItemType = (ItemType)9; definition.StackSize = definition.StackSize.GetValueOrDefault(100); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(1); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(); definition.TemplateRequiresDamage = true; } public AmmoTemplateBuilder Pierce(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pierce = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pierce = perLevel; return d; }); } public AmmoTemplateBuilder Blunt(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_blunt = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_blunt = perLevel; return d; }); } public AmmoTemplateBuilder Slash(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_slash = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_slash = perLevel; return d; }); } public AmmoTemplateBuilder Fire(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_fire = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_fire = perLevel; return d; }); } public AmmoTemplateBuilder Frost(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_frost = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_frost = perLevel; return d; }); } public AmmoTemplateBuilder Lightning(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_lightning = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_lightning = perLevel; return d; }); } public AmmoTemplateBuilder Poison(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_poison = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_poison = perLevel; return d; }); } public AmmoTemplateBuilder Spirit(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_spirit = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_spirit = perLevel; return d; }); } public AmmoTemplateBuilder NonEquipable(bool value = true) { if (value) { Definition.ItemType = (ItemType)23; } return this; } private AmmoTemplateBuilder DamageWithLevel(float perLevel, Func setDamage, Func setPerLevel) { Damage(setDamage); if (perLevel != 0f) { DamagePerLevel(setPerLevel); } return this; } } public sealed class ArmorTemplateBuilder : TemplateBuilderBase { internal ArmorTemplateBuilder(CustomItemDefinition definition, string templateName, ItemType itemType) : base(definition, templateName) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) definition.ItemType = itemType; definition.StackSize = definition.StackSize.GetValueOrDefault(1); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(4); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(1000f); definition.DurabilityPerLevel = definition.DurabilityPerLevel.GetValueOrDefault(200f); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(true); definition.TemplateRequiresArmor = true; } public ArmorTemplateBuilder Armor(float value, float perLevel = 0f) { Definition.Armor = value; Definition.ArmorPerLevel = perLevel; return this; } public ArmorTemplateBuilder Durability(float value, float perLevel = 0f) { return DurabilityValues(value, perLevel); } public ArmorTemplateBuilder MaxQuality(int value) { return MaxQualityValue(value); } public ArmorTemplateBuilder Repairable(bool value = true) { return RepairableValue(value); } } public sealed class BowTemplateBuilder : TemplateBuilderBase { internal BowTemplateBuilder(CustomItemDefinition definition) : base(definition, "Bow") { definition.ItemType = (ItemType)4; definition.StackSize = definition.StackSize.GetValueOrDefault(1); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(4); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(200f); definition.DurabilityPerLevel = definition.DurabilityPerLevel.GetValueOrDefault(50f); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(true); definition.TemplateRequiresDamage = true; } public BowTemplateBuilder Pierce(float value, float perLevel = 0f) { Damage(delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pierce = value; return d; }); if (perLevel != 0f) { DamagePerLevel(delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pierce = perLevel; return d; }); } return this; } public BowTemplateBuilder Attack(float stamina, float drawDuration = 1f, float drawStaminaDrain = 6f) { PrimaryAttack(delegate(Attack attack) { attack.m_attackStamina = stamina; attack.m_drawDurationMin = drawDuration; attack.m_drawStaminaDrain = drawStaminaDrain; }); return this; } public BowTemplateBuilder Projectile(float velocity, float accuracy = 0f) { PrimaryAttack(delegate(Attack attack) { attack.m_projectileVel = velocity; attack.m_projectileAccuracy = accuracy; }); return this; } public BowTemplateBuilder Durability(float value, float perLevel = 0f) { return DurabilityValues(value, perLevel); } public BowTemplateBuilder MaxQuality(int value) { return MaxQualityValue(value); } public BowTemplateBuilder Repairable(bool value = true) { return RepairableValue(value); } } public sealed class FoodTemplateBuilder : TemplateBuilderBase { internal FoodTemplateBuilder(CustomItemDefinition definition) : base(definition, "Food") { definition.ItemType = (ItemType)2; definition.StackSize = definition.StackSize.GetValueOrDefault(10); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(1); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(); definition.TemplateRequiresFoodStats = true; } public FoodTemplateBuilder Stats(float health, float stamina, float eitr = 0f) { Definition.TemplateHasFoodStats = health > 0f || stamina > 0f || eitr > 0f; Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_food = health; shared.m_foodStamina = stamina; shared.m_foodEitr = eitr; }); return this; } public FoodTemplateBuilder Duration(float seconds) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_foodBurnTime = seconds; }); return this; } public FoodTemplateBuilder Regen(float value) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_foodRegen = value; }); return this; } public FoodTemplateBuilder Drink(bool value = true) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_isDrink = value; }); return this; } } public sealed class MaterialTemplateBuilder : TemplateBuilderBase { internal MaterialTemplateBuilder(CustomItemDefinition definition) : base(definition, "Material") { definition.ItemType = (ItemType)1; definition.StackSize = definition.StackSize.GetValueOrDefault(50); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(1); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(); } public MaterialTemplateBuilder Value(int value) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_value = value; }); return this; } } public sealed class ShieldTemplateBuilder : TemplateBuilderBase { internal ShieldTemplateBuilder(CustomItemDefinition definition) : base(definition, "Shield") { definition.ItemType = (ItemType)5; definition.StackSize = definition.StackSize.GetValueOrDefault(1); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(4); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(200f); definition.DurabilityPerLevel = definition.DurabilityPerLevel.GetValueOrDefault(50f); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(true); definition.TemplateRequiresBlockPower = true; } public ShieldTemplateBuilder Block(float power, float force = 0f, float parry = 1.5f) { Definition.BlockPower = power; Definition.DeflectionForce = force; Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_timedBlockBonus = parry; }); return this; } public ShieldTemplateBuilder Durability(float value, float perLevel = 0f) { return DurabilityValues(value, perLevel); } public ShieldTemplateBuilder MaxQuality(int value) { return MaxQualityValue(value); } public ShieldTemplateBuilder Repairable(bool value = true) { return RepairableValue(value); } } public abstract class TemplateBuilderBase where TBuilder : TemplateBuilderBase { protected readonly CustomItemDefinition Definition; protected TemplateBuilderBase(CustomItemDefinition definition, string templateName) { Definition = definition; Definition.TemplateName = templateName; } public TBuilder Weight(float value) { Definition.Weight = value; return This(); } public TBuilder StackSize(int value) { Definition.StackSize = value; return This(); } public TBuilder Movement(float value) { Definition.MovementModifier = value; return This(); } public TBuilder Teleportable(bool value = true) { Definition.Teleportable = value; return This(); } public TBuilder ConfigureSharedData(Action configure) { if (configure != null) { Definition.SharedDataConfigurators.Add(configure); } return This(); } protected TBuilder DurabilityValues(float value, float perLevel) { Definition.MaxDurability = value; Definition.DurabilityPerLevel = perLevel; return This(); } protected TBuilder MaxQualityValue(int value) { Definition.MaxQuality = value; return This(); } protected TBuilder RepairableValue(bool value) { Definition.CanBeRepaired = value; return This(); } protected TBuilder Damage(Func 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(); } protected TBuilder DamagePerLevel(Func 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(); } protected TBuilder PrimaryAttack(Action configure) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { ConfigureAttack(shared.m_attack, "primary", shared.m_name, configure); }); return This(); } protected TBuilder SecondaryAttack(Action configure) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { ConfigureAttack(shared.m_secondaryAttack, "secondary", shared.m_name, configure); }); return This(); } protected TBuilder This() { return (TBuilder)this; } private static void ConfigureAttack(Attack attack, string label, string itemName, Action configure) { if (attack == null) { throw new CustomItemRegistrationException("Item '" + itemName + "' has no " + label + " attack to configure"); } configure(attack); } } public sealed class ToolTemplateBuilder : TemplateBuilderBase { internal ToolTemplateBuilder(CustomItemDefinition definition) : base(definition, "Tool") { definition.ItemType = (ItemType)19; definition.StackSize = definition.StackSize.GetValueOrDefault(1); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(4); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(200f); definition.DurabilityPerLevel = definition.DurabilityPerLevel.GetValueOrDefault(50f); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(true); } public ToolTemplateBuilder Chop(float value, float perLevel = 0f) { Damage(delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_chop = value; return d; }); if (perLevel != 0f) { DamagePerLevel(delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_chop = perLevel; return d; }); } return this; } public ToolTemplateBuilder Pickaxe(float value, float perLevel = 0f) { Damage(delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pickaxe = value; return d; }); if (perLevel != 0f) { DamagePerLevel(delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pickaxe = perLevel; return d; }); } return this; } public ToolTemplateBuilder ToolTier(int value) { Definition.ToolTier = value; return this; } public ToolTemplateBuilder Attack(float stamina, float force = 0f) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_attackForce = force; }); PrimaryAttack(delegate(Attack attack) { attack.m_attackStamina = stamina; }); return this; } public ToolTemplateBuilder Durability(float value, float perLevel = 0f) { return DurabilityValues(value, perLevel); } public ToolTemplateBuilder MaxQuality(int value) { return MaxQualityValue(value); } public ToolTemplateBuilder Repairable(bool value = true) { return RepairableValue(value); } } public sealed class WeaponTemplateBuilder : TemplateBuilderBase { internal WeaponTemplateBuilder(CustomItemDefinition definition, string templateName, ItemType itemType) : base(definition, templateName) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) definition.ItemType = itemType; definition.StackSize = definition.StackSize.GetValueOrDefault(1); definition.MaxQuality = definition.MaxQuality.GetValueOrDefault(4); definition.MaxDurability = definition.MaxDurability.GetValueOrDefault(200f); definition.DurabilityPerLevel = definition.DurabilityPerLevel.GetValueOrDefault(50f); definition.CanBeRepaired = definition.CanBeRepaired.GetValueOrDefault(true); definition.TemplateRequiresDamage = true; } public WeaponTemplateBuilder Slash(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_slash = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_slash = perLevel; return d; }); } public WeaponTemplateBuilder Blunt(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_blunt = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_blunt = perLevel; return d; }); } public WeaponTemplateBuilder Pierce(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pierce = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pierce = perLevel; return d; }); } public WeaponTemplateBuilder Chop(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_chop = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_chop = perLevel; return d; }); } public WeaponTemplateBuilder Pickaxe(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pickaxe = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_pickaxe = perLevel; return d; }); } public WeaponTemplateBuilder Fire(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_fire = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_fire = perLevel; return d; }); } public WeaponTemplateBuilder Frost(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_frost = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_frost = perLevel; return d; }); } public WeaponTemplateBuilder Lightning(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_lightning = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_lightning = perLevel; return d; }); } public WeaponTemplateBuilder Poison(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_poison = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_poison = perLevel; return d; }); } public WeaponTemplateBuilder Spirit(float value, float perLevel = 0f) { return DamageWithLevel(perLevel, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_spirit = value; return d; }, delegate(DamageTypes d) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) d.m_spirit = perLevel; return d; }); } public WeaponTemplateBuilder Block(float power, float force = 0f, float parry = 1.5f) { Definition.BlockPower = power; Definition.DeflectionForce = force; Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_timedBlockBonus = parry; }); return this; } public WeaponTemplateBuilder Attack(float stamina, float force = 0f, float eitr = 0f) { Definition.SharedDataConfigurators.Add(delegate(SharedData shared) { shared.m_attackForce = force; }); PrimaryAttack(delegate(Attack attack) { attack.m_attackStamina = stamina; attack.m_attackEitr = eitr; }); return this; } public WeaponTemplateBuilder SecondaryAttack(float stamina, float forceMultiplier = 1f, float eitr = 0f) { return SecondaryAttack(delegate(Attack attack) { attack.m_attackStamina = stamina; attack.m_attackEitr = eitr; attack.m_forceMultiplier = forceMultiplier; }); } public WeaponTemplateBuilder Durability(float value, float perLevel = 0f) { return DurabilityValues(value, perLevel); } public WeaponTemplateBuilder MaxQuality(int value) { return MaxQualityValue(value); } public WeaponTemplateBuilder Repairable(bool value = true) { return RepairableValue(value); } public WeaponTemplateBuilder ToolTier(int value) { Definition.ToolTier = value; return this; } private WeaponTemplateBuilder DamageWithLevel(float perLevel, Func setDamage, Func setPerLevel) { Damage(setDamage); if (perLevel != 0f) { DamagePerLevel(setPerLevel); } return this; } } internal static class PrefabPreparationValidationHarness { public static bool SimplePrefabFailsStrictValidation() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown GameObject val = new GameObject("HarnessSimplePrefab"); try { IReadOnlyList addedComponents; IReadOnlyList warnings; string error; return !CustomItemRegistry.PrepareItemPrefabForTest(CustomItemRegistry.Item("HarnessSimpleItem").FromBundle("unused", "HarnessSimplePrefab").AsMaterial() .Build(), val, out addedComponents, out warnings, out error) && error.Contains("ItemDrop") && error.Contains("Rigidbody") && error.Contains("ZNetView") && error.Contains("ZSyncTransform") && error.Contains("Collider"); } finally { Object.DestroyImmediate((Object)(object)val); } } public static bool OptInSimplePrefabGetsItemDropAndPhysics() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown GameObject val = new GameObject("HarnessSimplePrefab"); try { IReadOnlyList addedComponents; IReadOnlyList warnings; string error; return CustomItemRegistry.PrepareItemPrefabForTest(CustomItemRegistry.Item("HarnessSimpleItem").FromBundle("unused", "HarnessSimplePrefab").AsMaterial() .PrefabPreparation(delegate(PrefabPreparationBuilder prep) { prep.AutoAddItemDrop().AutoAddPhysics().WarnOnMissingCollider(); }) .Build(), val, out addedComponents, out warnings, out error) && Object.op_Implicit((Object)(object)val.GetComponent()) && Object.op_Implicit((Object)(object)val.GetComponent()) && Object.op_Implicit((Object)(object)val.GetComponent()) && Object.op_Implicit((Object)(object)val.GetComponent()) && addedComponents.Contains("ItemDrop") && addedComponents.Contains("Rigidbody") && addedComponents.Contains("ZNetView") && addedComponents.Contains("ZSyncTransform") && warnings.Count > 0; } finally { Object.DestroyImmediate((Object)(object)val); } } public static bool RequireItemDropKeepsStrictBehavior() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown GameObject val = new GameObject("HarnessStrictPrefab"); try { IReadOnlyList addedComponents; IReadOnlyList warnings; string error; return !CustomItemRegistry.PrepareItemPrefabForTest(CustomItemRegistry.Item("HarnessStrict").FromBundle("unused", "HarnessStrictPrefab").PrefabPreparation(delegate(PrefabPreparationBuilder prep) { prep.RequireItemDrop(); }) .AsMaterial() .Build(), val, out addedComponents, out warnings, out error) && error.Contains("ItemDrop"); } finally { Object.DestroyImmediate((Object)(object)val); } } public static bool ExistingSharedDataIsPreserved() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown GameObject val = new GameObject("HarnessExistingPrefab"); try { ItemDrop val2 = val.AddComponent(); val2.m_itemData = new ItemData(); val2.m_itemData.m_shared = new SharedData { m_name = "Existing Name", m_description = "Existing Description", m_weight = 9f }; IReadOnlyList addedComponents; IReadOnlyList warnings; string error; return CustomItemRegistry.PrepareItemPrefabForTest(CustomItemRegistry.Item("HarnessExisting").FromBundle("unused", "HarnessExistingPrefab").PrefabPreparation(delegate(PrefabPreparationBuilder prep) { prep.AutoAddPhysics().WarnOnMissingCollider(); }) .Build(), val, out addedComponents, out warnings, out error) && val2.m_itemData.m_shared.m_name == "Existing Name" && val2.m_itemData.m_shared.m_description == "Existing Description" && val2.m_itemData.m_shared.m_weight == 9f; } finally { Object.DestroyImmediate((Object)(object)val); } } } }