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;
}
}