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<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]
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 IsRunningOnPath
{
get
{
if (IsRunning)
{
return IsOnPath;
}
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_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)
{
//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.4")]
[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.4";
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();
}
}
internal 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_0107: 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 *= Mathf.Max(value, 0.0001f);
base.m_tooltip = StringExt.Localize($"$se_runstamina {value * 100f}%");
base.m_icon = (Configs.ShowStatusIcon.Value ? _icon : null);
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 Effect _buff;
private const float Cooldown = 1f;
private static float _activationTime;
private static bool IsExpired => Time.time >= _activationTime + 1f;
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(Player.m_localPlayer) && PathDetect.IsRunningOnPath)
{
ApplyBuff();
}
}
private static void ApplyBuff()
{
if (IsExpired)
{
((Character)Player.m_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(Player.m_localPlayer))
{
((Character)Player.m_localPlayer).GetSEMan().RemoveStatusEffect((StatusEffect)(object)_buff, false);
}
}
public static void CheckPath()
{
if (IsExpired && !PathDetect.IsRunningOnPath)
{
RemoveBuff();
}
}
}
}