Decompiled source of ArcherArrowDrops v1.0.1

ArcherArrowDrops.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ConditionalConfigSync;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ArcherArrowDrops")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("ArcherArrowDrops")]
[assembly: AssemblyTitle("ArcherArrowDrops")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 ArcherArrowDrops
{
	[BepInPlugin("com.dreich.archerarrowdrops", "ArcherArrowDrops", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ArcherArrowDropsPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.dreich.archerarrowdrops";

		public const string PluginName = "ArcherArrowDrops";

		public const string PluginVersion = "1.0.1";

		internal const string ConfigSyncGuid = "_shudnal.ConditionalConfigSync";

		private const long ReloadDelayTicks = 5000000L;

		private const long ReloadCooldownTicks = 20000000L;

		private static readonly (string enemyName, string defaultDrops)[] defaultEnemyDrops = new(string, string)[4]
		{
			("Skeleton", "ArrowFlint,1,3,0.5"),
			("Draugr_Ranged", "ArrowIron,1,3,0.5"),
			("GoblinArcher", "ArrowNeedle,1,3,0.5"),
			("Charred_Archer", "ArrowCharred,1,3,0.5")
		};

		internal static readonly Dictionary<string, ConfigEntry<string>> dropSettingsByEnemy = new Dictionary<string, ConfigEntry<string>>();

		internal static ConfigEntry<string> customEnemyDropsSetting;

		internal static ManualLogSource logger;

		internal static bool configSyncAvailable;

		private FileSystemWatcher configWatcher;

		private volatile bool reloadPending;

		private long lastChangeTicks;

		private long ignoreChangesUntilTicks;

		private void Awake()
		{
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			logger = ((BaseUnityPlugin)this).Logger;
			configSyncAvailable = Chainloader.PluginInfos.ContainsKey("_shudnal.ConditionalConfigSync");
			if (configSyncAvailable)
			{
				ConfigSyncCompat.Initialize("com.dreich.archerarrowdrops", "ArcherArrowDrops", "1.0.1");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"ConditionalConfigSync not found; configuration will not be synced from the server.");
			}
			ConfigEntry<bool> entry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only. Requires ConditionalConfigSync.");
			if (configSyncAvailable)
			{
				ConfigSyncCompat.AddLockingConfigEntry(entry);
			}
			(string, string)[] array = defaultEnemyDrops;
			for (int i = 0; i < array.Length; i++)
			{
				(string, string) tuple = array[i];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>(item, "Drops", item2, "Format: ItemPrefab,Min amount dropped,Max amount dropped, Chance to drop. Separate multiple drops with a semicolon, leave empty for no drops.");
				if (configSyncAvailable)
				{
					ConfigSyncCompat.AddServerControlledEntry(val);
				}
				dropSettingsByEnemy[item] = val;
			}
			customEnemyDropsSetting = ((BaseUnityPlugin)this).Config.Bind<string>("Custom Enemies", "Drops", "", "Add drops for any other enemy. Format: EnemyPrefab:ItemPrefab,Min amount dropped,Max amount dropped,Chance to drop. Separate multiple drops with a semicolon and multiple enemies with a vertical bar. Example: Fenring:ArrowWood,1,2,0.25|Troll:ArrowFlint,2,4,1.0");
			if (configSyncAvailable)
			{
				ConfigSyncCompat.AddServerControlledEntry(customEnemyDropsSetting);
			}
			configWatcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				NotifyFilter = (NotifyFilters.Size | NotifyFilters.LastWrite)
			};
			configWatcher.Changed += OnConfigFileChanged;
			configWatcher.EnableRaisingEvents = true;
			new Harmony("com.dreich.archerarrowdrops").PatchAll();
		}

		private void OnConfigFileChanged(object sender, FileSystemEventArgs args)
		{
			long ticks = DateTime.UtcNow.Ticks;
			if (ticks >= Interlocked.Read(in ignoreChangesUntilTicks))
			{
				Interlocked.Exchange(ref lastChangeTicks, ticks);
				reloadPending = true;
			}
		}

		private void Update()
		{
			if (!reloadPending || DateTime.UtcNow.Ticks - Interlocked.Read(in lastChangeTicks) <= 5000000)
			{
				return;
			}
			reloadPending = false;
			Interlocked.Exchange(ref ignoreChangesUntilTicks, DateTime.UtcNow.Ticks + 20000000);
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Config reload failed: " + ex.Message));
			}
		}
	}
	internal static class ConfigSyncCompat
	{
		private static object configSync;

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void Initialize(string guid, string name, string version)
		{
			//IL_0001: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			configSync = (object)new ConfigSync(guid)
			{
				DisplayName = name,
				CurrentVersion = version,
				MinimumRequiredVersion = version,
				ModRequired = true
			};
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddLockingConfigEntry(ConfigEntry<bool> entry)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			((ConditionalConfigSync)(ConfigSync)configSync).AddLockingConfigEntry<bool>(entry);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static void AddServerControlledEntry(ConfigEntry<string> entry)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			((ConditionalConfigSync)(ConfigSync)configSync).AddConfigEntry<string>(entry, (ConfigSyncMode)0);
		}
	}
	[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
	internal static class AddArrowDropsPatch
	{
		private static readonly ConditionalWeakTable<CharacterDrop, List<Drop>> arrowDropsByEnemy = new ConditionalWeakTable<CharacterDrop, List<Drop>>();

		private static void Prefix(CharacterDrop __instance)
		{
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject);
			List<Drop> orCreateValue = arrowDropsByEnemy.GetOrCreateValue(__instance);
			foreach (Drop item2 in orCreateValue)
			{
				__instance.m_drops.Remove(item2);
			}
			orCreateValue.Clear();
			foreach (string dropEntry in GetDropEntries(prefabName))
			{
				string[] array = dropEntry.Split(new char[1] { ',' });
				if (array.Length != 4 || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
				{
					ArcherArrowDropsPlugin.logger.LogWarning((object)("Invalid drop for " + prefabName + ": " + dropEntry));
					continue;
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(array[0].Trim());
				if ((Object)(object)prefab == (Object)null)
				{
					ArcherArrowDropsPlugin.logger.LogWarning((object)("Unknown item for " + prefabName + ": " + array[0]));
					continue;
				}
				Drop item = new Drop
				{
					m_prefab = prefab,
					m_amountMin = result,
					m_amountMax = Mathf.Max(result, result2),
					m_chance = Mathf.Clamp01(result3)
				};
				__instance.m_drops.Add(item);
				orCreateValue.Add(item);
			}
		}

		private static IEnumerable<string> GetDropEntries(string enemyName)
		{
			string[] array;
			if (ArcherArrowDropsPlugin.dropSettingsByEnemy.TryGetValue(enemyName, out var value))
			{
				array = value.Value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i < array.Length; i++)
				{
					yield return array[i];
				}
			}
			array = ArcherArrowDropsPlugin.customEnemyDropsSetting.Value.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				int num = text.IndexOf(':');
				if (num >= 0 && !(text.Substring(0, num).Trim() != enemyName))
				{
					string[] array2 = text.Substring(num + 1).Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
					for (int j = 0; j < array2.Length; j++)
					{
						yield return array2[j];
					}
				}
			}
		}
	}
}