Decompiled source of FreeFlight v1.1.0

plugins/FreeFlight.dll

Decompiled a week ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
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: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("FreeFlight")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+47387fc1dd9268975412a4fec193f5bfd45a3264")]
[assembly: AssemblyProduct("FreeFlight")]
[assembly: AssemblyTitle("FreeFlight")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[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 Oddhatter.FreeFlight
{
	internal static class Flight
	{
		private static bool _safeLanding;

		internal static bool Active { get; private set; }

		internal static bool IsLocalFlyer(Character character)
		{
			if (Active && (Object)(object)character != (Object)null)
			{
				return (Object)(object)character == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		internal static void UpdateToggle()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Active = false;
				_safeLanding = false;
				return;
			}
			bool flag = ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsAttached() || ((Character)localPlayer).IsAttachedToShip();
			if (Active && (!FreeFlightPlugin.Enabled.Value || flag))
			{
				SetActive(localPlayer, on: false);
			}
			else if (FreeFlightPlugin.Enabled.Value && !flag && ((Character)localPlayer).TakeInput() && (ZInput.GetKeyDown(FreeFlightPlugin.ToggleKey.Value, false) || (FreeFlightPlugin.GamepadToggle.Value && BothSticksPressed())))
			{
				SetActive(localPlayer, !Active);
			}
		}

		private static bool BothSticksPressed()
		{
			if (!ZInput.GetButtonDown("JoyLStick") || !ZInput.GetButton("JoyRStick"))
			{
				if (ZInput.GetButtonDown("JoyRStick"))
				{
					return ZInput.GetButton("JoyLStick");
				}
				return false;
			}
			return true;
		}

		private static void SetActive(Player player, bool on)
		{
			Active = on;
			if (!on)
			{
				_safeLanding = true;
				((Character)player).m_lastGroundTouch = 1f;
			}
			((Character)player).Message((MessageType)1, on ? "Flight on" : "Flight off", 0, (Sprite)null, false);
		}

		internal static bool UpdateMotion(Player player, float dt)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (Active && !((Character)player).IsDead() && !((Character)player).IsTeleporting())
			{
				Move(player, dt);
				return true;
			}
			if (_safeLanding)
			{
				if (((Character)player).IsDead() || ((Character)player).InLiquidSwimDepth() || ((Character)player).m_lastGroundTouch < 0.1f)
				{
					_safeLanding = false;
				}
				else
				{
					if (player.m_crouchToggled)
					{
						((Character)player).SetCrouch(false);
					}
					((Character)player).m_maxAirAltitude = ((Component)player).transform.position.y;
				}
			}
			return false;
		}

		private static void Move(Player player, float dt)
		{
			//IL_0057: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_00cd: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			((Character)player).UpdateBodyFriction();
			((Character)player).m_sliding = false;
			((Character)player).m_wallRunning = false;
			((Character)player).m_running = false;
			((Character)player).m_walking = false;
			if (player.m_crouchToggled)
			{
				((Character)player).SetCrouch(false);
			}
			float num = FreeFlightPlugin.FlySpeed.Value * (((Character)player).m_run ? FreeFlightPlugin.SprintMultiplier.Value : 1f);
			Vector3 val = ((Character)player).m_moveDir * num;
			if (((Character)player).TakeInput())
			{
				if ((ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump")) && !Hud.IsPieceSelectionVisible())
				{
					val.y = num;
				}
				else if (ZInput.GetButton("Crouch") || ZInput.GetButtonPressedTimer("JoyCrouch") > 0.33f)
				{
					val.y = 0f - num;
				}
			}
			Rigidbody body = ((Character)player).m_body;
			((Character)player).m_currentVel = Vector3.Lerp(((Character)player).m_currentVel, val, 0.5f);
			body.linearVelocity = ((Character)player).m_currentVel;
			body.useGravity = false;
			body.rotation = Quaternion.RotateTowards(((Component)player).transform.rotation, ((Character)player).m_lookYaw, ((Character)player).m_turnSpeed * dt);
			body.angularVelocity = Vector3.zero;
			((Character)player).m_lastGroundTouch = 0f;
			((Character)player).m_maxAirAltitude = ((Component)player).transform.position.y;
			((Character)player).m_fallTimer = 0f;
			((Character)player).m_zanim.SetBool(Character.s_animatorFalling, false);
			((Character)player).UpdateEyeRotation();
		}
	}
	[BepInPlugin("com.oddhatter.freeflight", "FreeFlight", "1.1.0")]
	[BepInProcess("valheim.exe")]
	public sealed class FreeFlightPlugin : BaseUnityPlugin
	{
		public const string Guid = "com.oddhatter.freeflight";

		public const string Name = "FreeFlight";

		public const string Version = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<KeyCode> ToggleKey;

		internal static ConfigEntry<bool> GamepadToggle;

		internal static ConfigEntry<float> FlySpeed;

		internal static ConfigEntry<float> SprintMultiplier;

		internal static ConfigEntry<bool> DragHarpooned;

		internal static ConfigEntry<float> RopeLength;

		private const float ConfigReloadDelay = 0.5f;

		private Harmony _harmony;

		private FileSystemWatcher _configWatcher;

		private volatile bool _configFileChanged;

		private float _configReloadAt = -1f;

		private bool _configLockedLogged;

		private void Awake()
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false, flight is unavailable and the harpoon works as in vanilla.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ToggleKey", (KeyCode)104, "Key that turns flying on and off. While flying: Jump (Space) climbs, Crouch (Ctrl) descends, Run (Shift) is faster.");
			GamepadToggle = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GamepadToggle", true, "Controller: press both thumbsticks in together (L3 + R3) to turn flying on and off.");
			FlySpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Speed", "FlySpeed", 20f, new ConfigDescription("Flying speed in meters per second (normal running is about 7).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			SprintMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Speed", "SprintMultiplier", 2.5f, new ConfigDescription("Speed multiplier while holding Run. Flying never costs stamina.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			DragHarpooned = ((BaseUnityPlugin)this).Config.Bind<bool>("Harpoon", "DragHarpooned", true, "true: an enemy you harpoon is towed through the air while you fly (the line doesn't snap and costs no stamina). Release it the vanilla way, by attacking or blocking. false: vanilla harpoon.");
			RopeLength = ((BaseUnityPlugin)this).Config.Bind<float>("Harpoon", "RopeLength", 5f, new ConfigDescription("How far below/behind you a towed enemy hangs, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			_harmony = new Harmony("com.oddhatter.freeflight");
			_harmony.PatchAll(typeof(FreeFlightPlugin).Assembly);
			foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
			{
				Log.LogInfo((object)("Patched " + patchedMethod.DeclaringType?.Name + "." + patchedMethod.Name));
			}
			WatchConfigFile();
			Log.LogInfo((object)"FreeFlight 1.1.0 loaded.");
		}

		private void Update()
		{
			Flight.UpdateToggle();
			if (_configFileChanged)
			{
				_configFileChanged = false;
				_configReloadAt = Time.realtimeSinceStartup + 0.5f;
			}
			if (_configReloadAt >= 0f && Time.realtimeSinceStartup >= _configReloadAt)
			{
				_configReloadAt = -1f;
				ReloadConfigFromDisk();
			}
		}

		private void OnDestroy()
		{
			_configWatcher?.Dispose();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void WatchConfigFile()
		{
			string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
			_configWatcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath))
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
				IncludeSubdirectories = false
			};
			_configWatcher.Changed += OnConfigFileEvent;
			_configWatcher.Created += OnConfigFileEvent;
			_configWatcher.Renamed += OnConfigFileEvent;
			_configWatcher.EnableRaisingEvents = true;
		}

		private void OnConfigFileEvent(object sender, FileSystemEventArgs e)
		{
			_configFileChanged = true;
		}

		private void ReloadConfigFromDisk()
		{
			if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				return;
			}
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				_configLockedLogged = false;
				Log.LogInfo((object)"Configuration reloaded from disk.");
			}
			catch (IOException ex)
			{
				if (!_configLockedLogged)
				{
					_configLockedLogged = true;
					Log.LogWarning((object)("Config file busy, will retry: " + ex.Message));
				}
				_configReloadAt = Time.realtimeSinceStartup + 0.5f;
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Failed to reload configuration: " + ex2.Message));
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateMotion")]
	internal static class Character_UpdateMotion_Patch
	{
		private static bool Prefix(Character __instance, float dt)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			return !Flight.UpdateMotion((Player)__instance, dt);
		}
	}
	[HarmonyPatch(typeof(Character), "Jump")]
	internal static class Character_Jump_Patch
	{
		private static bool Prefix(Character __instance)
		{
			return !Flight.IsLocalFlyer(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "IsEncumbered")]
	internal static class Player_IsEncumbered_Patch
	{
		private static void Postfix(Player __instance, ref bool __result)
		{
			if (__result && Flight.IsLocalFlyer((Character)(object)__instance))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class Character_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			if (hit == null || hit.m_statusEffectHash == 0 || !FreeFlightPlugin.Enabled.Value || !FreeFlightPlugin.DragHarpooned.Value)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !__instance.IsPlayer() && !__instance.IsBoss())
			{
				ZNetView nview = __instance.m_nview;
				if (!((Object)(object)nview == (Object)null) && nview.IsValid() && !nview.IsOwner() && !((Object)(object)hit.GetAttacker() != (Object)(object)localPlayer) && !((Object)(object)ObjectDB.instance == (Object)null) && ObjectDB.instance.GetStatusEffect(hit.m_statusEffectHash) is SE_Harpooned)
				{
					nview.ClaimOwnership();
				}
			}
		}
	}
	[HarmonyPatch(typeof(SE_Harpooned), "UpdateStatusEffect")]
	internal static class SE_Harpooned_UpdateStatusEffect_Patch
	{
		private const float Stiffness = 5f;

		private const float MaxCatchUpSpeed = 50f;

		private const float SnapDistance = 40f;

		private static bool Prefix(SE_Harpooned __instance, float dt)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00a6: 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)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!FreeFlightPlugin.Enabled.Value || !FreeFlightPlugin.DragHarpooned.Value || !Flight.Active)
			{
				return true;
			}
			Character attacker = __instance.m_attacker;
			Character character = ((StatusEffect)__instance).m_character;
			if ((Object)(object)attacker == (Object)null || (Object)(object)attacker != (Object)(object)Player.m_localPlayer || (Object)(object)character == (Object)null || (Object)(object)character.m_body == (Object)null)
			{
				return true;
			}
			BaseUpdate((StatusEffect)(object)__instance, dt);
			Rigidbody body = character.m_body;
			float value = FreeFlightPlugin.RopeLength.Value;
			Vector3 val = ((Component)attacker).transform.position - body.position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude > value)
			{
				Vector3 val2 = val / magnitude;
				float num = magnitude - value;
				if (num > 40f)
				{
					body.position = ((Component)attacker).transform.position - val2 * value;
					body.linearVelocity = attacker.m_body.linearVelocity;
				}
				else
				{
					body.linearVelocity = attacker.m_body.linearVelocity + val2 * Mathf.Min(num * 5f, 50f);
				}
			}
			__instance.m_baseDistance = value;
			if ((Object)(object)__instance.m_line != (Object)null)
			{
				__instance.m_line.SetSlack((1f - Utils.LerpStep(value / 2f, value, magnitude)) * __instance.m_maxLineSlack);
			}
			return false;
		}

		private static void BaseUpdate(StatusEffect se, float dt)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			se.m_time += dt;
			if (se.m_repeatInterval > 0f && !string.IsNullOrEmpty(se.m_repeatMessage))
			{
				se.m_msgTimer += dt;
				if (se.m_msgTimer > se.m_repeatInterval)
				{
					se.m_msgTimer = 0f;
					se.m_character.Message(se.m_repeatMessageType, se.m_repeatMessage, 0, (Sprite)null, false);
				}
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}