Decompiled source of Glider Plus Valheim Glider Addon v1.0.0

BepInEx/plugins/WDIENAT-Glider_Plus_Valheim_Glider_Addon/GliderPlus.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using IBelieveICanFly.Patches;
using IBelieveICanFly.Registration;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("GliderSkill.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WDIENAT")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A trainable Gliding skill for Yggdrah's ValheimGlider.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Glider-Plus Valheim-Glider Addon")]
[assembly: AssemblyTitle("GliderPlus")]
[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 WDIENAT.GliderSkill
{
	internal static class CallSiteRewriter
	{
		internal static MethodInfo StaticMethod(Type type, string name)
		{
			return type.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		}

		internal static IEnumerable<CodeInstruction> InsertModifier(IEnumerable<CodeInstruction> instructions, MethodInfo getter, MethodInfo modifier)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			if (getter == null || modifier == null)
			{
				throw new MissingMethodException("A glider integration method was not found.");
			}
			List<CodeInstruction> list = instructions.ToList();
			int num = list.Count((CodeInstruction code) => CodeInstructionExtensions.Calls(code, getter));
			if (num != 1)
			{
				throw new InvalidOperationException($"Expected exactly one call to {getter.Name}; found {num}. Unsupported ValheimGlider implementation.");
			}
			List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 2);
			foreach (CodeInstruction item in list)
			{
				list2.Add(item);
				if (!CodeInstructionExtensions.Calls(item, getter))
				{
					continue;
				}
				list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
				CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)modifier);
				foreach (ExceptionBlock item2 in item.blocks.Where((ExceptionBlock block) => (int)block.blockType == 5).ToList())
				{
					item.blocks.Remove(item2);
					val.blocks.Add(item2);
				}
				list2.Add(val);
			}
			return list2;
		}
	}
	[HarmonyPatch(typeof(GliderSystem), "ConsumeGliderStamina")]
	internal static class StaminaPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return CallSiteRewriter.InsertModifier(instructions, CallSiteRewriter.StaticMethod(typeof(Config), "GetGliderStaminaDrainPerSecond"), CallSiteRewriter.StaticMethod(typeof(Plugin), "AdjustStaminaDrain"));
		}
	}
	[HarmonyPatch(typeof(GliderSystem), "ApplyVisualTilt")]
	internal static class ControlPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return CallSiteRewriter.InsertModifier(CallSiteRewriter.InsertModifier(CallSiteRewriter.InsertModifier(instructions, CallSiteRewriter.StaticMethod(typeof(Config), "GetWingsAirTurnSpeed"), CallSiteRewriter.StaticMethod(typeof(Plugin), "AdjustTurnSpeed")), CallSiteRewriter.StaticMethod(typeof(Config), "GetWingsTiltPitchSmoothTime"), CallSiteRewriter.StaticMethod(typeof(Plugin), "AdjustSmoothTime")), CallSiteRewriter.StaticMethod(typeof(Config), "GetWingsTiltRollSmoothTime"), CallSiteRewriter.StaticMethod(typeof(Plugin), "AdjustSmoothTime"));
		}
	}
	[HarmonyPatch(typeof(GliderSystem), "ApplyGlidingPhysics")]
	internal static class ExperiencePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player player)
		{
			Plugin.AwardFlightExperience(player);
		}
	}
	[BepInPlugin("WDIENAT.GliderSkill", "Glider-Plus Valheim-Glider Addon", "1.0.0")]
	[BepInDependency("Yggdrah.ValheimGliders", "1.0.4")]
	[BepInDependency("com.jotunn.jotunn", "2.30.1")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "WDIENAT.GliderSkill";

		public const string PluginName = "Glider-Plus Valheim-Glider Addon";

		public const string PluginVersion = "1.0.0";

		public const string Author = "WDIENAT";

		public const string SkillIdentifier = "WDIENAT.GliderSkill.Gliding";

		internal static SkillType GlidingSkill;

		internal static ConfigEntry<float> ExperiencePerSecond;

		internal static ConfigEntry<float> ControlBonusPercent;

		internal static ConfigEntry<float> StaminaReductionPercent;

		private static readonly ConditionalWeakTable<Player, FlightExperience> Progress = new ConditionalWeakTable<Player, FlightExperience>();

		private Harmony harmony;

		private Sprite skillIcon;

		private Texture2D skillTexture;

		private void Awake()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Expected O, but got Unknown
			//IL_00f9: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected I4, but got Unknown
			ExperiencePerSecond = Bind("Experience", "ExperiencePerSecond", 1f, 0f, 10f, "Base skill experience per second of active gliding. 0 disables experience gain. Rested and world skill gain modifiers still apply.");
			ControlBonusPercent = Bind("Bonuses", "ControlBonusAtLevel100", 50f, 0f, 200f, "Percent increase to turning responsiveness at level 100. Pitch and bank smoothing times are divided by the same multiplier. Scales linearly from level 0.");
			StaminaReductionPercent = Bind("Bonuses", "StaminaReductionAtLevel100", 30f, 0f, 90f, "Percent reduction of gliding stamina drain at level 100. Only applies if ValheimGlider enables stamina drain. Scales linearly from level 0.");
			harmony = new Harmony("WDIENAT.GliderSkill");
			try
			{
				harmony.PatchAll(typeof(Plugin).Assembly);
				AddTranslations();
				if (!Application.isBatchMode)
				{
					LoadSkillIcon();
				}
				GlidingSkill = SkillManager.Instance.AddSkill(new SkillConfig
				{
					Identifier = "WDIENAT.GliderSkill.Gliding",
					Name = "$skill_wdienat_gliding",
					Description = "$skill_wdienat_gliding_description",
					IncreaseStep = 1f,
					Icon = skillIcon
				});
				if ((int)GlidingSkill == 0)
				{
					throw new InvalidOperationException("Skill registration failed.");
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} by {2} loaded. Gliding skill ID: {3}.", "Glider-Plus Valheim-Glider Addon", "1.0.0", "WDIENAT", (int)GlidingSkill));
			}
			catch (Exception arg)
			{
				harmony.UnpatchSelf();
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} could not initialize; its patches were removed. {1}", "Glider-Plus Valheim-Glider Addon", arg));
				throw;
			}
		}

		private ConfigEntry<float> Bind(string section, string key, float value, float min, float max, string description)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<float>(section, key, value, new ConfigDescription(description + " [Synced with server]", (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}

		private static void AddTranslations()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["skill_wdienat_gliding"] = "Gliding",
				["skill_wdienat_gliding_description"] = "Practice by flying with an open glider. Higher skill improves steering, pitch and bank response and reduces stamina drain when glider stamina is enabled."
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["skill_wdienat_gliding"] = "Планирование",
				["skill_wdienat_gliding_description"] = "Развивается при полёте с раскрытым глайдером. Улучшает повороты, реакцию на наклон и крен, а также снижает расход выносливости, если он включён у глайдера."
			});
		}

		private void LoadSkillIcon()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WDIENAT.GliderSkill.skill.png"))
			{
				if (stream == null)
				{
					throw new InvalidOperationException("Embedded skill icon is missing.");
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				skillTexture = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(skillTexture, memoryStream.ToArray(), true))
				{
					throw new InvalidOperationException("Embedded skill icon is invalid.");
				}
			}
			((Object)skillTexture).name = "WDIENAT_GlidingSkill";
			skillIcon = Sprite.Create(skillTexture, new Rect(0f, 0f, (float)((Texture)skillTexture).width, (float)((Texture)skillTexture).height), new Vector2(0.5f, 0.5f));
		}

		internal static bool IsLocalFlight(Player player)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && (int)GlidingSkill != 0 && GliderSystem.IsCurrentlyGliding() && GliderSystem.GetCurrentWingsIndex() > 0 && !((Character)player).IsDead() && !((Character)player).IsOnGround() && !((Character)player).InWater() && !((Character)player).IsAttached() && !((Character)player).IsTeleporting())
			{
				return !((Character)player).IsDebugFlying();
			}
			return false;
		}

		private static float Factor(Player player)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Skills skills = ((Character)player).GetSkills();
			if (!((Object)(object)skills == (Object)null))
			{
				return skills.GetSkillFactor(GlidingSkill);
			}
			return 0f;
		}

		internal static float AdjustStaminaDrain(float original, Player player)
		{
			if (!IsLocalFlight(player))
			{
				return original;
			}
			return original * SkillBalance.StaminaMultiplier(Factor(player), StaminaReductionPercent.Value, Config.GetGliderStaminaEnabled());
		}

		internal static float AdjustTurnSpeed(float original, Player player)
		{
			if (!IsLocalFlight(player))
			{
				return original;
			}
			return original * SkillBalance.ControlMultiplier(Factor(player), ControlBonusPercent.Value);
		}

		internal static float AdjustSmoothTime(float original, Player player)
		{
			if (!IsLocalFlight(player))
			{
				return original;
			}
			return original / SkillBalance.ControlMultiplier(Factor(player), ControlBonusPercent.Value);
		}

		internal static void AwardFlightExperience(Player player)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			int num;
			if (IsLocalFlight(player))
			{
				Vector3 velocity = ((Character)player).GetVelocity();
				num = ((((Vector3)(ref velocity)).sqrMagnitude > 0.01f) ? 1 : 0);
			}
			else
			{
				num = 0;
			}
			bool eligible = (byte)num != 0;
			int num2 = Progress.GetValue(player, (Player _) => new FlightExperience()).Sample(Time.frameCount, Time.deltaTime, eligible);
			float num3 = SkillBalance.FiniteClamp(ExperiencePerSecond.Value, 0f, 10f, 1f);
			for (int num4 = 0; num4 < num2; num4++)
			{
				if (!(num3 > 0f))
				{
					break;
				}
				((Character)player).RaiseSkill(GlidingSkill, num3);
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)skillIcon != (Object)null)
			{
				Object.Destroy((Object)(object)skillIcon);
			}
			if ((Object)(object)skillTexture != (Object)null)
			{
				Object.Destroy((Object)(object)skillTexture);
			}
		}
	}
	internal static class SkillBalance
	{
		internal const float DefaultExperiencePerSecond = 1f;

		internal const float DefaultControlBonusPercent = 50f;

		internal const float DefaultStaminaReductionPercent = 30f;

		internal static float FiniteClamp(float value, float min, float max, float fallback)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return fallback;
			}
			return Math.Max(min, Math.Min(max, value));
		}

		internal static float ControlMultiplier(float skillFactor, float bonusPercent)
		{
			return 1f + FiniteClamp(skillFactor, 0f, 1f, 0f) * FiniteClamp(bonusPercent, 0f, 200f, 50f) / 100f;
		}

		internal static float StaminaMultiplier(float skillFactor, float reductionPercent, bool staminaEnabled)
		{
			if (!staminaEnabled)
			{
				return 1f;
			}
			return 1f - FiniteClamp(skillFactor, 0f, 1f, 0f) * FiniteClamp(reductionPercent, 0f, 90f, 30f) / 100f;
		}
	}
	internal sealed class FlightExperience
	{
		private double seconds;

		private int lastFrame = -1;

		internal int Sample(int frame, float deltaTime, bool eligible)
		{
			if (frame == lastFrame)
			{
				return 0;
			}
			lastFrame = frame;
			if (!eligible || deltaTime <= 0f || deltaTime > 0.5f || float.IsNaN(deltaTime) || float.IsInfinity(deltaTime))
			{
				return 0;
			}
			seconds += deltaTime;
			int num = (int)Math.Floor(seconds + 1E-06);
			if (num > 0)
			{
				seconds = Math.Max(0.0, seconds - (double)num);
			}
			return num;
		}
	}
}