using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NoRainDamage")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NoRainDamage")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("65825995-ebff-4e7e-81c3-6254d9832f19")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace NoRainDamage;
[BepInPlugin("uk.co.oliapps.valheim.noraindamage", "No Rain Damage", "1.2.4")]
public class NoRainDamage : BaseUnityPlugin
{
private enum DamageFilter
{
ALL,
INCLUSIVE,
EXCLUSIVE
}
private static ConfigEntry<float> damagePerMinute;
private static ConfigEntry<float> maxRainDamagePercentage;
private static ConfigEntry<DamageFilter> damageFilter;
private static ConfigEntry<string> damageFilterValues;
private static ConfigEntry<bool> modEnabled;
private static Dictionary<int, float> minHealths;
private static float minHealthPercentage;
public void Awake()
{
modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Set whether the mod is enabled");
maxRainDamagePercentage = ((BaseUnityPlugin)this).Config.Bind<float>("Rain Damage", "Max Damage", 0f, "Maximum damage rain can do to uncovered structures between 0.0 and 1.0");
damagePerMinute = ((BaseUnityPlugin)this).Config.Bind<float>("Rain Damage", "Damage Per Minute", 5f, "Damage per minute rain deals to uncovered structures");
damageFilter = ((BaseUnityPlugin)this).Config.Bind<DamageFilter>("Damage Filter", "Filter Type", DamageFilter.ALL, "Set whether everything should be protected (ALL), certain things should be protected (INCLUSIVE) or certain things should not be protected (EXCLUSIVE)");
damageFilterValues = ((BaseUnityPlugin)this).Config.Bind<string>("Damage Filter", "Filter List", "", "If Filter type is INCLUSIVE or EXCLUSIVE, this list of comma-separated values will be used as a filter (will protect or damage if piece name contains value). Piece list included in mod download.");
((BaseUnityPlugin)this).Config.Save();
if (modEnabled.Value)
{
Harmony.CreateAndPatchAll(typeof(NoRainDamage), (string)null);
minHealths = new Dictionary<int, float>();
}
}
[HarmonyPatch(typeof(WearNTear), "Awake")]
[HarmonyPostfix]
public static void WearNTear_Awake(ref WearNTear __instance)
{
minHealthPercentage = 1f - Mathf.Clamp(maxRainDamagePercentage.Value, 0f, 1f);
minHealths.Add(((Object)__instance).GetInstanceID(), __instance.m_health * minHealthPercentage);
}
[HarmonyPatch(typeof(WearNTear), "UpdateWear")]
[HarmonyPrefix]
[HarmonyPriority(0)]
public static bool WearNTear_UpdateWear(ref WearNTear __instance, float time)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
if (OverrideWearNTear(ref __instance))
{
ZNetView val = (ZNetView)AccessTools.Field(typeof(WearNTear), "m_nview").GetValue(__instance);
if ((Object)(object)val == (Object)null || !val.IsValid())
{
return false;
}
bool flag = (bool)AccessTools.Method(typeof(WearNTear), "ShouldUpdate", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { time });
if (val.IsOwner() && flag)
{
if (ZNetScene.instance.OutsideActiveArea(((Component)__instance).transform.position))
{
float num = (float)AccessTools.Method(typeof(WearNTear), "GetMaxSupport", (Type[])null, (Type[])null).Invoke(__instance, new object[0]);
AccessTools.Field(typeof(WearNTear), "m_support").SetValue(__instance, num);
val.GetZDO().Set("support", num);
return false;
}
float num2 = 0f;
bool flag2 = (bool)AccessTools.Method(typeof(WearNTear), "HaveRoof", (Type[])null, (Type[])null).Invoke(__instance, new object[0]);
bool flag3 = EnvMan.IsWet() && !flag2;
if (Object.op_Implicit((Object)(object)__instance.m_wet))
{
__instance.m_wet.SetActive(flag3);
}
if (__instance.m_noRoofWear && (double)__instance.GetHealthPercentage() > (double)minHealthPercentage)
{
bool flag4 = (bool)AccessTools.Method(typeof(WearNTear), "IsUnderWater", (Type[])null, (Type[])null).Invoke(__instance, new object[0]);
float num3 = (float)AccessTools.Field(typeof(WearNTear), "m_rainTimer").GetValue(__instance);
float @float = val.GetZDO().GetFloat("health", __instance.m_health);
if (flag3 || flag4)
{
if ((double)num3 == 0.0)
{
num3 = Time.time;
}
else if ((double)Time.time - (double)num3 > 60.0)
{
num3 = Time.time;
num2 += damagePerMinute.Value;
if (IsTooMuchDamage(ref __instance, @float, num2))
{
float num4 = HowMuchIsTooMuch(ref __instance, @float, num2);
num2 -= num4;
}
}
}
else
{
num3 = 0f;
}
AccessTools.Field(typeof(WearNTear), "m_rainTimer").SetValue(__instance, num3);
}
if (__instance.m_noSupportWear)
{
AccessTools.Method(typeof(WearNTear), "UpdateSupport", (Type[])null, (Type[])null).Invoke(__instance, new object[0]);
if (!(bool)AccessTools.Method(typeof(WearNTear), "HaveSupport", (Type[])null, (Type[])null).Invoke(__instance, new object[0]))
{
num2 = 100f;
}
}
bool flag5 = (bool)AccessTools.Method(typeof(WearNTear), "CanBeRemoved", (Type[])null, (Type[])null).Invoke(__instance, new object[0]);
if ((double)num2 > 0.0 && !flag5)
{
num2 = 0f;
}
if ((double)num2 > 0.0)
{
__instance.ApplyDamage(num2 / 100f * __instance.m_health, (HitData)null);
}
}
AccessTools.Method(typeof(WearNTear), "UpdateVisual", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { true });
return false;
}
return true;
}
private static bool OverrideWearNTear(ref WearNTear instance)
{
if (DamageFilter.ALL.Equals(damageFilter.Value))
{
return true;
}
string[] array = damageFilterValues.Value.Split(new char[1] { ',' });
foreach (string value in array)
{
if (((Object)((Component)instance).gameObject).name.Contains(value))
{
return damageFilter.Value switch
{
DamageFilter.INCLUSIVE => true,
DamageFilter.EXCLUSIVE => false,
_ => true,
};
}
}
return DamageFilter.EXCLUSIVE.Equals(damageFilter.Value);
}
private static bool IsTooMuchDamage(ref WearNTear instance, float health, float damage)
{
return health - damage / 100f * instance.m_health < minHealths[((Object)instance).GetInstanceID()];
}
private static float HowMuchIsTooMuch(ref WearNTear instance, float health, float damage)
{
float num = health - damage / 100f * instance.m_health;
return Mathf.Abs(minHealths[((Object)instance).GetInstanceID()] - num) / instance.m_health * 100f;
}
private static void Log(string message)
{
ZLog.Log((object)("[No Rain Damage] " + message));
}
[HarmonyPatch(typeof(WearNTear), "OnDestroy")]
[HarmonyPostfix]
public static void WearNTear_OnDestroy(ref WearNTear __instance)
{
minHealths.Remove(((Object)__instance).GetInstanceID());
}
}