Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DeepNorthHotSprings v1.0.1
DeepNorthStructures.dll
Decompiled 6 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("igentuman")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Enables Valheim's vanilla Deep North Hot Springs and adds their restorative pool effects.")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+219718f651790ec01c9ed8fa9a9580ec0e93939c")] [assembly: AssemblyProduct("DeepNorthStructures")] [assembly: AssemblyTitle("DeepNorthStructures")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 DeepNorthStructures { internal sealed class HotSpringArea : MonoBehaviour { private static readonly HashSet<HotSpringArea> Instances = new HashSet<HotSpringArea>(); private WaterVolume[] _waterVolumes = Array.Empty<WaterVolume>(); private float _radius = 15f; internal void Initialize(float locationRadius) { _radius = Mathf.Clamp(locationRadius, 6f, 30f); _waterVolumes = ((Component)this).GetComponentsInChildren<WaterVolume>(true); } private void OnEnable() { Instances.Add(this); } private void OnDisable() { Instances.Remove(this); } internal static bool Contains(Player player) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (!((Character)player).InWater()) { return false; } Vector3 position = ((Component)player).transform.position; foreach (HotSpringArea instance in Instances) { if ((Object)(object)instance != (Object)null && instance.Contains(position)) { return true; } } return false; } private bool Contains(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) //IL_0091: Unknown result type (might be due to invalid IL or missing references) Vector3 val = position - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > _radius * _radius) { return false; } if (_waterVolumes.Length == 0) { return true; } WaterVolume[] waterVolumes = _waterVolumes; foreach (WaterVolume val2 in waterVolumes) { if ((Object)(object)val2 == (Object)null) { continue; } Collider component = ((Component)val2).GetComponent<Collider>(); if (!((Object)(object)component == (Object)null)) { Bounds bounds = component.bounds; ((Bounds)(ref bounds)).Expand(new Vector3(1f, 2f, 1f)); if (((Bounds)(ref bounds)).Contains(position)) { return true; } } } return false; } } [BepInPlugin("com.igentuman.deepnorthstructures", "Deep North Hot Springs", "1.0.1")] public sealed class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(ZoneSystem), "SetupLocations")] private static class SetupLocationsPatch { private static void Prefix() { int num = 0; HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (LocationList allLocationList in LocationList.GetAllLocationLists()) { foreach (ZoneLocation location in allLocationList.m_locations) { if (!location.m_prefab.IsValid) { continue; } string name = location.m_prefab.Name; if (name == "TheDarkestHole") { location.m_enable = false; } else if (IsHotSpring(name)) { hashSet.Add(name); if (!location.m_enable) { location.m_enable = true; num++; } } } } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)$"Hot Spring location setup: found {hashSet.Count}/3 prefabs; enabled {num}"); foreach (string hotSpringPrefab in HotSpringPrefabs) { if (!hashSet.Contains(hotSpringPrefab)) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)(hotSpringPrefab + " was not found. The current Valheim build may have renamed or removed it.")); } } } } [HarmonyPatch(typeof(ZoneSystem), "Load")] private static class LoadLocationsPatch { private static void Postfix(ZoneSystem __instance) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && __instance.LocationsGenerated) { ((MonoBehaviour)__instance).StartCoroutine(GenerateMissingHotSprings(__instance)); } } } [HarmonyPatch(typeof(ZoneSystem), "SpawnLocation")] private static class SpawnLocationPatch { private static void Postfix(ZoneLocation location, GameObject? __result) { if (!((Object)(object)__result == (Object)null) && location.m_prefab.IsValid && IsHotSpring(location.m_prefab.Name)) { (__result.GetComponent<HotSpringArea>() ?? __result.AddComponent<HotSpringArea>()).Initialize(Mathf.Max(location.m_exteriorRadius, location.m_interiorRadius)); } } } [HarmonyPatch(typeof(Player), "UpdateEnvStatusEffects")] private static class PlayerEnvironmentPatch { private static float _timeInHotSpring; private static float _healthTick; private static float _normalRestingDelay; private static bool _wasInHotSpring; private static void Postfix(Player __instance, float dt) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if (!HotSpringArea.Contains(__instance)) { if (_wasInHotSpring) { StatusEffect statusEffect = ((Character)__instance).GetSEMan().GetStatusEffect(SEMan.s_statusEffectResting); SE_Cozy val = (SE_Cozy)(object)((statusEffect is SE_Cozy) ? statusEffect : null); if (val != null) { val.m_delay = _normalRestingDelay; } } _timeInHotSpring = 0f; _healthTick = 0f; _wasInHotSpring = false; return; } SEMan sEMan = ((Character)__instance).GetSEMan(); sEMan.AddStatusEffect(SEMan.s_statusEffectResting, false, 0, 0f, (short)(-1)); StatusEffect statusEffect2 = sEMan.GetStatusEffect(SEMan.s_statusEffectResting); SE_Cozy val2 = (SE_Cozy)(object)((statusEffect2 is SE_Cozy) ? statusEffect2 : null); if (val2 != null) { if (!_wasInHotSpring) { _normalRestingDelay = val2.m_delay; ((StatusEffect)val2).ResetTime(); } val2.m_delay = 60f; } _wasInHotSpring = true; _timeInHotSpring += dt; _healthTick += dt; if (_healthTick >= 1f) { ((Character)__instance).Heal(_healthTick * 2f, false); _healthTick = 0f; } if (!(_timeInHotSpring < 60f)) { StatusEffect statusEffect3 = sEMan.GetStatusEffect(SEMan.s_statusEffectRested); if ((Object)(object)statusEffect3 == (Object)null) { sEMan.AddStatusEffect(SEMan.s_statusEffectRested, true, 0, 0f, (short)(-1)); statusEffect3 = sEMan.GetStatusEffect(SEMan.s_statusEffectRested); } else { statusEffect3.ResetTime(); } SE_Rested val3 = (SE_Rested)(object)((statusEffect3 is SE_Rested) ? statusEffect3 : null); if (val3 != null) { int comfortLevel = __instance.GetComfortLevel(); ((StatusEffect)val3).m_ttl = val3.m_baseTTL + (float)(comfortLevel - 1) * val3.m_TTLPerComfortLevel; } } } } [HarmonyPatch(typeof(SEMan), "RemoveStatusEffect", new Type[] { typeof(int), typeof(bool) })] private static class KeepRestingWhileInHotSpringPatch { private static bool Prefix(SEMan __instance, int nameHash) { Player localPlayer = Player.m_localPlayer; if (nameHash == SEMan.s_statusEffectResting && !((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).GetSEMan() == __instance) { return !HotSpringArea.Contains(localPlayer); } return true; } } [HarmonyPatch(typeof(Player), "GetComfortLevel")] private static class ComfortLevelPatch { private static void Postfix(Player __instance, ref int __result) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && HotSpringArea.Contains(__instance)) { __result += 5; } } } public const string PluginGuid = "com.igentuman.deepnorthstructures"; public const string PluginName = "Deep North Hot Springs"; public const string PluginVersion = "1.0.1"; internal const int HotSpringComfortLevel = 5; internal const float RestedDelay = 60f; internal const float HealthRegenerationPerSecond = 2f; private static readonly HashSet<string> HotSpringPrefabs = new HashSet<string>(StringComparer.Ordinal) { "HotSpring1", "HotSpring2", "HotSpring3" }; private Harmony? _harmony; internal static Plugin Instance { get; private set; } = null; private void Awake() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Instance = this; _harmony = new Harmony("com.igentuman.deepnorthstructures"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Deep North Hot Springs 1.0.1 loaded"); } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static bool IsHotSpring(string prefabName) { return HotSpringPrefabs.Contains(prefabName); } private static IEnumerator GenerateMissingHotSprings(ZoneSystem zoneSystem) { yield return null; MethodInfo generateLocation = AccessTools.Method(typeof(ZoneSystem), "GenerateLocationsTimeSliced", new Type[3] { typeof(ZoneLocation), typeof(Stopwatch), typeof(ZPackage) }, (Type[])null); if (generateLocation == null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"Could not find Valheim's location generator; Hot Springs were not added."); yield break; } Dictionary<string, ZoneLocation> locations = new Dictionary<string, ZoneLocation>(StringComparer.Ordinal); foreach (LocationList allLocationList in LocationList.GetAllLocationLists()) { foreach (ZoneLocation location2 in allLocationList.m_locations) { if (location2.m_prefab.IsValid && IsHotSpring(location2.m_prefab.Name)) { locations[location2.m_prefab.Name] = location2; } } } Stopwatch stopwatch = Stopwatch.StartNew(); foreach (string prefabName in HotSpringPrefabs) { if (!locations.TryGetValue(prefabName, out ZoneLocation location)) { continue; } int before = CountLocations(zoneSystem, prefabName); if (before < location.m_quantity) { ZPackage val = new ZPackage(); if (!(generateLocation.Invoke(zoneSystem, new object[3] { location, stopwatch, val }) is IEnumerator enumerator4)) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("Could not start generation for " + prefabName + ".")); continue; } yield return enumerator4; int num = CountLocations(zoneSystem, prefabName); ((BaseUnityPlugin)Instance).Logger.LogInfo((object)$"Automatically generated {num - before} missing {prefabName} locations ({num}/{location.m_quantity})."); location = null; } } } private static int CountLocations(ZoneSystem zoneSystem, string prefabName) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0030: 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) int num = 0; foreach (LocationInstance value in zoneSystem.m_locationInstances.Values) { if (value.m_location.m_prefabName == prefabName || (value.m_location.m_prefab.IsValid && value.m_location.m_prefab.Name == prefabName)) { num++; } } return num; } } }