Decompiled source of ZenPath v0.2.3

plugins\ZenPath.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Zen.Config;
using Zen.Lib;
using Zen.Logging;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenPath")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZenPath")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 ZenPath
{
	public static class Configs
	{
		public static readonly ConfigEntry<float> StaminaDrainPath;

		public static readonly ConfigEntry<float> StaminaDrainPaved;

		public static readonly ConfigEntry<bool> ShowStatusIcon;

		public static readonly ConfigEntry<string> LabelPath;

		public static readonly ConfigEntry<string> LabelPaved;

		static Configs()
		{
			StaminaDrainPath = Config.Define<float>(true, "General", "Stamina Usage Path", 0.5f, Config.AcceptRange<float>(0f, 1f), "The percent stamina drain when running on dirt, wood, or metal");
			StaminaDrainPaved = Config.Define<float>(true, "General", "Stamina Usage Paved", 0f, Config.AcceptRange<float>(0f, 1f), "The percent stamina drain when running on a paved surface or stone.");
			ShowStatusIcon = Config.Define<bool>(true, "General", "Show Status Icon", true, "Display the status effect icon when in buff is active");
			LabelPath = Config.Define<string>(false, "Translation", "Label Path", "Path", "Text to display when runninng on a dirt, wooden, or metal surface");
			LabelPaved = Config.Define<string>(false, "Translation", "Label Paved", "$piece_pavedroad", "Text to display when runninng on a paved road or stone surface");
		}
	}
	public static class HeightmapExt
	{
		public static Color GetPaintMask(this Heightmap heightmap, Vector3 worldPos)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			worldPos.x -= 0.5f;
			worldPos.z -= 0.5f;
			int num = default(int);
			int num2 = default(int);
			heightmap.WorldToVertex(worldPos, ref num, ref num2);
			return heightmap.GetPaintMask(num, num2);
		}

		public static bool IsPaintMaskOf(this Color color, Color mask)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (color.r >= mask.r * 0.5f && color.g >= mask.g * 0.5f)
			{
				return color.b >= mask.b * 0.5f;
			}
			return false;
		}

		public static bool IsDirt(this Heightmap heightmap, Vector3 worldPos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: 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)
			return heightmap.GetPaintMask(worldPos).IsPaintMaskOf(Heightmap.m_paintMaskDirt);
		}

		public static bool IsPaved(this Heightmap heightmap, Vector3 worldPos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: 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)
			return heightmap.GetPaintMask(worldPos).IsPaintMaskOf(Heightmap.m_paintMaskPaved);
		}
	}
	[HarmonyPatch]
	public static class PathDetect
	{
		public static MotionType MotionType { get; private set; }

		public static GroundMaterial GroundMaterial { get; private set; }

		public static PathType PathType { get; private set; }

		public static bool IsRunning
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Invalid comparison between Unknown and I4
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Invalid comparison between Unknown and I4
				MotionType motionType = MotionType;
				if ((int)motionType == 2 || (int)motionType == 8)
				{
					return true;
				}
				return false;
			}
		}

		public static bool IsOnPath => PathType != PathType.None;

		private static Player LocalPlayer => Player.m_localPlayer;

		private static PathType GetPathType(Collider? collider, Vector3 worldPos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Invalid comparison between Unknown and I4
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected I4, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			GroundMaterial groundMaterial = GroundMaterial;
			if ((int)groundMaterial <= 64)
			{
				if ((int)groundMaterial <= 16)
				{
					switch ((int)groundMaterial)
					{
					default:
						if ((int)groundMaterial == 16)
						{
							break;
						}
						goto IL_007d;
					case 0:
					case 2:
						break;
					case 8:
						goto IL_0079;
					case 4:
						return PathType.PavedPath;
					case 1:
					case 3:
					case 5:
					case 6:
					case 7:
						goto IL_007d;
					}
					goto IL_0077;
				}
				if ((int)groundMaterial != 32 && (int)groundMaterial == 64)
				{
				}
			}
			else if ((int)groundMaterial <= 256)
			{
				if ((int)groundMaterial != 128 && (int)groundMaterial == 256)
				{
					goto IL_0079;
				}
			}
			else if ((int)groundMaterial == 512 || (int)groundMaterial == 2048)
			{
				goto IL_0077;
			}
			goto IL_007d;
			IL_0077:
			return PathType.None;
			IL_0079:
			return PathType.SimplePath;
			IL_007d:
			if (!Object.op_Implicit((Object)(object)collider))
			{
				return PathType.None;
			}
			Heightmap component = ((Component)collider).GetComponent<Heightmap>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return PathType.None;
			}
			Color paintMask = component.GetPaintMask(worldPos);
			if (paintMask.IsPaintMaskOf(Heightmap.m_paintMaskDirt))
			{
				return PathType.SimplePath;
			}
			if (paintMask.IsPaintMaskOf(Heightmap.m_paintMaskPaved))
			{
				return PathType.PavedPath;
			}
			return PathType.None;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FootStep), "OnFoot", new Type[] { typeof(Transform) })]
		private static void FootStep_OnFoot(FootStep __instance)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Log.Info((object)$"GroundType: {GroundMaterial}, MotionType: {MotionType}, PathType: {PathType}", (ushort)0);
			PathEffect.UpdateStep();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FootStep), "GetMotionType")]
		private static void FootStep_GetMotionType(Character character, ref MotionType __result)
		{
			if (PlayerExt.Is(LocalPlayer, character))
			{
				MotionType = __result;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FootStep), "GetGroundMaterial")]
		private static void FootStep_GetGroundMaterial(Character character, Vector3 point, ref GroundMaterial __result)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerExt.Is(LocalPlayer, character))
			{
				GroundMaterial = __result;
				PathType = GetPathType(character.GetLastGroundCollider(), point);
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(FootStep), "GetGroundMaterial")]
		private static IEnumerable<CodeInstruction> Transpile_FootStep_GetGroundMaterial_Ashlands(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			Label jumpTarget = CodeInstructionExtensions.WithLabels(instructions.First((CodeInstruction code) => code.opcode == OpCodes.Ldc_I4_4), new Label[1] { generator.DefineLabel() }).labels.Last();
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Switch)
				{
					List<Label> list = ((Label[])instruction.operand).ToList();
					list.Add(jumpTarget);
					yield return new CodeInstruction(OpCodes.Switch, (object)list.ToArray());
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	public enum PathType
	{
		None,
		SimplePath,
		PavedPath
	}
	[BepInPlugin("ZenDragon.ZenPath", "ZenPath", "0.2.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : ZenMod<Plugin>
	{
		public const string PluginName = "ZenPath";

		public const string PluginVersion = "0.2.3";

		public const string PluginGUID = "ZenDragon.ZenPath";

		protected override void Setup()
		{
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

		protected override void WorldStart()
		{
			PathEffect.Init();
		}

		private void Update()
		{
			PathEffect.CheckPath();
		}

		protected override void Shutdown()
		{
			PathEffect.Cleanup();
		}
	}
	public static class PathEffect
	{
		private class Effect : StatusEffect
		{
			private readonly Sprite _icon = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("CorpseRun")).m_icon;

			private PathType _pathType;

			private Effect()
			{
				((Object)this).name = "SE_ZenPath";
			}

			public override void ModifyRunStaminaDrain(float baseDrain, ref float drain, Vector3 dir)
			{
				//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
				if (PathDetect.IsOnPath)
				{
					_pathType = PathDetect.PathType;
					float value;
					switch (_pathType)
					{
					case PathType.SimplePath:
						value = Configs.StaminaDrainPath.Value;
						base.m_name = StringExt.Localize(Configs.LabelPath.Value);
						break;
					case PathType.PavedPath:
						value = Configs.StaminaDrainPaved.Value;
						base.m_name = StringExt.Localize(Configs.LabelPaved.Value);
						break;
					case PathType.None:
						Log.Info((object)"No path detected, not applying stamina drain", (ushort)0);
						return;
					default:
						throw new ArgumentOutOfRangeException("_pathType");
					}
					drain = baseDrain * Math.Max(value, 0.001f);
					base.m_tooltip = StringExt.Localize($"$se_runstamina {value * 100f}%");
					base.m_icon = (Configs.ShowStatusIcon.Value ? _icon : null);
					if (PlayerExt.IsReady(LocalPlayer) && PathDetect.IsRunning)
					{
						Log.Info((object)$"Stamina Drain: {value}\tPathType: {_pathType} : {PathDetect.GroundMaterial}", (ushort)0);
					}
				}
			}
		}

		private static Effect _buff;

		private const float Cooldown = 1f;

		private static float _activationTime;

		private static Player LocalPlayer => Player.m_localPlayer;

		private static bool IsExpired => Time.time >= _activationTime + 1f;

		private static bool IsRunningOnPath
		{
			get
			{
				if (PathDetect.IsRunning)
				{
					return PathDetect.IsOnPath;
				}
				return false;
			}
		}

		public static void Init()
		{
			_buff = ScriptableObject.CreateInstance<Effect>();
			ObjectDB.instance.m_StatusEffects.Add((StatusEffect)(object)_buff);
		}

		public static void Cleanup()
		{
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				ObjectDB.instance.m_StatusEffects.Remove((StatusEffect)(object)_buff);
			}
		}

		public static void UpdateStep()
		{
			if (PlayerExt.IsReady(LocalPlayer) && IsRunningOnPath)
			{
				ApplyBuff();
			}
		}

		private static void ApplyBuff()
		{
			if (IsExpired)
			{
				((Character)LocalPlayer).GetSEMan().AddStatusEffect((StatusEffect)(object)_buff, false, 0, 0f);
			}
			_activationTime = Time.time;
		}

		private static void RemoveBuff()
		{
			if (Object.op_Implicit((Object)(object)_buff) && PlayerExt.IsReady(LocalPlayer))
			{
				((Character)LocalPlayer).GetSEMan().RemoveStatusEffect((StatusEffect)(object)_buff, false);
			}
		}

		public static void CheckPath()
		{
			if (IsExpired && !IsRunningOnPath)
			{
				RemoveBuff();
			}
		}
	}
}