using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("WatchWhereYouStab")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WatchWhereYouStab")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
public static class ConfigFileManager
{
internal static string ConfigFileName;
internal static string ConfigFileFullPath;
internal static DateTime lastRead = DateTime.MinValue;
private static readonly Dictionary<string, int> _sectionToSectionNumber = new Dictionary<string, int>();
private static readonly Dictionary<string, int> _sectionToSettingOrder = new Dictionary<string, int>();
private static readonly List<string> ConfigManagerGUIDs = new List<string> { "_shudnal.ConfigurationManager", "com.bepis.bepinex.configurationmanager" };
private static BaseUnityPlugin _configManager = null;
private const string WindowChangedEventName = "DisplayingWindowChanged";
private const string DisplayingWindowName = "DisplayingWindow";
private static PropertyInfo _dispWindowInfo = null;
private static BaseUnityPlugin ConfigManager
{
get
{
if ((Object)(object)_configManager == (Object)null)
{
foreach (string configManagerGUID in ConfigManagerGUIDs)
{
if (Chainloader.PluginInfos.TryGetValue(configManagerGUID, out var value) && Object.op_Implicit((Object)(object)value.Instance))
{
_configManager = value.Instance;
break;
}
}
}
return _configManager;
}
}
private static PropertyInfo DisplayWindowInfo
{
get
{
if ((object)_dispWindowInfo == null)
{
_dispWindowInfo = ((object)ConfigManager).GetType().GetProperty("DisplayingWindow");
}
return _dispWindowInfo;
}
}
internal static event Action OnConfigFileReloaded;
internal static event Action OnConfigWindowClosed;
private static string GetOrderedSectionName(string section)
{
if (!_sectionToSectionNumber.TryGetValue(section, out var value))
{
value = _sectionToSectionNumber.Count + 1;
_sectionToSectionNumber[section] = value;
}
return $"{value} - {section}";
}
private static int GetSettingOrder(string section)
{
if (!_sectionToSettingOrder.TryGetValue(section, out var value))
{
value = 0;
}
_sectionToSettingOrder[section] = value - 1;
return value;
}
private static void InvokeOnConfigFileReloaded()
{
Action onConfigFileReloaded = ConfigFileManager.OnConfigFileReloaded;
if (onConfigFileReloaded != null)
{
onConfigFileReloaded.SafeInvoke();
}
}
private static void InvokeOnConfigWindowClosed()
{
Action onConfigWindowClosed = ConfigFileManager.OnConfigWindowClosed;
if (onConfigWindowClosed != null)
{
onConfigWindowClosed.SafeInvoke();
}
}
public static void Init(this ConfigFile configFile, string GUID, bool saveOnConfigSet = false)
{
configFile.SaveOnConfigSet = saveOnConfigSet;
ConfigFileName = GUID + ".cfg";
ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName);
}
public static bool DisableSaveOnConfigSet(this ConfigFile configFile)
{
bool saveOnConfigSet = configFile.SaveOnConfigSet;
configFile.SaveOnConfigSet = false;
return saveOnConfigSet;
}
public static ConfigEntry<T> BindConfigInOrder<T>(this ConfigFile configFile, string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true, bool sectionOrder = true, bool settingOrder = true, Action<ConfigEntryBase> drawer = null, ConfigurationManagerAttributes configAttributes = null)
{
section = (sectionOrder ? GetOrderedSectionName(section) : section);
int value2 = (settingOrder ? GetSettingOrder(section) : 0);
if (configAttributes == null)
{
configAttributes = new ConfigurationManagerAttributes();
}
configAttributes.Order = value2;
return configFile.BindConfig(section, name, value, description, acceptVals, synced, drawer, configAttributes);
}
public static ConfigEntry<T> BindConfig<T>(this ConfigFile configFile, string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true, Action<ConfigEntryBase> drawer = null, ConfigurationManagerAttributes configAttributes = null)
{
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
string extendedDescription = GetExtendedDescription(description, synced);
if (configAttributes == null)
{
configAttributes = new ConfigurationManagerAttributes();
}
configAttributes.IsAdminOnly = synced;
if (drawer != null)
{
configAttributes.CustomDrawer = drawer;
}
return configFile.Bind<T>(section, name, value, new ConfigDescription(extendedDescription, acceptVals, new object[1] { configAttributes }));
}
internal static string GetExtendedDescription(string description, bool synchronizedSetting)
{
return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]");
}
internal static void SetupWatcher(this ConfigFile configFile)
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
fileSystemWatcher.Changed += configFile.ReloadConfigFile;
fileSystemWatcher.Created += configFile.ReloadConfigFile;
fileSystemWatcher.Renamed += configFile.ReloadConfigFile;
fileSystemWatcher.IncludeSubdirectories = true;
fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
fileSystemWatcher.EnableRaisingEvents = true;
}
internal static void ReloadConfigFile(this ConfigFile configFile, object sender, FileSystemEventArgs eventArgs)
{
if (!File.Exists(ConfigFileFullPath))
{
return;
}
try
{
DateTime lastWriteTime = File.GetLastWriteTime(eventArgs.FullPath);
if (lastRead != lastWriteTime)
{
Log.LogInfo("Reloading config file");
bool saveOnConfigSet = configFile.DisableSaveOnConfigSet();
configFile.Reload();
configFile.SaveOnConfigSet = saveOnConfigSet;
InvokeOnConfigFileReloaded();
lastRead = lastWriteTime;
}
}
catch
{
Log.LogError("There was an issue loading your " + ConfigFileName);
Log.LogError("Please check your config entries for spelling and format!");
}
}
internal static void CheckForConfigManager(this ConfigFile config)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
if ((int)SystemInfo.graphicsDeviceType != 4 && !((Object)(object)ConfigManager == (Object)null))
{
Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged");
EventInfo @event = ((object)ConfigManager).GetType().GetEvent("DisplayingWindowChanged");
if (!(@event == null))
{
Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
@event.AddEventHandler(ConfigManager, handler);
}
}
}
private static void OnConfigManagerDisplayingWindowChanged(object sender, object e)
{
if (!(DisplayWindowInfo == null) && !(bool)DisplayWindowInfo.GetValue(ConfigManager, null))
{
InvokeOnConfigWindowClosed();
}
}
private static void SafeInvoke(this Action events)
{
if (events == null)
{
return;
}
Delegate[] invocationList = events.GetInvocationList();
for (int i = 0; i < invocationList.Length; i++)
{
Action action = (Action)invocationList[i];
try
{
action();
}
catch (Exception arg)
{
Log.LogWarning("Exception thrown at event " + new StackFrame(1).GetMethod().Name + $" in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{arg}");
}
}
}
}
public sealed class ConfigurationManagerAttributes
{
public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);
public bool? ShowRangeAsPercent;
public Action<ConfigEntryBase> CustomDrawer;
public CustomHotkeyDrawerFunc CustomHotkeyDrawer;
public bool? Browsable;
public string Category;
public object DefaultValue;
public bool? HideDefaultButton;
public bool? HideSettingName;
public string Description;
public string DispName;
public int? Order;
public bool? ReadOnly;
public bool? IsAdvanced;
public Func<object, string> ObjToStr;
public Func<string, object> StrToObj;
private bool isAdminOnly;
public bool IsAdminOnly
{
get
{
return isAdminOnly;
}
set
{
isAdminOnly = value;
}
}
}
namespace VerticalAttacks
{
[BepInPlugin("Searica.Valheim.WatchWhereYouStab", "WatchWhereYouStab", "0.2.0")]
internal sealed class WatchWhereYouStab : BaseUnityPlugin
{
internal const string Author = "Searica";
public const string PluginName = "WatchWhereYouStab";
public const string PluginGUID = "Searica.Valheim.WatchWhereYouStab";
public const string PluginVersion = "0.2.0";
public static WatchWhereYouStab Instance;
private const string MainSection = "Global";
internal ConfigEntry<float> MaxAngle;
internal ConfigEntry<bool> FixedHeight;
internal ConfigEntry<float> AngleCorrection;
public void Awake()
{
Instance = this;
Log.Init(((BaseUnityPlugin)this).Logger);
((BaseUnityPlugin)this).Config.Init("Searica.Valheim.WatchWhereYouStab");
Log.Verbosity = ((BaseUnityPlugin)this).Config.BindConfigInOrder("Global", "Verbosity", Log.LogLevel.Low, "Low will log basic information about the mod. Medium will log information that is useful for troubleshooting. High will log a lot of information, do not set it to this without good reason as it will slow Down your game.", null, synced: false);
MaxAngle = ((BaseUnityPlugin)this).Config.BindConfigInOrder("Global", "Max Attack Angle", 65f, "Angle you can aim melee attacks up or down by. This is only applied to attacks that currently have a smaller maximum angle than the configured value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 90f), synced: false);
FixedHeight = ((BaseUnityPlugin)this).Config.BindConfigInOrder("Global", "Fixed Attack Height", value: false, "Different melee attacks originate from different positions based on their vanilla animations. Enable this to make all melee attacks originate from the same position to make aiming more consistent.", null, synced: false);
AngleCorrection = ((BaseUnityPlugin)this).Config.BindConfigInOrder("Global", "Angle Correction", 10f, "Angle to apply as a correction to your current look direction. This can be used to offset the way the camera is usually pointing downwards. If positive then attacks will be aimed above the current camera direction, if negative they will be aimed below.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-30f, 30f), synced: false);
((BaseUnityPlugin)this).Config.Save();
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.WatchWhereYouStab");
Game.isModded = true;
((BaseUnityPlugin)this).Config.SetupWatcher();
}
public void OnDestroy()
{
((BaseUnityPlugin)this).Config.Save();
}
}
[HarmonyPatch]
internal static class AttackPatch
{
[HarmonyTranspiler]
[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
private static IEnumerable<CodeInstruction> DoMeleeAttack_Transpiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Attack), "GetMeleeAttackDir", (Type[])null, (Type[])null), (string)null)
};
CodeInstruction instructionAndAdvance = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(AttackPatch), "GetMeleeAttackDirection", (Type[])null, (Type[])null));
return new CodeMatcher(instructions, (ILGenerator)null).Start().MatchStartForward(array).ThrowIfNotMatch("Failed to match code in Attack.DoMeleeAttack!", Array.Empty<CodeMatch>())
.SetInstructionAndAdvance(instructionAndAdvance)
.ThrowIfInvalid("Failed to patch Attack.DoMeleeAttack!")
.InstructionEnumeration();
}
private static void GetMeleeAttackDirection(Attack attack, out Transform originJoint, out Vector3 attackDir)
{
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: 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)
//IL_009b: 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_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
Character val = default(Character);
if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !((Component)Player.m_localPlayer).TryGetComponent<Character>(ref val) || (Object)(object)attack.m_character != (Object)(object)val)
{
attack.GetMeleeAttackDir(ref originJoint, ref attackDir);
return;
}
attack.m_maxYAngle = Mathf.Max(attack.m_maxYAngle, WatchWhereYouStab.Instance.MaxAngle.Value);
if (WatchWhereYouStab.Instance.FixedHeight.Value)
{
attack.m_attackHeight = 1f;
}
originJoint = attack.GetAttackOrigin();
Vector3 forward = ((Component)attack.m_character).transform.forward;
Vector3 val2 = attack.m_character.GetAimDir(originJoint.position);
val2.x = forward.x;
val2.z = forward.z;
((Vector3)(ref val2)).Normalize();
float value = WatchWhereYouStab.Instance.AngleCorrection.Value;
if (value != 0f)
{
Vector3 val3 = Mathf.Sign(value) * Vector3.up;
val2 = Vector3.RotateTowards(val2, val3, (float)Math.PI / 180f * Mathf.Abs(value), 0f);
}
attackDir = Vector3.RotateTowards(((Component)attack.m_character).transform.forward, val2, (float)Math.PI / 180f * attack.m_maxYAngle, 10f);
Log.LogInfo("Doing the thing!");
}
}
}
namespace Logging
{
internal static class Log
{
internal enum LogLevel
{
Low,
Medium,
High
}
private static ManualLogSource logSource;
internal static ConfigEntry<LogLevel> Verbosity { get; set; }
internal static LogLevel VerbosityLevel => Verbosity.Value;
internal static bool IsVerbosityLow => Verbosity.Value >= LogLevel.Low;
internal static bool IsVerbosityMedium => Verbosity.Value >= LogLevel.Medium;
internal static bool IsVerbosityHigh => Verbosity.Value >= LogLevel.High;
internal static void Init(ManualLogSource logSource)
{
Log.logSource = logSource;
}
internal static void LogDebug(object data)
{
logSource.LogDebug(data);
}
internal static void LogError(object data)
{
logSource.LogError(data);
}
internal static void LogFatal(object data)
{
logSource.LogFatal(data);
}
internal static void LogMessage(object data)
{
logSource.LogMessage(data);
}
internal static void LogWarning(object data)
{
logSource.LogWarning(data);
}
internal static void LogInfo(object data, LogLevel level = LogLevel.Low)
{
if (Verbosity == null || VerbosityLevel >= level)
{
logSource.LogInfo(data);
}
}
internal static void LogGameObject(GameObject prefab, bool includeChildren = false)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Expected O, but got Unknown
LogInfo("***** " + ((Object)prefab).name + " *****");
Component[] components = prefab.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
LogComponent(components[i]);
}
if (!includeChildren)
{
return;
}
LogInfo("***** " + ((Object)prefab).name + " (children) *****");
foreach (Transform item in prefab.transform)
{
Transform val = item;
if (Object.op_Implicit((Object)(object)val))
{
LogInfo(" - " + ((Object)val).name);
components = ((Component)val).GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
LogComponent(components[i]);
}
}
}
}
internal static void LogComponent(Component compo)
{
if (!Object.op_Implicit((Object)(object)compo))
{
return;
}
try
{
LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
}
catch (Exception ex)
{
LogError(ex.ToString());
LogWarning("Could not get type name for component!");
return;
}
try
{
foreach (PropertyInfo declaredProperty in AccessTools.GetDeclaredProperties(((object)compo).GetType()))
{
try
{
LogInfo($" - {declaredProperty.Name} = {declaredProperty.GetValue(compo)}");
}
catch (Exception ex2)
{
LogError(ex2.ToString());
LogWarning("Could not get property: " + declaredProperty.Name + " for component!");
}
}
}
catch (Exception ex3)
{
LogError(ex3.ToString());
LogWarning("Could not get properties for component!");
}
try
{
foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(((object)compo).GetType()))
{
try
{
LogInfo($" - {declaredField.Name} = {declaredField.GetValue(compo)}");
}
catch (Exception ex4)
{
LogError(ex4.ToString());
LogWarning("Could not get field: " + declaredField.Name + " for component!");
}
}
}
catch (Exception ex5)
{
LogError(ex5.ToString());
LogWarning("Could not get fields for component!");
}
}
}
}