Decompiled source of PassWard v1.3.0

PassWard.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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 System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComfyLib;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PassWard")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PassWard")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f51143e3-8886-4bc6-901c-89f307cc9714")]
[assembly: AssemblyFileVersion("1.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.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;
		}
	}
}
namespace PassWard
{
	public static class PluginConfig
	{
		public enum UserListSeperator
		{
			Newline,
			Comma
		}

		public enum UserListSorting
		{
			Unsorted,
			Alphabetically,
			ReverseAlphabetically
		}

		public static ConfigEntry<bool> IsModEnabled { get; private set; }

		public static ConfigEntry<KeyboardShortcut> EnterPasswordKey { get; private set; }

		public static ConfigEntry<KeyboardShortcut> RemovePasswordKey { get; private set; }

		public static ConfigEntry<UserListSeperator> WardHoverTextUserListSeparator { get; private set; }

		public static ConfigEntry<UserListSorting> WardHoverTextUserListSorting { get; private set; }

		public static void BindConfig(ConfigFile config)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			IsModEnabled = config.BindInOrder("_Global", "isModEnabled", defaultValue: true, "Globally enable or disable this mod.");
			EnterPasswordKey = config.BindInOrder<KeyboardShortcut>("Hotkeys", "enterPasswordShortcut", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Enter password into a passworded ward OR assign password to own ward.");
			RemovePasswordKey = config.BindInOrder<KeyboardShortcut>("Hotkeys", "removePasswordKey", new KeyboardShortcut((KeyCode)114, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Removes password on player's own passworded ward.");
			WardHoverTextUserListSeparator = config.BindInOrder("HoverText", "userListSeparator", UserListSeperator.Newline, "Separator to use between player names for a ward's hover-text.");
			WardHoverTextUserListSorting = config.BindInOrder("HoverText", "userListSorting", UserListSorting.Unsorted, "What sorting (if any) to use for player names for a ward's hover-text.");
			WardHoverTextUserListSorting.OnSettingChanged<UserListSorting>(WardManager.ClearCachedPermittedPlayerNames);
		}
	}
	public sealed class TryPasswordReceiver : TextReceiver
	{
		private readonly PrivateArea _privateArea;

		public TryPasswordReceiver(PrivateArea privateArea)
		{
			_privateArea = privateArea;
		}

		public string GetText()
		{
			return string.Empty;
		}

		public void SetText(string enteredPassword)
		{
			int @int = _privateArea.m_nview.GetZDO().GetInt(1595635768, -1);
			if (@int == -1)
			{
				WardManager.ShowMessage("No password on ward.");
			}
			else if (StringExtensionMethods.GetStableHashCode(enteredPassword) != @int)
			{
				WardManager.ShowMessage("Incorrect password.");
			}
			else
			{
				WardManager.OptPlayerIn(_privateArea);
			}
		}
	}
	public sealed class WardPasswordReceiver : TextReceiver
	{
		private readonly PrivateArea _privateArea;

		public WardPasswordReceiver(PrivateArea privateArea)
		{
			_privateArea = privateArea;
		}

		public string GetText()
		{
			return string.Empty;
		}

		public void SetText(string password)
		{
			_privateArea.m_nview.GetZDO().Set(1595635768, StringExtensionMethods.GetStableHashCode(password), false);
			WardManager.ShowMessage("Password set.");
		}
	}
	public static class WardManager
	{
		public const int GuardStoneHash = -1024209535;

		public const int PasswordHash = 1595635768;

		private static readonly List<string> _cachedPlayerNames = new List<string>(100);

		private static ZDOID _lastZDOID = ZDOID.None;

		private static uint _lastDataRevision = uint.MaxValue;

		private static int[] _cachedPuIdHashCodes = Array.Empty<int>();

		private static int[] _cachedPuNameHashCodes = Array.Empty<int>();

		public static void OptPlayerIn(PrivateArea privateArea)
		{
			if (!Object.op_Implicit((Object)(object)privateArea) || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				PassWard.LogError("Error opting-in after password success.");
				return;
			}
			long playerID = Player.m_localPlayer.GetPlayerID();
			if (privateArea.IsPermitted(playerID))
			{
				ShowMessage("Already opted-in.");
				return;
			}
			privateArea.AddPermitted(playerID, Player.m_localPlayer.GetPlayerName());
			ShowMessage("Password accepted.");
			Talker val = default(Talker);
			if (((Component)Player.m_localPlayer).TryGetComponent<Talker>(ref val))
			{
				val.Say((Type)1, "[PassWard] " + privateArea.GetCreatorName() + "'s Ward: password accepted.");
			}
		}

		public static void AddPasswordHoverText(PrivateArea privateArea, StringBuilder hoverText)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			bool flag = HasPassword(privateArea);
			if (privateArea.m_piece.IsCreator())
			{
				if (flag)
				{
					hoverText.Append("\n<size=18>[<color=yellow>").Append(PluginConfig.RemovePasswordKey.Value).Append("</color>] Remove password.</size>");
				}
				hoverText.Append("\n<size=18>[<color=yellow>").Append(PluginConfig.EnterPasswordKey.Value).Append("</color>] ")
					.Append(flag ? "Change password.</size>" : "Add password.</size>");
			}
			else if (flag)
			{
				hoverText.Append("\n\n<size=18><color=green>Password enabled</color>\n[<color=yellow>").Append(PluginConfig.EnterPasswordKey.Value).Append("</color>] Enter password.</size>");
			}
			else
			{
				hoverText.Append("\n\n<size=18><color=red>No password</color></size>");
			}
		}

		public static void EnterPassword(PrivateArea privateArea)
		{
			bool flag = HasPassword(privateArea);
			if (privateArea.m_piece.IsCreator())
			{
				WardPasswordReceiver wardPasswordReceiver = new WardPasswordReceiver(privateArea);
				TextInput.instance.RequestText((TextReceiver)(object)wardPasswordReceiver, flag ? "Change password" : "Set password", 32);
			}
			else if (!flag)
			{
				ShowMessage("No password assigned to this ward. Cannot opt-in using password.");
			}
			else
			{
				TryPasswordReceiver tryPasswordReceiver = new TryPasswordReceiver(privateArea);
				TextInput.instance.RequestText((TextReceiver)(object)tryPasswordReceiver, "Enter password", 32);
			}
		}

		public static void RemovePassword(PrivateArea privateArea)
		{
			if (!privateArea.m_piece.IsCreator())
			{
				ShowMessage("You do not own this ward. Cannot remove password.");
				return;
			}
			if (!HasPassword(privateArea))
			{
				ShowMessage("No password on this ward to remove.");
				return;
			}
			privateArea.m_nview.m_zdo.Set(1595635768, -1, false);
			ShowMessage("Password removed.");
		}

		public static bool HasPassword(PrivateArea privateArea)
		{
			int num = default(int);
			if (privateArea.m_nview.m_zdo.GetInt(1595635768, ref num))
			{
				return num != -1;
			}
			return false;
		}

		public static void ShowMessage(string message)
		{
			if (Object.op_Implicit((Object)(object)MessageHud.instance))
			{
				MessageHud.instance.ShowMessage((MessageType)1, message, 0, (Sprite)null, false);
			}
		}

		public static void ClearCachedPermittedPlayerNames()
		{
			//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)
			_lastZDOID = ZDOID.None;
			_lastDataRevision = uint.MaxValue;
			_cachedPlayerNames.Clear();
		}

		public static List<string> GetCachedPermittedPlayerNames(ZDO zdo)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (_lastZDOID == zdo.m_uid && _lastDataRevision == zdo.DataRevision)
			{
				return _cachedPlayerNames;
			}
			_lastZDOID = zdo.m_uid;
			_lastDataRevision = zdo.DataRevision;
			_cachedPlayerNames.Clear();
			int num = Mathf.Max(zdo.GetInt(ZDOVars.s_permitted, 0), 0);
			CachePuIdNameHashCodes(num);
			for (int i = 0; i < num; i++)
			{
				if (zdo.GetLong(_cachedPuIdHashCodes[i], 0L) != 0L)
				{
					string @string = zdo.GetString(_cachedPuNameHashCodes[i], string.Empty);
					if (@string.Length > 0)
					{
						_cachedPlayerNames.Add(@string);
					}
				}
			}
			switch (PluginConfig.WardHoverTextUserListSorting.Value)
			{
			case PluginConfig.UserListSorting.Alphabetically:
				_cachedPlayerNames.Sort(StringComparer.OrdinalIgnoreCase);
				break;
			case PluginConfig.UserListSorting.ReverseAlphabetically:
				_cachedPlayerNames.Sort(StringComparer.OrdinalIgnoreCase);
				_cachedPlayerNames.Reverse();
				break;
			}
			return _cachedPlayerNames;
		}

		private static void CachePuIdNameHashCodes(int capacity)
		{
			int num = Mathf.Min(_cachedPuIdHashCodes.Length, _cachedPuNameHashCodes.Length);
			if (capacity > 0 && capacity >= num)
			{
				Array.Resize(ref _cachedPuIdHashCodes, capacity);
				Array.Resize(ref _cachedPuNameHashCodes, capacity);
				for (int i = num; i < capacity; i++)
				{
					_cachedPuIdHashCodes[i] = StringExtensionMethods.GetStableHashCode($"pu_id{i}");
					_cachedPuNameHashCodes[i] = StringExtensionMethods.GetStableHashCode($"pu_name{i}");
				}
			}
		}
	}
	[BepInPlugin("bruce.valheim.mods.passward", "PassWard", "1.3.0")]
	public sealed class PassWard : BaseUnityPlugin
	{
		public const string PluginGuid = "bruce.valheim.mods.passward";

		public const string PluginName = "PassWard";

		public const string PluginVersion = "1.3.0";

		private static ManualLogSource _logger;

		private void Awake()
		{
			_logger = ((BaseUnityPlugin)this).Logger;
			PluginConfig.BindConfig(((BaseUnityPlugin)this).Config);
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "bruce.valheim.mods.passward");
		}

		public static void LogError(object obj)
		{
			_logger.LogError((object)$"[{DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo)}] {obj}");
		}
	}
	[HarmonyPatch(typeof(Game))]
	internal static class GamePatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix()
		{
			if (PluginConfig.IsModEnabled.Value)
			{
				WardManager.ClearCachedPermittedPlayerNames();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("OnDestroy")]
		private static void OnDestroyPrefix()
		{
			if (PluginConfig.IsModEnabled.Value)
			{
				WardManager.ClearCachedPermittedPlayerNames();
			}
		}
	}
	[HarmonyPatch(typeof(Player))]
	internal static class PlayerPatch
	{
		[HarmonyTranspiler]
		[HarmonyPatch("Update")]
		private static IEnumerable<CodeInstruction> UpdateTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			return new CodeMatcher(instructions, (ILGenerator)null).Start().MatchStartForward((CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(Player), "UpdateHover", (Type[])null, (Type[])null), (string)null)
			}).ThrowIfInvalid("Could not patch Player.Update()! (update-hover)")
				.Advance(1)
				.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2]
				{
					new CodeInstruction(OpCodes.Ldloc_1, (object)null),
					new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(PlayerPatch), "UpdateHoverPostDelegate", (Type[])null, (Type[])null))
				})
				.InstructionEnumeration();
		}

		private static void UpdateHoverPostDelegate(bool takeInput)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (takeInput && PluginConfig.IsModEnabled.Value && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				KeyboardShortcut value = PluginConfig.EnterPasswordKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_hovering) && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_hovering.TryGetComponentInParent<PrivateArea>(out PrivateArea component)))
				{
					WardManager.EnterPassword(component);
				}
				value = PluginConfig.RemovePasswordKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_hovering) && Object.op_Implicit((Object)(object)Player.m_localPlayer.m_hovering.TryGetComponentInParent<PrivateArea>(out component)))
				{
					WardManager.RemovePassword(component);
				}
			}
		}

		public static T TryGetComponentInParent<T>(this GameObject gameObject, out T component) where T : Component
		{
			component = gameObject.GetComponentInParent<T>();
			return component;
		}
	}
	[HarmonyPatch(typeof(PrivateArea))]
	internal static class PrivateAreaPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("AddUserList")]
		private static bool AddUserList(PrivateArea __instance, StringBuilder text)
		{
			if (PluginConfig.IsModEnabled.Value)
			{
				AddUserListUsingSeparator(__instance, text);
				return false;
			}
			return true;
		}

		public static void AddUserListUsingSeparator(PrivateArea privateArea, StringBuilder text)
		{
			List<string> cachedPermittedPlayerNames = WardManager.GetCachedPermittedPlayerNames(privateArea.m_nview.m_zdo);
			int count = cachedPermittedPlayerNames.Count;
			text.Append("\n$piece_guardstone_additional: ");
			if (count >= 1)
			{
				string value = ((PluginConfig.WardHoverTextUserListSeparator.Value == PluginConfig.UserListSeperator.Newline) ? "\n" : ", ");
				text.Append(cachedPermittedPlayerNames[0]);
				for (int i = 1; i < count; i++)
				{
					text.Append(value).Append(cachedPermittedPlayerNames[i]);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("AddUserList")]
		private static void AddUserListPostfix(PrivateArea __instance, StringBuilder text)
		{
			if (PluginConfig.IsModEnabled.Value)
			{
				WardManager.AddPasswordHoverText(__instance, text);
			}
		}
	}
}
namespace ComfyLib
{
	public static class ConfigFileExtensions
	{
		internal sealed class ConfigurationManagerAttributes
		{
			public Action<ConfigEntryBase> CustomDrawer;

			public bool? Browsable;

			public bool? HideDefaultButton;

			public bool? HideSettingName;

			public bool? IsAdvanced;

			public int? Order;

			public bool? ReadOnly;
		}

		private static readonly Dictionary<string, int> _sectionToSettingOrder = new Dictionary<string, int>();

		private static int GetSettingOrder(string section)
		{
			if (!_sectionToSettingOrder.TryGetValue(section, out var value))
			{
				value = 0;
			}
			_sectionToSettingOrder[section] = value - 1;
			return value;
		}

		public static ConfigEntry<T> BindInOrder<T>(this ConfigFile config, string section, string key, T defaultValue, string description, AcceptableValueBase acceptableValues, bool browsable = true, bool hideDefaultButton = false, bool hideSettingName = false, bool isAdvanced = false, bool readOnly = false)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, acceptableValues, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = browsable,
					CustomDrawer = null,
					HideDefaultButton = hideDefaultButton,
					HideSettingName = hideSettingName,
					IsAdvanced = isAdvanced,
					Order = GetSettingOrder(section),
					ReadOnly = readOnly
				}
			}));
		}

		public static ConfigEntry<T> BindInOrder<T>(this ConfigFile config, string section, string key, T defaultValue, string description, Action<ConfigEntryBase> customDrawer = null, bool browsable = true, bool hideDefaultButton = false, bool hideSettingName = false, bool isAdvanced = false, bool readOnly = false)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			return config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = browsable,
					CustomDrawer = customDrawer,
					HideDefaultButton = hideDefaultButton,
					HideSettingName = hideSettingName,
					IsAdvanced = isAdvanced,
					Order = GetSettingOrder(section),
					ReadOnly = readOnly
				}
			}));
		}

		public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action settingChangedHandler)
		{
			configEntry.SettingChanged += delegate
			{
				settingChangedHandler();
			};
		}

		public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action<T> settingChangedHandler)
		{
			configEntry.SettingChanged += delegate(object _, EventArgs eventArgs)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				settingChangedHandler((T)((SettingChangedEventArgs)eventArgs).ChangedSetting.BoxedValue);
			};
		}

		public static void OnSettingChanged<T>(this ConfigEntry<T> configEntry, Action<ConfigEntry<T>> settingChangedHandler)
		{
			configEntry.SettingChanged += delegate(object _, EventArgs eventArgs)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				settingChangedHandler((ConfigEntry<T>)((SettingChangedEventArgs)eventArgs).ChangedSetting.BoxedValue);
			};
		}
	}
}