Decompiled source of ZenPath v0.2.9

plugins\ZenPath.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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<float> MoveSpeedSnow;

		public static readonly ConfigEntry<bool> ShowStatusIcon;

		static Configs()
		{
			StaminaDrainPath = Config.Define<float>(true, "General", "Stamina Usage Path", 0.5f, Config.AcceptRange<float>(0f, 1f), "Stamina drain percent when running on dirt, wood, or metal (Vanilla: 1)");
			StaminaDrainPaved = Config.Define<float>(true, "General", "Stamina Usage Paved", 0f, Config.AcceptRange<float>(0f, 1f), "Stamina drain percent when running on a paved surface or stone. (Vanilla: 1)");
			MoveSpeedSnow = Config.Define<float>(true, "General", "Move Speed Snow", 0.75f, Config.AcceptRange<float>(0.1f, 1f), "Movement speed when on snow as a percentage. (Vanilla: 1)");
			ShowStatusIcon = Config.Define<bool>(true, "General", "Show Status Icon", true, "Display the status effect icon when running on paths");
		}
	}
	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]
	internal static class PathDetect
	{
		private static MotionType _motionType;

		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;

		public static bool IsOnSnow
		{
			get
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Invalid comparison between Unknown and I4
				if (PathType == PathType.None)
				{
					return (int)GroundMaterial == 16;
				}
				return false;
			}
		}

		public static bool IsRunningOnPath
		{
			get
			{
				if (IsOnPath)
				{
					return IsRunning;
				}
				return false;
			}
		}

		public static bool IsRunningOnSnow
		{
			get
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Invalid comparison between Unknown and I4
				if (IsOnSnow)
				{
					if (!IsRunning)
					{
						return (int)_motionType == 1;
					}
					return true;
				}
				return false;
			}
		}

		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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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)
			//IL_00b8: 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_0085;
					case 0:
					case 2:
						break;
					case 8:
						goto IL_0081;
					case 4:
						return PathType.PavedPath;
					case 1:
					case 3:
					case 5:
					case 6:
					case 7:
						goto IL_0085;
					}
					goto IL_007f;
				}
				if ((int)groundMaterial != 32 && (int)groundMaterial == 64)
				{
				}
			}
			else if ((int)groundMaterial <= 256)
			{
				if ((int)groundMaterial != 128 && (int)groundMaterial == 256)
				{
					goto IL_0081;
				}
			}
			else if ((int)groundMaterial == 512 || ((int)groundMaterial != 1024 && (int)groundMaterial == 2048))
			{
				goto IL_007f;
			}
			goto IL_0085;
			IL_007f:
			return PathType.None;
			IL_0081:
			return PathType.SimplePath;
			IL_0085:
			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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerExt.Is(Player.m_localPlayer, __instance.m_character))
			{
				Log.Info((object)$"GroundType: {GroundMaterial}, MotionType: {_motionType}, PathType: {PathType}", (ushort)0);
				Effect.UpdateStep();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FootStep), "GetMotionType")]
		private static void FootStep_GetMotionType(Character character, ref MotionType __result)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerExt.Is(Player.m_localPlayer, character))
			{
				_motionType = __result;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FootStep), "GetGroundMaterial")]
		private static void FootStep_GetGroundMaterial(Character character, Vector3 point, ref GroundMaterial __result)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerExt.Is(Player.m_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)
		{
			return Transpilers.Manipulator(instructions, (Func<CodeInstruction, bool>)((CodeInstruction code) => CodeInstructionExtensions.Is(code, OpCodes.Ldfld, (MemberInfo)AccessTools.Field(typeof(WearNTear), "m_materialType"))), (Action<CodeInstruction>)delegate(CodeInstruction code)
			{
				code.opcode = OpCodes.Call;
				code.operand = AccessTools.Method(typeof(PathDetect), "GetGroundMaterial_Intercept", (Type[])null, (Type[])null);
			});
		}

		private static MaterialType GetGroundMaterial_Intercept(WearNTear wnt)
		{
			//IL_0001: 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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected I4, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			MaterialType materialType = wnt.m_materialType;
			switch ((int)materialType)
			{
			case 0:
			case 3:
				return (MaterialType)0;
			case 2:
			case 6:
				return (MaterialType)2;
			case 1:
			case 4:
			case 5:
				return (MaterialType)1;
			default:
				Log.Info((object)$"WearNTear.MaterialType: {wnt.m_materialType} is out of range. Did a Valheim update add a new type? Is it a mod?", (ushort)0);
				return wnt.m_materialType;
			}
		}
	}
	public enum PathType
	{
		None,
		SimplePath,
		PavedPath
	}
	[BepInPlugin("ZenDragon.ZenPath", "ZenPath", "0.2.9")]
	[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.9";

		public const string PluginGUID = "ZenDragon.ZenPath";

		protected override void Setup()
		{
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

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

		private void Update()
		{
			Effect.Update();
		}

		protected override void Shutdown()
		{
			Effect.Shutdown();
		}
	}
	internal static class Effect
	{
		private class BaseEffect : StatusEffect
		{
			private const float Cooldown = 1f;

			public float initTime;

			public bool IsExpired => Time.time >= initTime + 1f;

			public BaseEffect()
			{
				base.m_icon = (Configs.ShowStatusIcon.Value ? ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("CorpseRun")).m_icon : null);
			}
		}

		private class SnowEffect : BaseEffect
		{
			public SnowEffect()
			{
				((Object)this).name = "SE_ZenPath_Snow";
				((StatusEffect)this).m_name = "$se_path_snow_name";
				((StatusEffect)this).m_tooltip = "$se_path_snow_tooltip";
			}

			public override void ModifySpeed(float baseSpeed, ref float speed, Character character, Vector3 dir)
			{
				if (PlayerExt.Is(Player.m_localPlayer, character) && PathDetect.IsOnSnow)
				{
					speed = baseSpeed * Configs.MoveSpeedSnow.Value;
					Log.Info((object)$"Snow Speed: {speed:F2}", (ushort)0);
				}
			}
		}

		private class PathEffect : BaseEffect
		{
			private PathType _pathType;

			public PathEffect()
			{
				((Object)this).name = "SE_ZenPath";
			}

			public override void ModifyRunStaminaDrain(float baseDrain, ref float drain, Vector3 dir)
			{
				//IL_00cd: 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;
						((StatusEffect)this).m_name = "$se_path_dirt_name";
						((StatusEffect)this).m_tooltip = "$se_path_dirt_tooltip";
						break;
					case PathType.PavedPath:
						value = Configs.StaminaDrainPaved.Value;
						((StatusEffect)this).m_name = "$se_path_paved_name";
						((StatusEffect)this).m_tooltip = "$se_path_paved_tooltip";
						break;
					case PathType.None:
						Log.Info((object)"No path detected, not applying stamina drain", (ushort)0);
						return;
					default:
						throw new ArgumentOutOfRangeException("_pathType");
					}
					drain *= Mathf.Max(value, 0.0001f);
					if (PlayerExt.IsReady(Player.m_localPlayer) && PathDetect.IsRunning)
					{
						Log.Info((object)$"Stamina Drain: {1f / (baseDrain / drain):P0}\tPathType: {_pathType} : {PathDetect.GroundMaterial}", (ushort)0);
					}
				}
			}
		}

		private static PathEffect _pathEffect;

		private static SnowEffect _snowEffect;

		private static bool _initialized;

		public static void Init()
		{
			_pathEffect = ScriptableObject.CreateInstance<PathEffect>();
			_snowEffect = ScriptableObject.CreateInstance<SnowEffect>();
			ObjectDB.instance.m_StatusEffects.Add((StatusEffect)(object)_pathEffect);
			ObjectDB.instance.m_StatusEffects.Add((StatusEffect)(object)_snowEffect);
			_initialized = true;
		}

		public static void Shutdown()
		{
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				ObjectDB.instance.m_StatusEffects.Remove((StatusEffect)(object)_pathEffect);
				ObjectDB.instance.m_StatusEffects.Remove((StatusEffect)(object)_snowEffect);
			}
		}

		public static void UpdateStep()
		{
			if (PathDetect.IsRunningOnPath)
			{
				RemoveEffect(_snowEffect);
				ApplyEffect(_pathEffect);
			}
			else if (PathDetect.IsRunningOnSnow && Configs.MoveSpeedSnow.Value < 1f)
			{
				RemoveEffect(_pathEffect);
				ApplyEffect(_snowEffect);
			}
		}

		private static void ApplyEffect(BaseEffect effect)
		{
			if (PlayerExt.IsReady(Player.m_localPlayer))
			{
				if (effect.IsExpired)
				{
					((Character)Player.m_localPlayer).GetSEMan().AddStatusEffect((StatusEffect)(object)effect, false, 0, 0f);
				}
				effect.initTime = Time.time;
			}
		}

		private static void RemoveEffect(BaseEffect effect)
		{
			if (PlayerExt.IsReady(Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).GetSEMan().RemoveStatusEffect((StatusEffect)(object)effect, false);
				effect.initTime = 0f;
			}
		}

		public static void Update()
		{
			if (_initialized)
			{
				if (_pathEffect.IsExpired && !PathDetect.IsRunningOnPath)
				{
					RemoveEffect(_pathEffect);
				}
				if (_snowEffect.IsExpired && !PathDetect.IsRunningOnSnow)
				{
					RemoveEffect(_snowEffect);
				}
			}
		}
	}
}