using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
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 DodgeShortcut.Configs;
using DodgeShortcut.Extensions;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("DodgeShortcut")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DodgeShortcut")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("57ebdc73-fd85-484c-9e08-2b838274af44")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
namespace DodgeShortcut
{
internal enum DodgeDir
{
CharacterDir,
LookDir
}
[BepInPlugin("Searica.Valheim.DodgeShortcut", "DodgeShortcut", "1.2.0")]
internal sealed class DodgeShortcut : BaseUnityPlugin
{
public const string PluginName = "DodgeShortcut";
internal const string Author = "Searica";
public const string PluginGUID = "Searica.Valheim.DodgeShortcut";
public const string PluginVersion = "1.2.0";
private static readonly string MainSection = ConfigManager.SetStringPriority("Global", 1);
private static readonly string MechanicsSection = "Mechanics";
private static ConfigEntry<bool> ModEnabled;
private static ConfigEntry<KeyCode> DodgeKey;
private static ConfigEntry<DodgeDir> DefaultDir;
internal static bool IsModEnabled => ModEnabled.Value;
internal static KeyCode GetDodgeKey()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
return DodgeKey.Value;
}
internal static DodgeDir GetDefaultDir()
{
return DefaultDir.Value;
}
public void Awake()
{
Log.Init(((BaseUnityPlugin)this).Logger);
ConfigManager.Init("Searica.Valheim.DodgeShortcut", ((BaseUnityPlugin)this).Config);
SetUpConfig();
ConfigManager.SaveOnConfigSet(value: true);
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.DodgeShortcut");
Game.isModded = true;
ConfigManager.SetupWatcher();
}
public static void SetUpConfig()
{
ModEnabled = ConfigManager.BindConfig(MainSection, "EnableMod", value: true, "Globally enable or disable this mod.");
Log.Verbosity = ConfigManager.BindConfig(MainSection, "Verbosity", 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.");
DodgeKey = ConfigManager.BindConfig<KeyCode>(MechanicsSection, "DodgeShortcut", (KeyCode)308, "Set the key to press to dodge in the direction your character is moving.\nIf LeftAlt conflicts with other mods, I recommend setting the dodge key to the back button on your mouse.");
DefaultDir = ConfigManager.BindConfig(MechanicsSection, "DefaultDodgeDir", DodgeDir.CharacterDir, "Default direction that character dodges in if the dodge shortcut key is pressed while not moving. Can be set to the direction the character is facing, or the direction the camera is facing.");
}
public void OnDestroy()
{
ConfigManager.Save();
}
}
[HarmonyPatch(typeof(Player))]
internal static class PlayerPatch
{
[HarmonyPrefix]
[HarmonyPatch("Update")]
private static void DodgePatch()
{
//IL_008e: 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_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: 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)
if (!DodgeShortcut.IsModEnabled)
{
return;
}
if ((Object)(object)Player.m_localPlayer == (Object)null)
{
Log.LogInfo("Local player is null.", LogLevel.High);
}
else if (!((Character)Player.m_localPlayer).IsTeleporting() && !((Character)Player.m_localPlayer).IsAttachedToShip() && !((Character)Player.m_localPlayer).InPlaceMode() && !((Component)((Terminal)Console.instance).m_chatWindow).gameObject.activeInHierarchy && !((Component)((Terminal)Chat.instance).m_chatWindow).gameObject.activeInHierarchy && !TextInput.IsVisible() && !StoreGui.IsVisible() && !InventoryGui.IsVisible() && !Menu.IsVisible() && Input.GetKeyDown(DodgeShortcut.GetDodgeKey()))
{
Vector3 val = ((Character)Player.m_localPlayer).m_moveDir;
val.y = 0f;
if (((Vector3)(ref val)).magnitude < 0.1f)
{
val = ((DodgeShortcut.GetDefaultDir() != 0) ? ((Character)Player.m_localPlayer).m_lookDir : (((Component)Player.m_localPlayer).transform.rotation * Vector3.forward));
val.y = 0f;
}
((Vector3)(ref val)).Normalize();
Log.LogInfo($"Dodge Vector: {val}", LogLevel.Medium);
Player.m_localPlayer.Dodge(val);
}
}
}
internal enum LogLevel
{
Low,
Medium,
High
}
internal static class Log
{
private static ManualLogSource logSource;
internal static ConfigEntry<LogLevel> Verbosity { get; set; }
internal static LogLevel VerbosityLevel => Verbosity.Value;
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 LogInfo(object data, LogLevel level = LogLevel.Low)
{
if (VerbosityLevel >= level)
{
logSource.LogInfo(data);
}
}
internal static void LogMessage(object data)
{
logSource.LogMessage(data);
}
internal static void LogWarning(object data)
{
logSource.LogWarning(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;
LogInfo(" - " + ((Object)((Component)val).gameObject).name);
components = ((Component)val).gameObject.GetComponents<Component>();
for (int i = 0; i < components.Length; i++)
{
LogComponent(components[i]);
}
}
}
internal static void LogComponent(Component compo)
{
LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
PropertyInfo[] properties = ((object)compo).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
foreach (PropertyInfo propertyInfo in properties)
{
LogInfo($" - {propertyInfo.Name} = {propertyInfo.GetValue(compo)}");
}
FieldInfo[] fields = ((object)compo).GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
foreach (FieldInfo fieldInfo in fields)
{
LogInfo($" - {fieldInfo.Name} = {fieldInfo.GetValue(compo)}");
}
}
}
}
namespace DodgeShortcut.Extensions
{
internal static class EventExtensions
{
public 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 ex)
{
Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
}
}
}
public static void SafeInvoke<TArg1>(this Action<TArg1> events, TArg1 arg1)
{
if (events == null)
{
return;
}
Delegate[] invocationList = events.GetInvocationList();
for (int i = 0; i < invocationList.Length; i++)
{
Action<TArg1> action = (Action<TArg1>)invocationList[i];
try
{
action(arg1);
}
catch (Exception ex)
{
Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
}
}
}
public static void SafeInvoke<TArg1, TArg2>(this Action<TArg1, TArg2> events, TArg1 arg1, TArg2 arg2)
{
if (events == null)
{
return;
}
Delegate[] invocationList = events.GetInvocationList();
for (int i = 0; i < invocationList.Length; i++)
{
Action<TArg1, TArg2> action = (Action<TArg1, TArg2>)invocationList[i];
try
{
action(arg1, arg2);
}
catch (Exception ex)
{
Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}");
}
}
}
public static void SafeInvoke<TEventArg>(this EventHandler<TEventArg> events, object sender, TEventArg arg1)
{
if (events == null)
{
return;
}
Delegate[] invocationList = events.GetInvocationList();
for (int i = 0; i < invocationList.Length; i++)
{
EventHandler<TEventArg> eventHandler = (EventHandler<TEventArg>)invocationList[i];
try
{
eventHandler(sender, arg1);
}
catch (Exception ex)
{
Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {eventHandler.Method.DeclaringType.Name}.{eventHandler.Method.Name}:\n{ex}");
}
}
}
}
internal static class ReflectionUtils
{
public const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;
internal static MethodInfo GetMethod(Type type, string name, Type[] types)
{
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name == name && HasMatchingParameterTypes(0, types, methodInfo.GetParameters()))
{
return methodInfo;
}
}
return null;
}
internal static MethodInfo GetGenericMethod(Type type, string name, int genericParameterCount, Type[] types)
{
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.IsGenericMethod && methodInfo.ContainsGenericParameters && methodInfo.Name == name && HasMatchingParameterTypes(genericParameterCount, types, methodInfo.GetParameters()))
{
return methodInfo;
}
}
return null;
}
private static bool HasMatchingParameterTypes(int genericParameterCount, Type[] types, ParameterInfo[] parameters)
{
if (parameters.Length < genericParameterCount || parameters.Length != types.Length)
{
return false;
}
int num = 0;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType.IsGenericParameter)
{
num++;
}
else if (types[i] != parameters[i].ParameterType)
{
return false;
}
}
if (num != genericParameterCount)
{
return false;
}
return true;
}
}
}
namespace DodgeShortcut.Configs
{
internal static class ConfigManager
{
private static string ConfigFileName;
private static string ConfigFileFullPath;
private static ConfigFile configFile;
private static BaseUnityPlugin ConfigurationManager;
private const string ConfigManagerGUID = "com.bepis.bepinex.configurationmanager";
private const char ZWS = '\u200b';
internal static event Action OnConfigWindowClosed;
internal static event Action OnConfigFileReloaded;
private static void InvokeOnConfigWindowClosed()
{
ConfigManager.OnConfigWindowClosed?.SafeInvoke();
}
private static void InvokeOnConfigFileReloaded()
{
ConfigManager.OnConfigFileReloaded?.SafeInvoke();
}
internal static ConfigEntry<T> BindConfig<T>(string section, string name, T value, string description, AcceptableValueBase acceptVals = null)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
return configFile.Bind<T>(section, name, value, new ConfigDescription(description, acceptVals, Array.Empty<object>()));
}
internal static string SetStringPriority(string sectionName, int priority)
{
if (priority <= 0)
{
return sectionName;
}
return new string('\u200b', priority) + sectionName;
}
internal static void Init(string GUID, ConfigFile config, bool saveOnConfigSet = false)
{
configFile = config;
configFile.SaveOnConfigSet = saveOnConfigSet;
ConfigFileName = GUID + ".cfg";
ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName);
}
internal static bool DisableSaveOnConfigSet()
{
bool saveOnConfigSet = configFile.SaveOnConfigSet;
configFile.SaveOnConfigSet = false;
return saveOnConfigSet;
}
internal static void SaveOnConfigSet(bool value)
{
configFile.SaveOnConfigSet = value;
}
internal static void Save()
{
configFile.Save();
}
internal static void SetupWatcher()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
fileSystemWatcher.Changed += ReloadConfigFile;
fileSystemWatcher.Created += ReloadConfigFile;
fileSystemWatcher.Renamed += ReloadConfigFile;
fileSystemWatcher.IncludeSubdirectories = true;
fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
fileSystemWatcher.EnableRaisingEvents = true;
}
private static void ReloadConfigFile(object sender, FileSystemEventArgs e)
{
if (!File.Exists(ConfigFileFullPath))
{
return;
}
try
{
Log.LogInfo("Reloading config file", LogLevel.Medium);
bool value = DisableSaveOnConfigSet();
configFile.Reload();
SaveOnConfigSet(value);
InvokeOnConfigFileReloaded();
}
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()
{
//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 && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance))
{
ConfigurationManager = value.Instance;
Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged");
EventInfo @event = ((object)ConfigurationManager).GetType().GetEvent("DisplayingWindowChanged");
if (@event != null)
{
Action<object, object> action = OnConfigManagerDisplayingWindowChanged;
Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, action.Method);
@event.AddEventHandler(ConfigurationManager, handler);
}
}
}
private static void OnConfigManagerDisplayingWindowChanged(object sender, object e)
{
if (!(bool)((object)ConfigurationManager).GetType().GetProperty("DisplayingWindow").GetValue(ConfigurationManager, null))
{
InvokeOnConfigWindowClosed();
}
}
}
}