using System;
using System.Collections.Generic;
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 HarmonyLib;
using Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CameraTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CameraTweaks")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.3.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.1.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 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!");
}
}
}
}
namespace CameraTweaks
{
[BepInPlugin("Searica.Valheim.CameraTweaks", "CameraTweaks", "1.3.1")]
internal sealed class CameraTweaks : BaseUnityPlugin
{
internal const string Author = "Searica";
public const string PluginName = "CameraTweaks";
public const string PluginGUID = "Searica.Valheim.CameraTweaks";
public const string PluginVersion = "1.3.1";
internal static ConfigEntry<float> MaxDistance;
internal static ConfigEntry<float> MaxDistanceBoat;
internal static ConfigEntry<float> CameraFoV;
internal static ConfigEntry<bool> AlwaysFaceCamera;
private static bool ShouldUpdateCamera;
private static readonly string MainSection = "Global";
private static readonly string CameraSection = "Camera";
public void Awake()
{
Log.Init(((BaseUnityPlugin)this).Logger);
((BaseUnityPlugin)this).Config.Init("Searica.Valheim.CameraTweaks");
Log.Verbosity = ((BaseUnityPlugin)this).Config.BindConfigInOrder(MainSection, "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);
CameraFoV = ((BaseUnityPlugin)this).Config.BindConfigInOrder(CameraSection, "Field of View", 65f, "Camera field of view in degrees. Vanilla default is 65.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 120f), synced: false);
MaxDistance = ((BaseUnityPlugin)this).Config.BindConfigInOrder(CameraSection, "Max Distance", 6f, "Maximum distance you can zoom out to while on foot. Vanilla default is 6.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 20f), synced: false);
MaxDistanceBoat = ((BaseUnityPlugin)this).Config.BindConfigInOrder(CameraSection, "Max Distance (Boat)", 12f, "Maximum distance you can zoom out to while in a boat. Vanilla default is 6.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 20f), synced: false);
AlwaysFaceCamera = ((BaseUnityPlugin)this).Config.BindConfigInOrder(CameraSection, "Always Face Camera", value: false, "Controls whether the player character will always face in the direction of the crosshairs.", null, synced: false);
MaxDistance.SettingChanged += SetShouldUpdateCamera;
MaxDistance.SettingChanged += SetShouldUpdateCamera;
CameraFoV.SettingChanged += SetShouldUpdateCamera;
((BaseUnityPlugin)this).Config.Save();
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.CameraTweaks");
Game.isModded = true;
((BaseUnityPlugin)this).Config.SetupWatcher();
((BaseUnityPlugin)this).Config.CheckForConfigManager();
ConfigFileManager.OnConfigFileReloaded += UpdateCameraSettings;
ConfigFileManager.OnConfigWindowClosed += UpdateCameraSettings;
}
public void OnDestroy()
{
((BaseUnityPlugin)this).Config.Save();
}
private void SetShouldUpdateCamera(object obj, EventArgs e)
{
ShouldUpdateCamera |= !ShouldUpdateCamera;
}
private void UpdateCameraSettings()
{
if (ShouldUpdateCamera && (Object)(object)GameCamera.instance != (Object)null)
{
GameCamera.instance.m_maxDistance = MaxDistance.Value;
GameCamera.instance.m_maxDistanceBoat = MaxDistanceBoat.Value;
GameCamera.instance.m_fov = CameraFoV.Value;
GameCamera.instance.UpdateCamera(Time.unscaledDeltaTime);
ShouldUpdateCamera = false;
((BaseUnityPlugin)this).Config.Save();
}
}
}
[HarmonyPatch]
internal static class CameraPatches
{
[HarmonyPostfix]
[HarmonyPatch(typeof(GameCamera), "Awake")]
private static void GameCameraAwakePostfix(GameCamera __instance)
{
__instance.m_maxDistance = CameraTweaks.MaxDistance.Value;
__instance.m_maxDistanceBoat = CameraTweaks.MaxDistanceBoat.Value;
__instance.m_fov = CameraTweaks.CameraFoV.Value;
}
[HarmonyPrefix]
[HarmonyPriority(0)]
[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
public static void GameCamera_UpdateCamera_MaxDistBoat_Prefix(GameCamera __instance, ref float __state)
{
if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Character)Player.m_localPlayer).IsAttachedToShip())
{
__state = __instance.m_maxDistance;
__instance.m_maxDistance = __instance.m_maxDistanceBoat;
}
else
{
__state = -1f;
}
}
[HarmonyPostfix]
[HarmonyPriority(0)]
[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
public static void GameCamera_UpdateCamera_MaxDistBoat_Postfix(GameCamera __instance, float __state)
{
if (__state != -1f)
{
__instance.m_maxDistance = __state;
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Player), "AlwaysRotateCamera")]
public static bool AlwaysRotateCameraPrefix(Player __instance, ref bool __result)
{
if (CameraTweaks.AlwaysFaceCamera.Value && ((Humanoid)__instance).GetCurrentWeapon() != null && !((Character)__instance).InEmote())
{
__result = true;
return false;
}
__result = false;
return true;
}
}
}