using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RaincoatMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RaincoatMod")] [assembly: AssemblyTitle("RaincoatMod")] [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 RaincoatMod { [BepInPlugin("yourname.valheim.raincoat", "Raincoat", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class RaincoatMod : BaseUnityPlugin { public const string PluginGUID = "yourname.valheim.raincoat"; public const string PluginName = "Raincoat"; public const string PluginVersion = "1.0.0"; private static readonly Color TintMultiplier = new Color(0.6f, 1.15f, 0.5f, 1f); private const string StatusEffectName = "SE_RainResistant"; private const string TranslationResourceName = "RaincoatMod.English.json"; private static readonly Color NeckSkinTintMultiplier = new Color(0.3f, 0.75f, 0.3f, 1f); private const string NeckSkinIconResourceName = "RaincoatMod.NeckSkin.png"; private static readonly Color NeckTailTintMultiplier = new Color(0.3f, 0.75f, 0.3f, 1f); private const string NeckTailIconResourceName = "RaincoatMod.NeckTail.png"; private const string BodyIconResourceName = "RaincoatMod.RaincoatBody.png"; private const string HoodIconResourceName = "RaincoatMod.RaincoatHood.png"; private static StatusEffect RaincoatStatusEffect; private void Awake() { AddLocalizations(); PrefabManager.OnVanillaPrefabsAvailable += CreateRaincoatSet; Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "yourname.valheim.raincoat"); } private void AddLocalizations() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); try { using Stream stream = executingAssembly.GetManifestResourceStream("RaincoatMod.English.json"); if (stream == null) { string text = string.Join(", ", executingAssembly.GetManifestResourceNames()); Logger.LogError((object)("[Raincoat] Embedded resource 'RaincoatMod.English.json' not found. Resources actually in this DLL: [" + text + "]. Make sure English.json has an entry in the .csproj with LogicalName 'RaincoatMod.English.json'.")); return; } using StreamReader streamReader = new StreamReader(stream); string text2 = streamReader.ReadToEnd(); CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); localization.AddJsonFile("English", text2); Logger.LogInfo((object)"[Raincoat] Loaded translations from embedded resource."); } catch (Exception arg) { Logger.LogError((object)$"[Raincoat] Failed to load/parse embedded translation JSON: {arg}"); } } private static void ExportMeshToObj(string prefabName, string outputPath) { //IL_00ef: 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_00fe: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)("[Raincoat][MeshExport] Could not find prefab '" + prefabName + "'.")); return; } SkinnedMeshRenderer componentInChildren = prefab.GetComponentInChildren(true); Mesh val = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.sharedMesh : null); if ((Object)(object)val == (Object)null) { MeshFilter componentInChildren2 = prefab.GetComponentInChildren(true); val = (((Object)(object)componentInChildren2 != (Object)null) ? componentInChildren2.sharedMesh : null); } if ((Object)(object)val == (Object)null) { Logger.LogError((object)("[Raincoat][MeshExport] No mesh found on '" + prefabName + "' or its children.")); return; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Exported from Valheim prefab '" + prefabName + "' by RaincoatMod"); stringBuilder.AppendLine("o " + prefabName); Vector3[] vertices = val.vertices; Vector3[] array = vertices; foreach (Vector3 val2 in array) { stringBuilder.AppendLine($"v {0f - val2.x} {val2.y} {val2.z}"); } Vector3[] normals = val.normals; Vector3[] array2 = normals; foreach (Vector3 val3 in array2) { stringBuilder.AppendLine($"vn {0f - val3.x} {val3.y} {val3.z}"); } Vector2[] uv = val.uv; Vector2[] array3 = uv; foreach (Vector2 val4 in array3) { stringBuilder.AppendLine($"vt {val4.x} {val4.y}"); } bool hasNormals = normals != null && normals.Length == vertices.Length; bool hasUVs = uv != null && uv.Length == vertices.Length; int[] triangles = val.triangles; for (int l = 0; l < triangles.Length; l += 3) { int idx = triangles[l] + 1; int idx2 = triangles[l + 1] + 1; int idx3 = triangles[l + 2] + 1; stringBuilder.AppendLine("f " + FaceVertex(idx) + " " + FaceVertex(idx3) + " " + FaceVertex(idx2)); } File.WriteAllText(outputPath, stringBuilder.ToString()); Logger.LogInfo((object)$"[Raincoat][MeshExport] Wrote '{prefabName}' ({vertices.Length} verts, {triangles.Length / 3} tris) to: {outputPath}"); string FaceVertex(int num) { return (hasUVs && hasNormals) ? $"{num}/{num}/{num}" : (hasUVs ? $"{num}/{num}" : (hasNormals ? $"{num}//{num}" : $"{num}")); } } catch (Exception arg) { Logger.LogError((object)$"[Raincoat][MeshExport] Failed to export '{prefabName}': {arg}"); } } private void CreateRaincoatSet() { try { CreateStatusEffect(); } catch (Exception arg) { Logger.LogError((object)$"[Raincoat] CreateStatusEffect failed: {arg}"); } try { CreateNeckSkinItem(); AddNeckDropTableEntry(); } catch (Exception arg2) { Logger.LogError((object)$"[Raincoat] Failed to set up Neck Skin: {arg2}"); } try { CloneArmorPiece("CapeTrollHide", "RaincoatBody", "$item_raincoat_body", "$item_raincoat_body_desc", "RaincoatMod.RaincoatBody.png", 5, 2, "piece_workbench", 2); } catch (Exception arg3) { Logger.LogError((object)$"[Raincoat] Failed to register RaincoatBody: {arg3}"); } try { CloneArmorPiece("HelmetTrollLeather", "RaincoatHood", "$item_raincoat_hood", "$item_raincoat_hood_desc", "RaincoatMod.RaincoatHood.png", 3, 1, "piece_workbench", 2); } catch (Exception arg4) { Logger.LogError((object)$"[Raincoat] Failed to register RaincoatHood: {arg4}"); } PrefabManager.OnVanillaPrefabsAvailable -= CreateRaincoatSet; } private void CreateNeckSkinItem() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown GameObject prefab = PrefabManager.Instance.GetPrefab("LeatherScraps"); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)"[Raincoat] Could not find source prefab 'LeatherScraps' for Neck Skin."); return; } GameObject val = PrefabManager.Instance.CreateClonedPrefab("NeckSkin", prefab); Renderer[] componentsInChildren = val.GetComponentsInChildren(true); Renderer[] array = componentsInChildren; foreach (Renderer val2 in array) { Material[] materials = val2.materials; foreach (Material val3 in materials) { if (val3.HasProperty("_Color")) { val3.color *= NeckSkinTintMultiplier; } } } ItemDrop component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Logger.LogError((object)"[Raincoat] Cloned 'NeckSkin' prefab has no ItemDrop component."); return; } SharedData shared = component.m_itemData.m_shared; shared.m_name = "$item_neckskin"; shared.m_description = "$item_neckskin_desc"; if (shared.m_icons != null && shared.m_icons.Length != 0) { Sprite val4 = LoadEmbeddedIconSprite("RaincoatMod.NeckSkin.png", shared.m_icons[0]); Sprite[] array2 = (Sprite[])(object)new Sprite[shared.m_icons.Length]; for (int k = 0; k < array2.Length; k++) { array2[k] = val4; } shared.m_icons = array2; } ItemConfig val5 = new ItemConfig { Amount = 1 }; CustomItem val6 = new CustomItem(val, false, val5); ItemManager.Instance.AddItem(val6); Logger.LogInfo((object)"[Raincoat] Registered NeckSkin item."); } private void AddNeckDropTableEntry() { //IL_007c: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown GameObject prefab = PrefabManager.Instance.GetPrefab("Neck"); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)"[Raincoat] Could not find 'Neck' prefab to add Neck Skin drop."); return; } CharacterDrop component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { Logger.LogError((object)"[Raincoat] 'Neck' prefab has no CharacterDrop component."); return; } GameObject prefab2 = PrefabManager.Instance.GetPrefab("NeckSkin"); if ((Object)(object)prefab2 == (Object)null) { Logger.LogError((object)"[Raincoat] Could not find the newly created 'NeckSkin' prefab to add as a drop."); return; } Drop item = new Drop { m_prefab = prefab2, m_amountMin = 1, m_amountMax = 3, m_chance = 1f, m_onePerPlayer = false, m_levelMultiplier = true }; component.m_drops.Add(item); Logger.LogInfo((object)"[Raincoat] Added NeckSkin to Neck's drop table."); } private static Sprite LoadEmbeddedIconSprite(string resourceName, Sprite referenceSprite) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) Assembly executingAssembly = Assembly.GetExecutingAssembly(); try { using Stream stream = executingAssembly.GetManifestResourceStream(resourceName); if (stream == null) { string text = string.Join(", ", executingAssembly.GetManifestResourceNames()); Logger.LogError((object)("[Raincoat] Embedded icon resource '" + resourceName + "' not found. Resources actually in this DLL: [" + text + "]. Falling back to the original icon.")); return referenceSprite; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); byte[] array = memoryStream.ToArray(); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { Logger.LogError((object)("[Raincoat] Failed to decode embedded icon PNG '" + resourceName + "'. Falling back to the original icon.")); return referenceSprite; } Vector2 val2; if ((Object)(object)referenceSprite != (Object)null) { Rect rect = referenceSprite.rect; if (((Rect)(ref rect)).width > 0f) { rect = referenceSprite.rect; if (((Rect)(ref rect)).height > 0f) { float x = referenceSprite.pivot.x; rect = referenceSprite.rect; float num = x / ((Rect)(ref rect)).width; float y = referenceSprite.pivot.y; rect = referenceSprite.rect; val2 = new Vector2(num, y / ((Rect)(ref rect)).height); goto IL_013b; } } } val2 = new Vector2(0.5f, 0.5f); goto IL_013b; IL_013b: Vector2 val3 = val2; float num2 = (((Object)(object)referenceSprite != (Object)null) ? referenceSprite.pixelsPerUnit : 100f); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), val3, num2); } catch (Exception arg) { Logger.LogError((object)$"[Raincoat] Failed to load embedded icon '{resourceName}': {arg}. Falling back to the original icon."); return referenceSprite; } } private static Requirement[] GetSourceRecipeRequirements(string sourcePrefabName, ItemDrop sourceItemDrop) { if ((Object)(object)sourceItemDrop == (Object)null) { Logger.LogWarning((object)("[Raincoat] sourceItemDrop was null when looking up recipe for '" + sourcePrefabName + "'.")); return null; } Recipe[] array = Resources.FindObjectsOfTypeAll(); Recipe[] array2 = array; foreach (Recipe val in array2) { if ((Object)(object)val != (Object)null && (Object)(object)val.m_item == (Object)(object)sourceItemDrop) { return val.m_resources; } } Logger.LogWarning((object)("[Raincoat] No loaded Recipe found whose m_item is '" + sourcePrefabName + "' " + $"(searched {array.Length} Recipe objects in memory).")); return null; } private void CloneArmorPiece(string sourcePrefabName, string newPrefabName, string displayName, string description, string iconResourceName, int recipeAmount, int recipeAmountPerLevel, string stationName, int stationLevel) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Expected O, but got Unknown GameObject prefab = PrefabManager.Instance.GetPrefab(sourcePrefabName); if ((Object)(object)prefab == (Object)null) { Logger.LogError((object)("[Raincoat] Could not find source prefab '" + sourcePrefabName + "'. Check that the prefab name matches your game version.")); return; } GameObject val = PrefabManager.Instance.CreateClonedPrefab(newPrefabName, prefab); Renderer[] componentsInChildren = val.GetComponentsInChildren(true); Renderer[] array = componentsInChildren; foreach (Renderer val2 in array) { Material[] materials = val2.materials; foreach (Material val3 in materials) { if (val3.HasProperty("_Color")) { val3.color *= TintMultiplier; } } } ItemDrop component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Logger.LogError((object)("[Raincoat] Cloned prefab '" + newPrefabName + "' has no ItemDrop component - source prefab '" + sourcePrefabName + "' may not be a valid item prefab.")); return; } SharedData shared = component.m_itemData.m_shared; shared.m_name = displayName; shared.m_description = description; if (shared.m_icons != null && shared.m_icons.Length != 0) { Sprite val4 = LoadEmbeddedIconSprite(iconResourceName, shared.m_icons[0]); Sprite[] array2 = (Sprite[])(object)new Sprite[shared.m_icons.Length]; for (int k = 0; k < array2.Length; k++) { array2[k] = val4; } shared.m_icons = array2; } shared.m_setName = "$item_set_raincoat"; shared.m_setSize = 2; if ((Object)(object)RaincoatStatusEffect == (Object)null) { Logger.LogWarning((object)("[Raincoat] RaincoatStatusEffect was not created before cloning '" + newPrefabName + "' - set bonus will not have an effect assigned.")); } else { shared.m_setStatusEffect = Object.Instantiate(RaincoatStatusEffect); ((Object)shared.m_setStatusEffect).name = "SE_RainResistant"; } ItemConfig val5 = new ItemConfig { Amount = 1, CraftingStation = stationName, MinStationLevel = stationLevel }; val5.AddRequirement(new RequirementConfig("NeckSkin", recipeAmount, recipeAmountPerLevel, true)); val5.AddRequirement(new RequirementConfig("LeatherScraps", recipeAmount, recipeAmountPerLevel, true)); val5.AddRequirement(new RequirementConfig("TrollHide", recipeAmount, recipeAmountPerLevel, true)); CustomItem val6 = new CustomItem(val, false, val5); ItemManager.Instance.AddItem(val6); Logger.LogInfo((object)("[Raincoat] Registered " + newPrefabName)); } private void CreateStatusEffect() { StatusEffect val = ScriptableObject.CreateInstance(); ((Object)val).name = "SE_RainResistant"; val.m_name = "$se_raincoat_name"; val.m_tooltip = "$se_raincoat_tooltip"; GameObject prefab = PrefabManager.Instance.GetPrefab("CapeTrollHide"); SharedData val2 = ((prefab == null) ? null : prefab.GetComponent()?.m_itemData.m_shared); if (val2 != null && val2.m_icons != null && val2.m_icons.Length != 0) { val.m_icon = LoadEmbeddedIconSprite("RaincoatMod.RaincoatBody.png", val2.m_icons[0]); } RaincoatStatusEffect = val; } } internal static class RaincoatSEUtil { internal static bool HasRaincoatEffect(SEMan seman) { List value = Traverse.Create((object)seman).Field>("m_statusEffects").Value; if (value == null) { return false; } foreach (StatusEffect item in value) { if ((Object)(object)item != (Object)null && ((Object)item).name.StartsWith("SE_RainResistant")) { return true; } } return false; } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float) })] public static class WetBlockPatch { private static bool Prefix(SEMan __instance, StatusEffect statusEffect) { if ((Object)(object)statusEffect == (Object)null) { return true; } if (((Object)statusEffect).name != "Wet") { return true; } if (!RaincoatSEUtil.HasRaincoatEffect(__instance)) { return true; } Character value = Traverse.Create((object)__instance).Field("m_character").Value; if ((Object)(object)value != (Object)null && value.IsSwimming()) { return true; } return false; } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(int), typeof(bool), typeof(int), typeof(float) })] public static class WetBlockByHashPatch { private static bool Prefix(SEMan __instance, int nameHash) { if (nameHash != SEMan.s_statusEffectWet) { return true; } if (!RaincoatSEUtil.HasRaincoatEffect(__instance)) { return true; } Character value = Traverse.Create((object)__instance).Field("m_character").Value; if ((Object)(object)value != (Object)null && value.IsSwimming()) { return true; } return false; } } }