Decompiled source of DualSwords v0.4.1

plugins\DualSwords\DualSwords.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using 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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DualSwords")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DualSwords")]
[assembly: AssemblyTitle("DualSwords")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 DualSwords
{
	[BepInPlugin("sunray.valheim.dualswords", "Dual Swords", "0.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "sunray.valheim.dualswords";

		public const string PluginName = "Dual Swords";

		public const string PluginVersion = "0.4.1";

		private const string BasePrefabName = "AxeEarly";

		private const string TemperedBladesPrefabName = "TemperedBlades";

		private const string MoonlitBladesPrefabName = "MoonlitBlades";

		private const string WispboundBladesPrefabName = "WispboundBlades";

		private const string DuskfallBladesPrefabName = "DuskfallBlades";

		private const string IronSwordPrefabName = "SwordIron";

		private const string BronzeSwordPrefabName = "SwordBronze";

		private const string SilverSwordPrefabName = "SwordSilver";

		private const string MistwalkerPrefabName = "SwordMistwalker";

		private const string NidhoggPrefabName = "SwordNiedhogg";

		private const string AssetBundleFileName = "dualswords";

		private const string ReadableMistwalkerPrefabName = "WispboundMistwalkerReadable";

		private const string ReadableNidhoggPrefabName = "DuskfallNidhoggReadable";

		private AssetBundle _assetBundle;

		private MeshRenderer _readableMistwalkerRenderer;

		private MeshRenderer _readableNidhoggRenderer;

		private void Awake()
		{
			AddLocalizations();
			LoadCustomAssets();
			PrefabManager.OnVanillaPrefabsAvailable += AddDualSwords;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Dual Swords loaded.");
		}

		private void LoadCustomAssets()
		{
			string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Assets", "dualswords");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loading AssetBundle from path: " + text));
			if (!File.Exists(text))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("AssetBundle not found: " + text));
				return;
			}
			FileInfo fileInfo = new FileInfo(text);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"AssetBundle file size: {fileInfo.Length} bytes");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"AssetBundle modified: {fileInfo.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
			_assetBundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)_assetBundle == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to load AssetBundle: " + text));
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"AssetBundle contents:");
			string[] allAssetNames = _assetBundle.GetAllAssetNames();
			foreach (string text2 in allAssetNames)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("- " + text2));
			}
			_readableMistwalkerRenderer = LoadReadableRendererFromBundle("WispboundMistwalkerReadable", required: true);
			_readableNidhoggRenderer = LoadReadableRendererFromBundle("DuskfallNidhoggReadable", required: false);
		}

		private MeshRenderer LoadReadableRendererFromBundle(string prefabName, bool required)
		{
			if ((Object)(object)_assetBundle == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Cannot load readable asset '" + prefabName + "' because AssetBundle is null."));
				return null;
			}
			string prefabNameLower = prefabName.ToLowerInvariant();
			string text = _assetBundle.GetAllAssetNames().FirstOrDefault((string assetName) => assetName.EndsWith("/" + prefabNameLower + ".prefab") || assetName.EndsWith(prefabNameLower + ".prefab"));
			if (string.IsNullOrEmpty(text))
			{
				string text2 = "Could not find asset path for prefab '" + prefabName + "' in AssetBundle.";
				if (required)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)text2);
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)(text2 + " This is OK if the related weapon is not used yet."));
				}
				return null;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loading readable prefab '" + prefabName + "' from AssetBundle path: " + text));
			GameObject val = _assetBundle.LoadAsset<GameObject>(text);
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not load prefab '" + prefabName + "' from AssetBundle path: " + text));
				return null;
			}
			MeshRenderer componentInChildren = val.GetComponentInChildren<MeshRenderer>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Readable prefab '" + prefabName + "' does not contain MeshRenderer."));
				return null;
			}
			MeshFilter component = ((Component)componentInChildren).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Readable prefab '" + prefabName + "' does not contain MeshFilter/sharedMesh."));
				return null;
			}
			Mesh sharedMesh = component.sharedMesh;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded readable asset: " + prefabName + " | Renderer: " + ((Object)componentInChildren).name + " | Mesh: " + ((Object)sharedMesh).name + " | " + $"Readable: {sharedMesh.isReadable} | " + $"Vertices: {sharedMesh.vertexCount} | " + $"SubMeshes: {sharedMesh.subMeshCount} | " + $"Materials: {((Renderer)componentInChildren).sharedMaterials.Length}"));
			return componentInChildren;
		}

		private void AddDualSwords()
		{
			try
			{
				AddTemperedBlades();
				AddMoonlitBlades();
				AddWispboundBlades();
				AddDuskfallBlades();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"DualSwords items registered successfully.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to register DualSwords items: {arg}");
			}
			finally
			{
				PrefabManager.OnVanillaPrefabsAvailable -= AddDualSwords;
			}
		}

		private void AddTemperedBlades()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = "$item_tempered_blades",
				Description = "$item_tempered_blades_desc",
				CraftingStation = CraftingStations.Forge,
				MinStationLevel = 2,
				Amount = 1
			};
			val.AddRequirement("SwordIron", 1, 0);
			val.AddRequirement("SwordBronze", 1, 0);
			val.AddRequirement("Iron", 0, 8);
			val.AddRequirement("Bronze", 0, 2);
			val.AddRequirement("SurtlingCore", 0, 2);
			val.AddRequirement("Chain", 1, 0);
			AddPairedSwordItem("TemperedBlades", val, "$item_tempered_blades", "$item_tempered_blades_desc", "SwordIron", "SwordBronze", "tempered_duals_icon.png", 55f, 6f, 0f, 0f, 0f, 0f, 10f, 20f, 175f, 50f);
		}

		private void AddMoonlitBlades()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = "$item_moonlit_blades",
				Description = "$item_moonlit_blades_desc",
				CraftingStation = CraftingStations.Forge,
				MinStationLevel = 3,
				Amount = 1
			};
			val.AddRequirement("SwordSilver", 1, 0);
			val.AddRequirement("SwordIron", 1, 0);
			val.AddRequirement("Silver", 0, 8);
			val.AddRequirement("Iron", 0, 2);
			val.AddRequirement("Crystal", 0, 4);
			val.AddRequirement("SurtlingCore", 0, 1);
			val.AddRequirement("Chain", 1, 0);
			AddPairedSwordItem("MoonlitBlades", val, "$item_moonlit_blades", "$item_moonlit_blades_desc", "SwordSilver", "SwordIron", "moonlit_duals_icon.png", 75f, 6f, 0f, 0f, 25f, 5f, 12f, 24f, 200f, 50f);
		}

		private void AddWispboundBlades()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = "$item_wispbound_blades",
				Description = "$item_wispbound_blades_desc",
				CraftingStation = CraftingStations.BlackForge,
				MinStationLevel = 1,
				Amount = 1
			};
			val.AddRequirement("SwordMistwalker", 1, 0);
			val.AddRequirement("SwordSilver", 1, 0);
			val.AddRequirement("Iron", 0, 4);
			val.AddRequirement("Silver", 0, 2);
			val.AddRequirement("Eitr", 0, 4);
			val.AddRequirement("Wisp", 10, 4);
			AddPairedSwordItem("WispboundBlades", val, "$item_wispbound_blades", "$item_wispbound_blades_desc", "SwordMistwalker", "SwordSilver", "wispbound_duals_icon.png", 120f, 6f, 40f, 6f, 20f, 6f, 15f, 30f, 225f, 50f);
		}

		private void AddDuskfallBlades()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = "$item_duskfall_blades",
				Description = "$item_duskfall_blades_desc",
				CraftingStation = CraftingStations.BlackForge,
				MinStationLevel = 1,
				Amount = 1
			};
			val.AddRequirement("SwordNiedhogg", 1, 0);
			val.AddRequirement("SwordMistwalker", 1, 0);
			val.AddRequirement("FlametalNew", 0, 8);
			val.AddRequirement("Iron", 0, 2);
			val.AddRequirement("SulfurStone", 0, 4);
			val.AddRequirement("Eitr", 0, 1);
			val.AddRequirement("MoltenCore", 1, 0);
			AddPairedSwordItem("DuskfallBlades", val, "$item_duskfall_blades", "$item_duskfall_blades_desc", "SwordNiedhogg", "SwordMistwalker", "duskfall_duals_icon.png", 155f, 7f, 45f, 6f, 0f, 0f, 18f, 36f, 250f, 50f);
		}

		private void AddPairedSwordItem(string prefabName, ItemConfig config, string nameToken, string descriptionToken, string rightSwordPrefabName, string leftSwordPrefabName, string iconFileName, float slashDamage, float slashDamagePerLevel, float frostDamage, float frostDamagePerLevel, float spiritDamage, float spiritDamagePerLevel, float primaryAttackStamina, float secondaryAttackStamina, float maxDurability, float durabilityPerLevel)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			try
			{
				CustomItem val = new CustomItem(prefabName, "AxeEarly", config);
				SharedData shared = val.ItemDrop.m_itemData.m_shared;
				ConfigureStats(shared, nameToken, descriptionToken, slashDamage, slashDamagePerLevel, frostDamage, frostDamagePerLevel, spiritDamage, spiritDamagePerLevel, maxDurability, durabilityPerLevel);
				ConfigureAttackStamina(shared, primaryAttackStamina, secondaryAttackStamina);
				CopyAttackEffectsFromSource(shared, rightSwordPrefabName);
				ConfigureIcon(shared, iconFileName);
				bool num = ReplaceDefaultAxeMeshesWithSwordMeshes(val.ItemPrefab, rightSwordPrefabName, leftSwordPrefabName);
				bool flag = ReplaceEquippedSkinnedMeshWithDualSwordMesh(val.ItemPrefab, rightSwordPrefabName, leftSwordPrefabName);
				if (!num || !flag)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)(prefabName + " was not registered because its visuals could not be prepared."));
					return;
				}
				ItemManager.Instance.AddItem(val);
				((BaseUnityPlugin)this).Logger.LogInfo((object)(prefabName + " registered successfully."));
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to register {prefabName}: {arg}");
			}
		}

		private static void ConfigureStats(SharedData shared, string nameToken, string descriptionToken, float slashDamage, float slashDamagePerLevel, float frostDamage, float frostDamagePerLevel, float spiritDamage, float spiritDamagePerLevel, float maxDurability, float durabilityPerLevel)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			shared.m_name = nameToken;
			shared.m_description = descriptionToken;
			shared.m_skillType = (SkillType)1;
			shared.m_damages = new DamageTypes
			{
				m_slash = slashDamage,
				m_chop = 0f,
				m_blunt = 0f,
				m_pierce = 0f,
				m_fire = 0f,
				m_frost = frostDamage,
				m_lightning = 0f,
				m_poison = 0f,
				m_spirit = spiritDamage
			};
			shared.m_damagesPerLevel = new DamageTypes
			{
				m_slash = slashDamagePerLevel,
				m_frost = frostDamagePerLevel,
				m_spirit = spiritDamagePerLevel
			};
			shared.m_maxQuality = 4;
			shared.m_maxDurability = maxDurability;
			shared.m_durabilityPerLevel = durabilityPerLevel;
			shared.m_attackForce = 35f;
			shared.m_backstabBonus = 2f;
		}

		private static void ConfigureAttackStamina(SharedData shared, float primaryAttackStamina, float secondaryAttackStamina)
		{
			if (shared.m_attack != null)
			{
				shared.m_attack.m_attackStamina = primaryAttackStamina;
			}
			if (shared.m_secondaryAttack != null)
			{
				shared.m_secondaryAttack.m_attackStamina = secondaryAttackStamina;
			}
		}

		private void CopyAttackEffectsFromSource(SharedData targetShared, string sourcePrefabName)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(sourcePrefabName);
			if ((Object)(object)prefab == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find source item prefab for effects: " + sourcePrefabName));
				return;
			}
			ItemDrop component = prefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Source prefab " + sourcePrefabName + " has no ItemDrop."));
				return;
			}
			SharedData shared = component.m_itemData.m_shared;
			CopyAttackEffects(shared.m_attack, targetShared.m_attack);
			CopyAttackEffects(shared.m_secondaryAttack, targetShared.m_secondaryAttack);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Copied attack SFX/VFX from " + sourcePrefabName + "."));
		}

		private void CopyAttackEffects(Attack sourceAttack, Attack targetAttack)
		{
			if (sourceAttack != null && targetAttack != null)
			{
				targetAttack.m_startEffect = CloneEffectList(sourceAttack.m_startEffect);
				targetAttack.m_triggerEffect = CloneEffectList(sourceAttack.m_triggerEffect);
				targetAttack.m_hitEffect = CloneEffectList(sourceAttack.m_hitEffect);
				targetAttack.m_hitTerrainEffect = CloneEffectList(sourceAttack.m_hitTerrainEffect);
				targetAttack.m_attackStartNoise = sourceAttack.m_attackStartNoise;
				targetAttack.m_attackHitNoise = sourceAttack.m_attackHitNoise;
			}
		}

		private EffectList CloneEffectList(EffectList source)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			EffectList val = new EffectList();
			if (source == null || source.m_effectPrefabs == null)
			{
				val.m_effectPrefabs = Array.Empty<EffectData>();
				return val;
			}
			val.m_effectPrefabs = source.m_effectPrefabs.ToArray();
			return val;
		}

		private void ConfigureIcon(SharedData shared, string iconFileName)
		{
			string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Assets", iconFileName);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Trying to load item icon from: " + text));
			Sprite val = AssetUtils.LoadSpriteFromFile(text);
			if ((Object)(object)val != (Object)null)
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { val };
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Custom item icon loaded successfully: " + iconFileName));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Custom item icon failed to load from: " + text));
			}
		}

		private Mesh CreateDualSwordMeshWeightedToHands(Mesh rightSourceMesh, Mesh leftSourceMesh, SkinnedMeshRenderer targetRenderer, int rightHandBoneIndex, int leftHandBoneIndex, float rightScale, Vector3 rightOffset, Quaternion rightRotation, float leftScale, Vector3 leftOffset, Quaternion leftRotation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = new Mesh();
			((Object)val).name = "DualSwords_RightLeft";
			List<Vector3> list = new List<Vector3>();
			List<Vector3> list2 = new List<Vector3>();
			List<Vector2> list3 = new List<Vector2>();
			List<BoneWeight> list4 = new List<BoneWeight>();
			List<int> list5 = new List<int>();
			List<int> list6 = new List<int>();
			AddSwordMeshPart(rightSourceMesh, targetRenderer, rightHandBoneIndex, rightScale, rightOffset, rightRotation, list, list2, list3, list4, list5);
			AddSwordMeshPart(leftSourceMesh, targetRenderer, leftHandBoneIndex, leftScale, leftOffset, leftRotation, list, list2, list3, list4, list6);
			val.SetVertices(list);
			if (list2.Count == list.Count)
			{
				val.SetNormals(list2);
			}
			if (list3.Count == list.Count)
			{
				val.SetUVs(0, list3);
			}
			val.boneWeights = list4.ToArray();
			Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[targetRenderer.bones.Length];
			for (int i = 0; i < targetRenderer.bones.Length; i++)
			{
				array[i] = targetRenderer.bones[i].worldToLocalMatrix * ((Component)targetRenderer).transform.localToWorldMatrix;
			}
			val.bindposes = array;
			val.subMeshCount = 2;
			val.SetTriangles(list5, 0);
			val.SetTriangles(list6, 1);
			val.RecalculateBounds();
			if (list2.Count != list.Count)
			{
				val.RecalculateNormals();
			}
			return val;
		}

		private void AddSwordMeshPart(Mesh sourceMesh, SkinnedMeshRenderer targetRenderer, int boneIndex, float scale, Vector3 localOffsetFromBone, Quaternion localRotationFromBone, List<Vector3> vertices, List<Vector3> normals, List<Vector2> uvs, List<BoneWeight> boneWeights, List<int> triangles)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			Transform val = targetRenderer.bones[boneIndex];
			if (!sourceMesh.isReadable)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Skipping unreadable source mesh in skinned mesh build: " + ((Object)sourceMesh).name + "."));
				return;
			}
			int count = vertices.Count;
			Vector3[] vertices2 = sourceMesh.vertices;
			Vector3[] normals2 = sourceMesh.normals;
			Vector2[] uv = sourceMesh.uv;
			for (int i = 0; i < vertices2.Length; i++)
			{
				Vector3 val2 = localRotationFromBone * (vertices2[i] * scale) + localOffsetFromBone;
				Vector3 val3 = val.TransformPoint(val2);
				Vector3 item = ((Component)targetRenderer).transform.InverseTransformPoint(val3);
				vertices.Add(item);
				if (normals2 != null && normals2.Length == vertices2.Length)
				{
					Vector3 val4 = localRotationFromBone * normals2[i];
					Vector3 val5 = val.TransformDirection(val4);
					Vector3 val6 = ((Component)targetRenderer).transform.InverseTransformDirection(val5);
					normals.Add(((Vector3)(ref val6)).normalized);
				}
				if (uv != null && uv.Length == vertices2.Length)
				{
					uvs.Add(uv[i]);
				}
				else
				{
					uvs.Add(Vector2.zero);
				}
				BoneWeight item2 = default(BoneWeight);
				((BoneWeight)(ref item2)).boneIndex0 = boneIndex;
				((BoneWeight)(ref item2)).weight0 = 1f;
				((BoneWeight)(ref item2)).boneIndex1 = 0;
				((BoneWeight)(ref item2)).weight1 = 0f;
				((BoneWeight)(ref item2)).boneIndex2 = 0;
				((BoneWeight)(ref item2)).weight2 = 0f;
				((BoneWeight)(ref item2)).boneIndex3 = 0;
				((BoneWeight)(ref item2)).weight3 = 0f;
				boneWeights.Add(item2);
			}
			for (int j = 0; j < sourceMesh.subMeshCount; j++)
			{
				int[] triangles2 = sourceMesh.GetTriangles(j);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Adding triangles from source mesh " + ((Object)sourceMesh).name + " | " + $"subMesh: {j} | " + $"triangles: {triangles2.Length}"));
				for (int k = 0; k < triangles2.Length; k++)
				{
					triangles.Add(count + triangles2[k]);
				}
			}
		}

		private MeshRenderer GetReadableHandRendererIfAvailable(string prefabName, MeshRenderer vanillaRenderer, string handLabel)
		{
			if (prefabName == "SwordMistwalker")
			{
				if ((Object)(object)_readableMistwalkerRenderer == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Readable Mistwalker asset is not loaded. Cannot build " + handLabel + "-hand mesh."));
					return null;
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Using readable Mistwalker asset for in-hand " + handLabel + " sword mesh."));
				return _readableMistwalkerRenderer;
			}
			if (prefabName == "SwordNiedhogg" && (Object)(object)_readableNidhoggRenderer != (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Using readable Nidhögg asset for in-hand " + handLabel + " sword mesh."));
				return _readableNidhoggRenderer;
			}
			return vanillaRenderer;
		}

		private bool ReplaceEquippedSkinnedMeshWithDualSwordMesh(GameObject dualSwordsPrefab, string rightSwordPrefabName, string leftSwordPrefabName)
		{
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab(rightSwordPrefabName);
			GameObject prefab2 = PrefabManager.Instance.GetPrefab(leftSwordPrefabName);
			if ((Object)(object)prefab == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find prefab " + rightSwordPrefabName + "."));
				return false;
			}
			if ((Object)(object)prefab2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find prefab " + leftSwordPrefabName + "."));
				return false;
			}
			MeshRenderer swordMeshRenderer = GetSwordMeshRenderer(prefab);
			MeshRenderer swordMeshRenderer2 = GetSwordMeshRenderer(prefab2);
			if ((Object)(object)swordMeshRenderer == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find MeshRenderer for " + rightSwordPrefabName + "."));
				return false;
			}
			if ((Object)(object)swordMeshRenderer2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find MeshRenderer for " + leftSwordPrefabName + "."));
				return false;
			}
			MeshRenderer readableHandRendererIfAvailable = GetReadableHandRendererIfAvailable(rightSwordPrefabName, swordMeshRenderer, "right");
			MeshRenderer readableHandRendererIfAvailable2 = GetReadableHandRendererIfAvailable(leftSwordPrefabName, swordMeshRenderer2, "left");
			if ((Object)(object)readableHandRendererIfAvailable == (Object)null || (Object)(object)readableHandRendererIfAvailable2 == (Object)null)
			{
				return false;
			}
			MeshFilter component = ((Component)readableHandRendererIfAvailable).GetComponent<MeshFilter>();
			MeshFilter component2 = ((Component)readableHandRendererIfAvailable2).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(rightSwordPrefabName + " renderer has no MeshFilter/sharedMesh."));
				return false;
			}
			if ((Object)(object)component2 == (Object)null || (Object)(object)component2.sharedMesh == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(leftSwordPrefabName + " renderer has no MeshFilter/sharedMesh."));
				return false;
			}
			Transform val = dualSwordsPrefab.transform.Find("attach_skin/berzerkr/Berzerkr");
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find attach_skin/berzerkr/Berzerkr.");
				return false;
			}
			SkinnedMeshRenderer component3 = ((Component)val).GetComponent<SkinnedMeshRenderer>();
			if ((Object)(object)component3 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Berzerkr object has no SkinnedMeshRenderer.");
				return false;
			}
			int num = FindBoneIndex(component3, "RightHand");
			int num2 = FindBoneIndex(component3, "LeftHand");
			if (num < 0 || num2 < 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Cannot create dual swords because RightHand or LeftHand bone was not found.");
				return false;
			}
			if (!component.sharedMesh.isReadable)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(rightSwordPrefabName + " mesh '" + ((Object)component.sharedMesh).name + "' is not readable. Cannot build in-hand SkinnedMeshRenderer from this mesh. Use a readable custom asset for this weapon."));
				return false;
			}
			if (!component2.sharedMesh.isReadable)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(leftSwordPrefabName + " mesh '" + ((Object)component2.sharedMesh).name + "' is not readable. Cannot build in-hand SkinnedMeshRenderer from this mesh. Use a readable custom asset for this weapon."));
				return false;
			}
			float rightScale = ((rightSwordPrefabName == "SwordMistwalker" || rightSwordPrefabName == "SwordNiedhogg") ? 0.009f : 0.003f);
			Vector3 rightOffset = ((rightSwordPrefabName == "SwordMistwalker") ? new Vector3(0.0012f, 0.0012f, 0.0004f) : ((rightSwordPrefabName == "SwordNiedhogg") ? new Vector3(0.0016f, 0.0011f, 0.0006f) : new Vector3(0f, 0.0012f, 0.0001f)));
			Quaternion rightRotation = ((rightSwordPrefabName == "SwordMistwalker") ? Quaternion.Euler(0f, -8f, 96f) : ((rightSwordPrefabName == "SwordNiedhogg") ? Quaternion.Euler(5f, -6f, 90f) : Quaternion.Euler(0f, 10f, 93f)));
			float leftScale = ((leftSwordPrefabName == "SwordMistwalker" || leftSwordPrefabName == "SwordNiedhogg") ? 0.009f : 0.003f);
			Vector3 leftOffset = ((leftSwordPrefabName == "SwordMistwalker") ? new Vector3(-0.0012f, 0.0012f, 0.0004f) : ((leftSwordPrefabName == "SwordNiedhogg") ? new Vector3(-0.0012f, 0.0012f, 0.0004f) : new Vector3(0f, 0.0012f, 0.0001f)));
			Quaternion leftRotation = ((leftSwordPrefabName == "SwordMistwalker") ? Quaternion.Euler(0f, 8f, -96f) : ((leftSwordPrefabName == "SwordNiedhogg") ? Quaternion.Euler(0f, 8f, -96f) : Quaternion.Euler(0f, -10f, -93f)));
			Mesh sharedMesh = CreateDualSwordMeshWeightedToHands(component.sharedMesh, component2.sharedMesh, component3, num, num2, rightScale, rightOffset, rightRotation, leftScale, leftOffset, leftRotation);
			component3.sharedMesh = sharedMesh;
			Material firstUsableMaterial = GetFirstUsableMaterial((Renderer)(object)swordMeshRenderer);
			Material firstUsableMaterial2 = GetFirstUsableMaterial((Renderer)(object)swordMeshRenderer2);
			((Renderer)component3).sharedMaterials = (Material[])(object)new Material[2] { firstUsableMaterial, firstUsableMaterial2 };
			((Renderer)component3).localBounds = new Bounds(Vector3.zero, Vector3.one * 100f);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Replaced equipped mesh with " + ((Object)readableHandRendererIfAvailable).name + " in right hand and " + leftSwordPrefabName + " in left hand."));
			return true;
		}

		private Material GetFirstUsableMaterial(Renderer renderer)
		{
			Material[] sharedMaterials = renderer.sharedMaterials;
			foreach (Material val in sharedMaterials)
			{
				if ((Object)(object)val != (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Selected material for " + GetPath(((Component)renderer).transform) + ": " + ((Object)val).name));
					return val;
				}
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)("No usable material found for " + GetPath(((Component)renderer).transform) + "."));
			return null;
		}

		private int FindBoneIndex(SkinnedMeshRenderer renderer, string boneName)
		{
			for (int i = 0; i < renderer.bones.Length; i++)
			{
				if ((Object)(object)renderer.bones[i] != (Object)null && ((Object)renderer.bones[i]).name == boneName)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"Found bone {boneName} at index {i}: {GetPath(renderer.bones[i])}");
					return i;
				}
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Bone " + boneName + " not found. Available bones:"));
			for (int j = 0; j < renderer.bones.Length; j++)
			{
				if ((Object)(object)renderer.bones[j] != (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)$"Bone[{j}]: {((Object)renderer.bones[j]).name} | {GetPath(renderer.bones[j])}");
				}
			}
			return -1;
		}

		private bool ReplaceDefaultAxeMeshesWithSwordMeshes(GameObject dualSwordsPrefab, string rightSwordPrefabName, string leftSwordPrefabName)
		{
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab(rightSwordPrefabName);
			GameObject prefab2 = PrefabManager.Instance.GetPrefab(leftSwordPrefabName);
			if ((Object)(object)prefab == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find prefab " + rightSwordPrefabName + "."));
				return false;
			}
			if ((Object)(object)prefab2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find prefab " + leftSwordPrefabName + "."));
				return false;
			}
			MeshRenderer swordMeshRenderer = GetSwordMeshRenderer(prefab);
			MeshRenderer swordMeshRenderer2 = GetSwordMeshRenderer(prefab2);
			if ((Object)(object)swordMeshRenderer == (Object)null || (Object)(object)swordMeshRenderer2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find source sword renderers for " + rightSwordPrefabName + " / " + leftSwordPrefabName + "."));
				return false;
			}
			Transform val = dualSwordsPrefab.transform.Find("attach");
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find " + ((Object)dualSwordsPrefab).name + "/attach."));
				return false;
			}
			MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshRenderer>(true);
			if (componentsInChildren.Length < 2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"Expected 2 target renderers under attach, found {componentsInChildren.Length}.");
				return false;
			}
			ApplyStaticMeshToRenderer(componentsInChildren[0], swordMeshRenderer);
			ApplyStaticMeshToRenderer(componentsInChildren[1], swordMeshRenderer2);
			float localScale = ((rightSwordPrefabName == "SwordMistwalker" || rightSwordPrefabName == "SwordNiedhogg") ? 0.75f : 0.28f);
			float localScale2 = ((leftSwordPrefabName == "SwordMistwalker" || leftSwordPrefabName == "SwordNiedhogg") ? 0.75f : 0.28f);
			ConfigureDroppedSwordTransform(componentsInChildren[0], new Vector3(-0.25f, -0.03f, 0.45f), new Vector3(75f, 180f, 30f), localScale);
			ConfigureDroppedSwordTransform(componentsInChildren[1], new Vector3(0.2f, 0.06f, 0.35f), new Vector3(90f, 180f, -30f), localScale2);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Default axe meshes replaced with " + rightSwordPrefabName + " + " + leftSwordPrefabName + " meshes."));
			return true;
		}

		private MeshRenderer GetSwordMeshRenderer(GameObject weaponPrefab)
		{
			MeshRenderer[] componentsInChildren = weaponPrefab.GetComponentsInChildren<MeshRenderer>(true);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("--- MeshRenderer candidates for " + ((Object)weaponPrefab).name + " ---"));
			MeshRenderer[] array = componentsInChildren;
			foreach (MeshRenderer val in array)
			{
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				int num = (((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) ? component.sharedMesh.vertexCount : 0);
				int num2 = (((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) ? component.sharedMesh.subMeshCount : 0);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Candidate: " + GetPath(((Component)val).transform) + " | RendererName: " + ((Object)((Component)val).gameObject).name + " | Mesh: " + (((Object)(object)((component != null) ? component.sharedMesh : null) != (Object)null) ? ((Object)component.sharedMesh).name : "null") + " | " + $"Vertices: {num} | " + $"SubMeshes: {num2} | " + $"Materials: {((Renderer)val).sharedMaterials.Length}"));
			}
			MeshRenderer val2 = (from renderer in componentsInChildren.Where(delegate(MeshRenderer renderer)
				{
					MeshFilter component3 = ((Component)renderer).GetComponent<MeshFilter>();
					return (Object)(object)component3 != (Object)null && (Object)(object)component3.sharedMesh != (Object)null && component3.sharedMesh.vertexCount > 0;
				})
				orderby ((Component)renderer).GetComponent<MeshFilter>().sharedMesh.vertexCount descending
				select renderer).FirstOrDefault();
			if ((Object)(object)val2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find usable MeshRenderer for " + ((Object)weaponPrefab).name + "."));
				return null;
			}
			MeshFilter component2 = ((Component)val2).GetComponent<MeshFilter>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Selected MeshRenderer for " + ((Object)weaponPrefab).name + ": " + GetPath(((Component)val2).transform) + " | Mesh: " + ((Object)component2.sharedMesh).name + " | " + $"Vertices: {component2.sharedMesh.vertexCount} | " + $"SubMeshes: {component2.sharedMesh.subMeshCount} | " + $"Materials: {((Renderer)val2).sharedMaterials.Length}"));
			return val2;
		}

		private void ConfigureDroppedSwordTransform(MeshRenderer renderer, Vector3 localPosition, Vector3 localRotationEuler, float localScale)
		{
			//IL_0006: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			((Component)renderer).transform.localPosition = localPosition;
			((Component)renderer).transform.localRotation = Quaternion.Euler(localRotationEuler);
			((Component)renderer).transform.localScale = Vector3.one * localScale;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Configured dropped sword transform: " + GetPath(((Component)renderer).transform) + " | " + $"Pos: {localPosition} | Rot: {localRotationEuler} | Scale: {localScale}"));
		}

		private void ApplyStaticMeshToRenderer(MeshRenderer targetRenderer, MeshRenderer sourceRenderer)
		{
			MeshFilter component = ((Component)sourceRenderer).GetComponent<MeshFilter>();
			MeshFilter component2 = ((Component)targetRenderer).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Source renderer " + GetPath(((Component)sourceRenderer).transform) + " has no MeshFilter/sharedMesh."));
				return;
			}
			if ((Object)(object)component2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Target renderer " + GetPath(((Component)targetRenderer).transform) + " has no MeshFilter."));
				return;
			}
			component2.sharedMesh = component.sharedMesh;
			((Renderer)targetRenderer).sharedMaterials = ((Renderer)sourceRenderer).sharedMaterials;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied " + ((Object)sourceRenderer).name + " mesh to " + GetPath(((Component)targetRenderer).transform) + "."));
		}

		private static string GetPath(Transform transform)
		{
			if ((Object)(object)transform.parent == (Object)null)
			{
				return ((Object)transform).name;
			}
			return GetPath(transform.parent) + "/" + ((Object)transform).name;
		}

		private void AddLocalizations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "item_tempered_blades", "Tempered Blades" },
				{ "item_tempered_blades_desc", "A paired weapon forged from bronze and iron. Uneven in origin, yet balanced by careful tempering." },
				{ "item_moonlit_blades", "Moonlit Blades" },
				{ "item_moonlit_blades_desc", "A paired weapon of silver and iron. The moonlit gleam of these blades is deadly to the undead." },
				{ "item_wispbound_blades", "Wispbound Blades" },
				{ "item_wispbound_blades_desc", "Paired blades bound by chilling glow. Their pale edge cuts through mist and darkness alike." },
				{ "item_duskfall_blades", "Duskfall Blades" },
				{ "item_duskfall_blades_desc", "Paired blades of ash and mist. Dark edge and the pale frost move as one." }
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "item_tempered_blades", "Закалённые клинки" },
				{ "item_tempered_blades_desc", "Парное оружие, выкованное из бронзы и железа. Разное по происхождению, но сбалансированное тщательной закалкой." },
				{ "item_moonlit_blades", "Лунные клинки" },
				{ "item_moonlit_blades_desc", "Парное оружие из серебра и железа. Лунный блеск этих клинков губителен для нежити." },
				{ "item_wispbound_blades", "Мерцающие клинки" },
				{ "item_wispbound_blades_desc", "Парные клинки, связанные холодным мерцанием. Их бледные лезвия рассекают как туман, так и тьму." },
				{ "item_duskfall_blades", "Клинки сумеречной мглы" },
				{ "item_duskfall_blades_desc", "Парные клинки, связанные пеплом и мглой. Тёмное лезвие и бледный мороз движутся как одно целое." }
			});
		}
	}
}