Decompiled source of ValheimWirePatches v0.1.4

ValheimWirePatches.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
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("ValheimWirePatches")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+695f4d6563954fb43ae5b2267fb4e3a55e922848")]
[assembly: AssemblyProduct("ValheimWirePatches")]
[assembly: AssemblyTitle("ValheimWirePatches")]
[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 ValheimWirePatches
{
	[HarmonyPatch]
	internal static class DoubleClickSound
	{
		private static readonly HashSet<string> KeepSound = new HashSet<string> { "UpdateGamepad", "MoveToLowerInventoryGrid", "MoveToUpperInventoryGrid", "OnSelectedRecipe", "SetActiveGroup" };

		private static bool IsSetActiveGroup(object operand)
		{
			if (operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(InventoryGui))
			{
				return methodInfo.Name == "SetActiveGroup";
			}
			return false;
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(InventoryGui)))
			{
				if (KeepSound.Contains(declaredMethod.Name) || declaredMethod.IsAbstract || declaredMethod.ContainsGenericParameters)
				{
					continue;
				}
				List<CodeInstruction> originalInstructions;
				try
				{
					originalInstructions = PatchProcessor.GetOriginalInstructions((MethodBase)declaredMethod, (ILGenerator)null);
				}
				catch
				{
					continue;
				}
				for (int i = 1; i < originalInstructions.Count; i++)
				{
					if (IsSetActiveGroup(originalInstructions[i].operand) && CodeInstructionExtensions.LoadsConstant(originalInstructions[i - 1], 1L))
					{
						yield return declaredMethod;
						break;
					}
				}
			}
		}

		private static bool GroupSound()
		{
			return !Plugin.DoubleClickSound.Value;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 1; i < list.Count; i++)
			{
				if (IsSetActiveGroup(list[i].operand) && CodeInstructionExtensions.LoadsConstant(list[i - 1], 1L))
				{
					list[i - 1] = CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DoubleClickSound), "GroupSound", (Type[])null, (Type[])null)), list[i - 1]);
				}
			}
			return list;
		}
	}
	[BepInPlugin("wire.valheimwirepatches", "Valheim Wire Patches", "0.1.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "wire.valheimwirepatches";

		public const string Name = "Valheim Wire Patches";

		public const string Version = "0.1.4";

		internal static Plugin Instance;

		internal static ConfigEntry<bool> DoubleClickSound;

		internal static ConfigEntry<bool> TeleportLighting;

		internal static ConfigEntry<bool> LightningLighting;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			Instance = this;
			DoubleClickSound = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Double click sound", false, "Inventory tabs and buttons (Craft, Upgrade, Skills, Trophies, Achievements...) play the click sound twice. Only one plays.");
			TeleportLighting = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Lighting after teleporting", true, "After a portal, a dungeon entrance or loading in, the lighting breaks for a few seconds and comes back in a wave spreading out from you. It stays right.");
			LightningLighting = ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Lighting stuck on lightning flashes", true, "The lighting can get stuck with a lightning flash in it for a few seconds. It waits until the flash is over.");
			((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)((BaseUnityPlugin)this).Config.Bind<bool>("Performance", "Shadow maps sized to the light", true, "Removed.")).Definition);
			((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", "Shadows for building lights", false, "Removed.")).Definition);
			TeleportLighting.SettingChanged += delegate
			{
				ReflectionSnapshots.SettingChanged();
			};
			_harmony = new Harmony("wire.valheimwirepatches");
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly);
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					_harmony.CreateClassProcessor(type).Patch();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Couldn't patch " + type.Name + ": " + ex.Message));
				}
			}
			VpoCompat.Remove(_harmony, ((BaseUnityPlugin)this).Logger, AccessTools.Method(typeof(ReflectionUpdate), "Start", (Type[])null, (Type[])null), "ValheimPerformanceOptimizations.Patches.VPOReflectionRenderer");
		}

		internal void ReflectionGiveUp()
		{
			ReflectionSnapshots.GiveUp();
		}

		internal void ReflectionTerrainTimeout()
		{
			ReflectionSnapshots.TerrainTimeout();
		}

		internal void ReflectionFadeBack()
		{
			ReflectionSnapshots.RestoreFade();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class ReflectionSnapshots
	{
		private enum Phase
		{
			None,
			Teleporting,
			WaitingForTerrain
		}

		[HarmonyPatch(typeof(ReflectionUpdate), "Start")]
		private static class ReflectionUpdateStart
		{
			private static void Postfix(ReflectionUpdate __instance)
			{
				_follower = null;
				_frozen = null;
				_savedInterval = -1f;
				_faded = null;
				_savedFade = -1f;
				_phase = Phase.None;
				if (On)
				{
					Unparent(__instance);
					Freeze();
				}
			}
		}

		[HarmonyPatch(typeof(Player), "TeleportTo")]
		private static class TeleportTo
		{
			private static void Postfix(Player __instance, bool __result)
			{
				if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Character)__instance).IsTeleporting())
				{
					Freeze();
				}
			}
		}

		[HarmonyPatch(typeof(Character), "ResetCloth")]
		private static class ResetCloth
		{
			private static void Postfix(Character __instance)
			{
				if (_phase == Phase.Teleporting && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && !((Character)Player.m_localPlayer).IsTeleporting() && (Object)(object)Game.instance != (Object)null && !Game.instance.WaitingForRespawn())
				{
					Arrived();
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class OnSpawned
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					if (_phase == Phase.None)
					{
						Freeze();
					}
					Arrived();
				}
			}
		}

		[HarmonyPatch(typeof(TerrainLod), "RebuildAllHeightmaps")]
		private static class RebuildAllHeightmaps
		{
			private static void Postfix()
			{
				if (_phase == Phase.WaitingForTerrain && DistantTerrainReady())
				{
					_phase = Phase.None;
					((MonoBehaviour)Plugin.Instance).CancelInvoke("ReflectionTerrainTimeout");
					Render(instant: false);
				}
			}
		}

		[HarmonyPatch(typeof(TerrainLod), "OnEnable")]
		private static class LodEnable
		{
			private static void Postfix(TerrainLod __instance)
			{
				Lods.RemoveAll((TerrainLod l) => (Object)(object)l == (Object)null);
				if (!Lods.Contains(__instance))
				{
					Lods.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(TerrainLod), "OnDisable")]
		private static class LodDisable
		{
			private static void Postfix(TerrainLod __instance)
			{
				Lods.Remove(__instance);
			}
		}

		[HarmonyPatch(typeof(Thunder), "DoFlash")]
		private static class DoFlash
		{
			private static void Postfix(Thunder __instance)
			{
				ReflectionUpdate instance = ReflectionUpdate.instance;
				if (!Plugin.LightningLighting.Value || (Object)(object)instance == (Object)null || _phase == Phase.Teleporting)
				{
					return;
				}
				float num = 0f;
				EffectData[] array = __instance.m_flashEffect?.m_effectPrefabs;
				if (array != null)
				{
					EffectData[] array2 = array;
					foreach (EffectData val in array2)
					{
						if (val != null && val.m_enabled && (Object)(object)val.m_prefab != (Object)null)
						{
							num = Mathf.Max(num, LengthOf(val.m_prefab));
						}
					}
				}
				if (num <= 0f)
				{
					num = 1f;
				}
				float num2 = instance.m_interval - Mathf.Min(4f, num + 0.3f);
				float num3 = UpdateTimer.Invoke(instance);
				if (num3 > num2 || num3 < 0.5f)
				{
					UpdateTimer.Invoke(instance) = Mathf.Max(0f, num2);
				}
			}

			private static float LengthOf(GameObject prefab)
			{
				if (FlashLength.TryGetValue(prefab, out var value))
				{
					return value;
				}
				value = 0f;
				LightFlicker[] componentsInChildren = prefab.GetComponentsInChildren<LightFlicker>(true);
				foreach (LightFlicker val in componentsInChildren)
				{
					if (val.m_ttl > 0f)
					{
						value = Mathf.Max(value, val.m_ttl);
					}
				}
				if (value <= 0f)
				{
					TimedDestruction[] componentsInChildren2 = prefab.GetComponentsInChildren<TimedDestruction>(true);
					foreach (TimedDestruction val2 in componentsInChildren2)
					{
						value = Mathf.Max(value, val2.m_timeout);
					}
				}
				FlashLength[prefab] = value;
				return value;
			}
		}

		private const float FrozenInterval = 1000000f;

		private const float GiveUpSeconds = 40f;

		private const float TerrainWaitSeconds = 20f;

		private const float InstantFade = 0.01f;

		private const float FadeBackAfter = 2.9f;

		private const float FlashMargin = 0.3f;

		private const float FlashMax = 4f;

		private const float FlashDefault = 1f;

		private const float RecentRender = 0.5f;

		private static Phase _phase;

		private static ReflectionUpdate _frozen;

		private static float _savedInterval = -1f;

		private static ReflectionUpdate _faded;

		private static float _savedFade = -1f;

		private static Transform _follower;

		private static readonly FieldRef<ReflectionUpdate, float> UpdateTimer = AccessTools.FieldRefAccess<ReflectionUpdate, float>("m_updateTimer");

		private static readonly List<TerrainLod> Lods = new List<TerrainLod>();

		private static readonly FieldInfo LodState = AccessTools.Field(typeof(TerrainLod), "m_heightmapState");

		private static readonly FieldRef<TerrainLod, Vector3> LodPoint = AccessTools.FieldRefAccess<TerrainLod, Vector3>("m_lastPoint");

		private static readonly FieldRef<TerrainLod, float> LodStep = AccessTools.FieldRefAccess<TerrainLod, float>("m_updateStepDistance");

		private const int LodDone = 2;

		private static readonly Dictionary<GameObject, float> FlashLength = new Dictionary<GameObject, float>();

		private static bool On => Plugin.TeleportLighting.Value;

		internal static void SettingChanged()
		{
			if (!On)
			{
				GiveUp();
				RestoreFade();
			}
			Unparent(ReflectionUpdate.instance);
		}

		private static void Unparent(ReflectionUpdate r)
		{
			if (!((Object)(object)r == (Object)null) && !((Object)(object)r.m_probe1 == (Object)null) && !((Object)(object)r.m_probe2 == (Object)null))
			{
				if ((Object)(object)_follower == (Object)null)
				{
					_follower = ((Component)r.m_probe1).transform.parent;
				}
				if (!((Object)(object)_follower == (Object)null))
				{
					Transform val = (On ? _follower.parent : _follower);
					((Component)r.m_probe1).transform.SetParent(val, true);
					((Component)r.m_probe2).transform.SetParent(val, true);
				}
			}
		}

		private static void Freeze()
		{
			ReflectionUpdate instance = ReflectionUpdate.instance;
			if (On && !((Object)(object)instance == (Object)null))
			{
				RestoreFade();
				if ((Object)(object)_frozen != (Object)(object)instance)
				{
					Unfreeze();
					_frozen = instance;
					_savedInterval = instance.m_interval;
					instance.m_interval = 1000000f;
				}
				_phase = Phase.Teleporting;
				((MonoBehaviour)Plugin.Instance).CancelInvoke("ReflectionGiveUp");
				((MonoBehaviour)Plugin.Instance).Invoke("ReflectionGiveUp", 40f);
			}
		}

		private static void Unfreeze()
		{
			if ((Object)(object)_frozen != (Object)null && _savedInterval > 0f)
			{
				_frozen.m_interval = _savedInterval;
			}
			_frozen = null;
			_savedInterval = -1f;
		}

		private static void Arrived()
		{
			if (_phase == Phase.Teleporting)
			{
				((MonoBehaviour)Plugin.Instance).CancelInvoke("ReflectionGiveUp");
				Unfreeze();
				Render(instant: true);
				if (DistantTerrainReady())
				{
					_phase = Phase.None;
					return;
				}
				_phase = Phase.WaitingForTerrain;
				((MonoBehaviour)Plugin.Instance).CancelInvoke("ReflectionTerrainTimeout");
				((MonoBehaviour)Plugin.Instance).Invoke("ReflectionTerrainTimeout", 20f);
			}
		}

		internal static void TerrainTimeout()
		{
			if (_phase == Phase.WaitingForTerrain)
			{
				_phase = Phase.None;
			}
		}

		internal static void GiveUp()
		{
			((MonoBehaviour)Plugin.Instance).CancelInvoke("ReflectionGiveUp");
			Unfreeze();
			_phase = Phase.None;
		}

		private static void Render(bool instant)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			ReflectionUpdate instance = ReflectionUpdate.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null))
			{
				RestoreFade();
				UpdateTimer.Invoke(instance) = 0f;
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					ZNet.instance.SetReferencePosition(((Component)localPlayer).transform.position);
				}
				if (instant)
				{
					_faded = instance;
					_savedFade = instance.m_transitionDuration;
					instance.m_transitionDuration = 0.01f;
					((MonoBehaviour)Plugin.Instance).CancelInvoke("ReflectionFadeBack");
					((MonoBehaviour)Plugin.Instance).Invoke("ReflectionFadeBack", 2.9f);
				}
				instance.UpdateReflection();
			}
		}

		internal static void RestoreFade()
		{
			if ((Object)(object)_faded != (Object)null && _savedFade > 0f)
			{
				_faded.m_transitionDuration = _savedFade;
			}
			_faded = null;
			_savedFade = -1f;
		}

		private static bool DistantTerrainReady()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (LodState == null || (Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			foreach (TerrainLod lod in Lods)
			{
				if (!((Object)(object)lod == (Object)null) && ((Behaviour)lod).isActiveAndEnabled)
				{
					if (Convert.ToInt32(LodState.GetValue(lod)) != 2)
					{
						return false;
					}
					if (Utils.DistanceXZ(position, LodPoint.Invoke(lod)) > LodStep.Invoke(lod))
					{
						return false;
					}
				}
			}
			return true;
		}
	}
	internal static class VpoCompat
	{
		public const string Guid = "dev.ontrigger.vpo";

		public static void Remove(Harmony harmony, ManualLogSource log, MethodBase original, string vpoType)
		{
			Patches val = ((original != null) ? Harmony.GetPatchInfo(original) : null);
			if (val == null)
			{
				return;
			}
			foreach (Patch prefix in val.Prefixes)
			{
				Type declaringType = prefix.PatchMethod.DeclaringType;
				if (!(declaringType == null) && !(declaringType.FullName != vpoType))
				{
					harmony.Unpatch(original, prefix.PatchMethod);
					log.LogInfo((object)("Disabled VPO " + declaringType.Name + "." + prefix.PatchMethod.Name));
				}
			}
		}
	}
}