Decompiled source of RunicBladeLongerDuration v1.3.1

RunicBladeLongerDuration.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using SideLoader;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RunicBladeLongerDuration;

[BepInPlugin("com.codex.outward.runicbladelongerduration", "Runic Blade Longer Duration", "1.3.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class RunicBladeLongerDurationPlugin : BaseUnityPlugin
{
	private class LegacyConfig
	{
		public bool HasDurationSeconds;

		public float DurationSeconds = 604800f;

		public bool HasRunicBladeCountsAsLexicon;

		public bool RunicBladeCountsAsLexicon = true;

		public bool HasRequireArcaneSyntaxForRunicBladeLexicon;

		public bool RequireArcaneSyntaxForRunicBladeLexicon;
	}

	private sealed class ConfigurationManagerAttributes
	{
		public Action<ConfigEntryBase> CustomDrawer { get; set; }

		public string DispName { get; set; }

		public int? Order { get; set; }
	}

	[HarmonyPatch(typeof(RunicBlade), "ActivateLocally")]
	private static class RunicBladeActivateLocallyPatch
	{
		private static void Prefix(RunicBlade __instance)
		{
			if ((Object)(object)__instance != (Object)null)
			{
				__instance.SummonLifeSpan = s_durationSeconds;
			}
		}
	}

	[HarmonyPatch(typeof(SummonedEquipment), "Activate")]
	private static class SummonedEquipmentActivatePatch
	{
		private static void Prefix(SummonedEquipment __instance, ref float _lifespan)
		{
			if (IsRunicSummonedEquipment(__instance) && _lifespan < s_durationSeconds)
			{
				_lifespan = s_durationSeconds;
			}
		}
	}

	[HarmonyPatch(typeof(SummonedEquipment), "RefreshLifespan")]
	private static class SummonedEquipmentRefreshLifespanPatch
	{
		private static void Prefix(SummonedEquipment __instance, ref float _lifeSpan)
		{
			if (IsRunicSummonedEquipment(__instance) && _lifeSpan < s_durationSeconds)
			{
				_lifeSpan = s_durationSeconds;
			}
		}
	}

	[HarmonyPatch(typeof(Item), "HasTag", new Type[] { typeof(Tag) })]
	private static class ItemHasTagPatch
	{
		private static void Postfix(Item __instance, Tag _tag, ref bool __result)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (IsRunicBlade(__instance) && IsLexiconTag(_tag))
			{
				if (!RunicBladeLexiconAllowed(__instance))
				{
					__result = false;
				}
				else if (!__result)
				{
					__result = true;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Item), "HasTag", new Type[]
	{
		typeof(IList<Tag>),
		typeof(bool)
	})]
	private static class ItemHasTagListPatch
	{
		private static void Postfix(Item __instance, IList<Tag> _tags, bool _perfectMatch, ref bool __result)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!IsRunicBlade(__instance) || _tags == null)
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < _tags.Count; i++)
			{
				if (IsLexiconTag(_tags[i]))
				{
					flag = true;
					break;
				}
			}
			if (flag && (!_perfectMatch || _tags.Count == 1))
			{
				if (!RunicBladeLexiconAllowed(__instance))
				{
					__result = false;
				}
				else if (!__result)
				{
					__result = true;
				}
			}
		}
	}

	private const string PluginGuid = "com.codex.outward.runicbladelongerduration";

	private const string SideLoaderGuid = "com.sinai.SideLoader";

	private const string PluginName = "Runic Blade Longer Duration";

	private const string PluginVersion = "1.3.1";

	private const int RunicBladeItemId = 2000100;

	private const int GreatRunicBladeItemId = 2100999;

	private const int ArcaneSyntaxSkillId = 8205180;

	private const float VanillaDurationSeconds = 180f;

	private const float DefaultDurationSeconds = 604800f;

	private const bool DefaultRunicBladeCountsAsLexicon = true;

	private const bool DefaultRequireArcaneSyntaxForRunicBladeLexicon = false;

	private static readonly string[] LexiconTag = new string[1] { "Lexicon" };

	private static float s_durationSeconds = 604800f;

	private static bool s_runicBladeCountsAsLexicon = true;

	private static bool s_requireArcaneSyntaxForRunicBladeLexicon = false;

	private readonly HashSet<string> _extendedSummonUids = new HashSet<string>();

	private ConfigEntry<float> _durationSecondsConfig;

	private ConfigEntry<bool> _runicBladeCountsAsLexiconConfig;

	private ConfigEntry<bool> _requireArcaneSyntaxForRunicBladeLexiconConfig;

	private float _durationSeconds = 604800f;

	private bool _updatingConfig;

	private static string PluginDirectory
	{
		get
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (!string.IsNullOrEmpty(directoryName))
			{
				return directoryName;
			}
			return ".";
		}
	}

	private void Awake()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		BindConfig();
		RefreshConfigValues();
		new Harmony("com.codex.outward.runicbladelongerduration").PatchAll(typeof(RunicBladeLongerDurationPlugin).Assembly);
		SL_Item.AddOnInstanceStartListener(2000100, (Action<Item>)OnRunicBladeInstanceStart);
		PatchRunicBladeEffects();
		Debug.Log((object)("[Runic Blade Longer Duration] Duration set to " + _durationSeconds.ToString("0", CultureInfo.InvariantCulture) + " seconds. Runic Blade counts as Lexicon: " + s_runicBladeCountsAsLexicon + ". Require Arcane Syntax for Runic Blade Lexicon: " + s_requireArcaneSyntaxForRunicBladeLexicon + "."));
	}

	private void BindConfig()
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Expected O, but got Unknown
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Expected O, but got Unknown
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Expected O, but got Unknown
		LegacyConfig legacyConfig = LoadLegacyConfig();
		_durationSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DurationSeconds", legacyConfig.HasDurationSeconds ? legacyConfig.DurationSeconds : 604800f, new ConfigDescription("Duration for Runic Blade and Great Runic Blade summons, in seconds. The mod clamps this to at least the vanilla 180 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(180f, 315360000f), new object[1]
		{
			new ConfigurationManagerAttributes
			{
				DispName = "Summon duration, seconds",
				Order = 30
			}
		}));
		_runicBladeCountsAsLexiconConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Runic Blade Lexicon", "RunicBladeCountsAsLexicon", !legacyConfig.HasRunicBladeCountsAsLexicon || legacyConfig.RunicBladeCountsAsLexicon, new ConfigDescription("If true, one-handed Runic Blade can count as a Lexicon for rune casting. If false, the mod only changes summon duration.", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				DispName = "Runic Blade counts as Lexicon",
				Order = 20
			}
		}));
		_requireArcaneSyntaxForRunicBladeLexiconConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Runic Blade Lexicon", "RequireArcaneSyntaxForRunicBladeLexicon", legacyConfig.HasRequireArcaneSyntaxForRunicBladeLexicon && legacyConfig.RequireArcaneSyntaxForRunicBladeLexicon, new ConfigDescription("If true, one-handed Runic Blade counts as a Lexicon only when the owner knows Arcane Syntax. This setting is ignored while RunicBladeCountsAsLexicon is false.", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				CustomDrawer = DrawRequireArcaneSyntaxConfig,
				DispName = "Require Arcane Syntax",
				Order = 10
			}
		}));
		_durationSecondsConfig.SettingChanged += OnConfigSettingChanged;
		_runicBladeCountsAsLexiconConfig.SettingChanged += OnConfigSettingChanged;
		_requireArcaneSyntaxForRunicBladeLexiconConfig.SettingChanged += OnConfigSettingChanged;
		((BaseUnityPlugin)this).Config.Save();
	}

	private void OnConfigSettingChanged(object sender, EventArgs e)
	{
		if (!_updatingConfig)
		{
			RefreshConfigValues(saveConfig: true);
			_extendedSummonUids.Clear();
			PatchRunicBladeEffects();
			ExtendAlreadySummonedRunicWeapons();
			Debug.Log((object)("[Runic Blade Longer Duration] Config changed. Duration set to " + _durationSeconds.ToString("0", CultureInfo.InvariantCulture) + " seconds. Runic Blade counts as Lexicon: " + s_runicBladeCountsAsLexicon + ". Require Arcane Syntax for Runic Blade Lexicon: " + s_requireArcaneSyntaxForRunicBladeLexicon + "."));
		}
	}

	private void RefreshConfigValues(bool saveConfig = false)
	{
		_durationSeconds = Math.Max(180f, _durationSecondsConfig.Value);
		s_durationSeconds = _durationSeconds;
		s_runicBladeCountsAsLexicon = _runicBladeCountsAsLexiconConfig.Value;
		if (!s_runicBladeCountsAsLexicon && _requireArcaneSyntaxForRunicBladeLexiconConfig.Value)
		{
			_updatingConfig = true;
			try
			{
				_requireArcaneSyntaxForRunicBladeLexiconConfig.Value = false;
			}
			finally
			{
				_updatingConfig = false;
			}
			if (saveConfig)
			{
				((BaseUnityPlugin)this).Config.Save();
			}
		}
		s_requireArcaneSyntaxForRunicBladeLexicon = s_runicBladeCountsAsLexicon && _requireArcaneSyntaxForRunicBladeLexiconConfig.Value;
	}

	private void DrawRequireArcaneSyntaxConfig(ConfigEntryBase entry)
	{
		bool flag = _runicBladeCountsAsLexiconConfig == null || _runicBladeCountsAsLexiconConfig.Value;
		bool flag2 = entry.BoxedValue is bool && (bool)entry.BoxedValue;
		if (!flag && flag2)
		{
			entry.BoxedValue = false;
			flag2 = false;
		}
		bool enabled = GUI.enabled;
		GUI.enabled = enabled && flag;
		bool flag3 = GUILayout.Toggle(flag2, GUIContent.none, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
		GUI.enabled = enabled;
		if (flag && flag3 != flag2)
		{
			entry.BoxedValue = flag3;
		}
	}

	private static LegacyConfig LoadLegacyConfig()
	{
		string path = Path.Combine(PluginDirectory, "RunicBladeLongerDuration.cfg");
		LegacyConfig legacyConfig = new LegacyConfig();
		if (!File.Exists(path))
		{
			return legacyConfig;
		}
		try
		{
			string[] array = File.ReadAllLines(path);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0 || text.StartsWith("#", StringComparison.Ordinal))
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num < 0)
				{
					continue;
				}
				string text2 = text.Substring(0, num).Trim();
				string text3 = text.Substring(num + 1).Trim();
				bool result3;
				if (text2.Equals("DurationSeconds", StringComparison.OrdinalIgnoreCase))
				{
					if (float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						legacyConfig.DurationSeconds = Math.Max(180f, result);
						legacyConfig.HasDurationSeconds = true;
					}
				}
				else if (text2.Equals("RunicBladeCountsAsLexicon", StringComparison.OrdinalIgnoreCase))
				{
					if (TryParseBool(text3, out var result2))
					{
						legacyConfig.RunicBladeCountsAsLexicon = result2;
						legacyConfig.HasRunicBladeCountsAsLexicon = true;
					}
				}
				else if (text2.Equals("RequireArcaneSyntaxForRunicBladeLexicon", StringComparison.OrdinalIgnoreCase) && TryParseBool(text3, out result3))
				{
					legacyConfig.RequireArcaneSyntaxForRunicBladeLexicon = result3;
					legacyConfig.HasRequireArcaneSyntaxForRunicBladeLexicon = true;
				}
			}
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("[Runic Blade Longer Duration] Could not read legacy config: " + ex.Message));
		}
		return legacyConfig;
	}

	private static bool TryParseBool(string value, out bool result)
	{
		if (bool.TryParse(value, out result))
		{
			return true;
		}
		if (string.Equals(value, "1", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "yes", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "y", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "on", StringComparison.OrdinalIgnoreCase))
		{
			result = true;
			return true;
		}
		if (string.Equals(value, "0", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "no", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "n", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "off", StringComparison.OrdinalIgnoreCase))
		{
			result = false;
			return true;
		}
		result = false;
		return false;
	}

	private void PatchRunicBladeEffects()
	{
		RunicBlade[] array = Resources.FindObjectsOfTypeAll<RunicBlade>();
		foreach (RunicBlade val in array)
		{
			if (!((Object)(object)val == (Object)null) && !(Math.Abs(val.SummonLifeSpan - _durationSeconds) < 0.01f))
			{
				val.SummonLifeSpan = _durationSeconds;
			}
		}
	}

	private void ExtendAlreadySummonedRunicWeapons()
	{
		SummonedEquipment[] array = Resources.FindObjectsOfTypeAll<SummonedEquipment>();
		foreach (SummonedEquipment val in array)
		{
			if ((Object)(object)val == (Object)null || val.RemainingLifespan <= 0f)
			{
				continue;
			}
			Item component = ((Component)val).GetComponent<Item>();
			if (!((Object)(object)component == (Object)null) && (component.ItemID == 2000100 || component.ItemID == 2100999))
			{
				string uID = component.UID;
				if (!string.IsNullOrEmpty(uID) && _extendedSummonUids.Add(uID) && val.RemainingLifespan < _durationSeconds)
				{
					val.RefreshLifespan(_durationSeconds);
				}
			}
		}
	}

	private void OnRunicBladeInstanceStart(Item item)
	{
		if (!((Object)(object)item == (Object)null) && s_runicBladeCountsAsLexicon && !s_requireArcaneSyntaxForRunicBladeLexicon)
		{
			CustomTags.SetTagSource(((Component)item).gameObject, LexiconTag, false);
		}
	}

	private static bool IsRunicBlade(Item item)
	{
		if ((Object)(object)item != (Object)null)
		{
			return item.ItemID == 2000100;
		}
		return false;
	}

	private static bool IsRunicWeapon(Item item)
	{
		if ((Object)(object)item != (Object)null)
		{
			if (item.ItemID != 2000100)
			{
				return item.ItemID == 2100999;
			}
			return true;
		}
		return false;
	}

	private static bool IsRunicSummonedEquipment(SummonedEquipment summoned)
	{
		return IsRunicWeapon(((Object)(object)summoned == (Object)null) ? null : ((Component)summoned).GetComponent<Item>());
	}

	private static bool IsLexiconTag(Tag tag)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		return string.Equals(tag.TagName, "Lexicon", StringComparison.Ordinal);
	}

	private static bool RunicBladeLexiconAllowed(Item item)
	{
		if (!s_runicBladeCountsAsLexicon)
		{
			return false;
		}
		if (!s_requireArcaneSyntaxForRunicBladeLexicon)
		{
			return true;
		}
		Character val = (((Object)(object)item == (Object)null) ? null : ((EffectSynchronizer)item).OwnerCharacter);
		if ((Object)(object)val != (Object)null && (Object)(object)val.Inventory != (Object)null && (Object)(object)val.Inventory.SkillKnowledge != (Object)null)
		{
			return ((CharacterKnowledge)val.Inventory.SkillKnowledge).IsItemLearned(8205180);
		}
		return false;
	}
}