Decompiled source of ServersideResourceMultiplier v1.0.0

ServersideResourceMultiplier.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
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("ServersideResourceMultiplier")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ServersideResourceMultiplier")]
[assembly: AssemblyTitle("ServersideResourceMultiplier")]
[assembly: AssemblyVersion("1.0.0.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 ServersideResourceMultiplier
{
	internal static class DropTracker
	{
		private struct PendingDrop
		{
			public ZDOID Id;

			public float Time;
		}

		private struct BreakEvent
		{
			public Vector3 Position;

			public float Time;

			public SourceIndex.SourceInfo Source;
		}

		private const uint RevisionMargin = 10u;

		private const int MaxExtraPiles = 50;

		private static readonly int s_setAreaHealthHash = StringExtensionMethods.GetStableHashCode("RPC_SetAreaHealth");

		private static readonly int s_hideHash = StringExtensionMethods.GetStableHashCode("Hide");

		private static readonly List<PendingDrop> s_pending = new List<PendingDrop>();

		private static readonly List<BreakEvent> s_events = new List<BreakEvent>();

		private static readonly HashSet<ZDOID> s_ownSpawns = new HashSet<ZDOID>();

		private static bool Active
		{
			get
			{
				if (Plugin.Enabled.Value && SourceIndex.Ready && (Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		internal static void Reset()
		{
			s_pending.Clear();
			s_events.Clear();
			s_ownSpawns.Clear();
		}

		internal static void OnZdoCreated(ZDO zdo)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && Active)
			{
				s_pending.Add(new PendingDrop
				{
					Id = zdo.m_uid,
					Time = Time.time
				});
			}
		}

		internal static void OnZdoDestroyed(ZDO zdo)
		{
			if (Active)
			{
				AddEvent(zdo);
			}
		}

		internal static void OnRoutedRpc(RoutedRPCData data)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (((ZDOID)(ref data.m_targetZDO)).IsNone() || !Active)
			{
				return;
			}
			if (data.m_methodHash == s_setAreaHealthHash)
			{
				ZPackage parameters = data.m_parameters;
				int pos = parameters.GetPos();
				parameters.ReadInt();
				float num = parameters.ReadSingle();
				parameters.SetPos(pos);
				if (num > 0f)
				{
					return;
				}
			}
			else if (data.m_methodHash != s_hideHash)
			{
				return;
			}
			AddEvent(ZDOMan.instance.GetZDO(data.m_targetZDO));
		}

		private static void AddEvent(ZDO zdo)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (zdo != null && SourceIndex.TryGetSource(zdo.GetPrefab(), out var source))
			{
				s_events.Add(new BreakEvent
				{
					Position = zdo.GetPosition(),
					Time = Time.time,
					Source = source
				});
			}
		}

		internal static void Tick()
		{
			if (!Active)
			{
				if (s_pending.Count > 0 || s_events.Count > 0)
				{
					Reset();
				}
				return;
			}
			float time = Time.time;
			float value = Plugin.MatchWindowSeconds.Value;
			for (int num = s_events.Count - 1; num >= 0; num--)
			{
				if (time - s_events[num].Time > value * 2f)
				{
					RemoveSwapBack(s_events, num);
				}
			}
			for (int num2 = s_pending.Count - 1; num2 >= 0; num2--)
			{
				if (TryProcess(s_pending[num2], time, value))
				{
					RemoveSwapBack(s_pending, num2);
				}
			}
		}

		private static bool TryProcess(PendingDrop pending, float now, float window)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(pending.Id);
			if (zDO == null)
			{
				return true;
			}
			if (s_ownSpawns.Remove(pending.Id))
			{
				return true;
			}
			int prefab = zDO.GetPrefab();
			if (!SourceIndex.IsResourceItem(prefab))
			{
				return true;
			}
			bool result = now - pending.Time > window;
			byte[] byteArray = zDO.GetByteArray(ZDOVars.s_itemData, (byte[])null);
			if (byteArray == null || byteArray.Length <= 2)
			{
				return result;
			}
			if (!TryFindEvent(prefab, zDO.GetPosition(), pending.Time, window, out var match))
			{
				return result;
			}
			Apply(zDO, prefab, match);
			return true;
		}

		private static bool TryFindEvent(int itemHash, Vector3 position, float dropTime, float window, out BreakEvent match)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			for (int num = s_events.Count - 1; num >= 0; num--)
			{
				BreakEvent breakEvent = s_events[num];
				if (!(Mathf.Abs(breakEvent.Time - dropTime) > window) && breakEvent.Source.Items.Contains(itemHash))
				{
					Vector3 val = breakEvent.Position - position;
					if (!(((Vector3)(ref val)).sqrMagnitude > breakEvent.Source.Radius * breakEvent.Source.Radius))
					{
						match = breakEvent;
						return true;
					}
				}
			}
			match = default(BreakEvent);
			return false;
		}

		private static void Apply(ZDO zdo, int prefabHash, BreakEvent ev)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(prefabHash);
			ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			ItemData val2 = val.m_itemData.Clone();
			val2.m_dropPrefab = prefab;
			ItemDrop.LoadFromZDO(val2, zdo, -1);
			if (val2.m_pickedUp)
			{
				return;
			}
			float multiplier = Plugin.GetMultiplier(ev.Source.Category, prefabHash);
			int stack = val2.m_stack;
			int num = Scale(stack, multiplier);
			if (num == stack)
			{
				return;
			}
			if (Plugin.LogMatches.Value)
			{
				Plugin.Log.LogInfo((object)$"{ev.Source.Name} -> {((Object)prefab).name} x{stack} => x{num} (multiplier {multiplier:0.##})");
			}
			if (num <= 0)
			{
				zdo.SetOwner(ZDOMan.GetSessionID());
				ZDOMan.instance.DestroyZDO(zdo);
				return;
			}
			int num2 = Mathf.Max(1, val2.m_shared.m_maxStackSize);
			val2.m_stack = Mathf.Min(num, num2);
			ItemDrop.SaveToZDO(val2, zdo, -1);
			zdo.DataRevision += 10;
			int num3 = num - val2.m_stack;
			int num4 = 0;
			while (num3 > 0 && num4 < 50)
			{
				int num5 = Mathf.Min(num3, num2);
				SpawnPile(zdo, prefab, prefabHash, val2, num5);
				num3 -= num5;
				num4++;
			}
		}

		private static void SpawnPile(ZDO original, GameObject prefab, int prefabHash, ItemData data, int stack)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = original.GetPosition() + new Vector3(Random.Range(-0.5f, 0.5f), 0.25f, Random.Range(-0.5f, 0.5f));
			ZDO val2 = ZDOMan.instance.CreateNewZDO(val, prefabHash);
			s_ownSpawns.Add(val2.m_uid);
			ZNetView component = prefab.GetComponent<ZNetView>();
			val2.Persistent = component.m_persistent;
			val2.Type = component.m_type;
			val2.Distant = component.m_distant;
			val2.SetPrefab(prefabHash);
			val2.SetRotation(original.GetRotation());
			val2.Set(ZDOVars.s_spawnTime, original.GetLong(ZDOVars.s_spawnTime, ZNet.instance.GetTime().Ticks));
			ItemData obj = data.Clone();
			obj.m_stack = stack;
			ItemDrop.SaveToZDO(obj, val2, -1);
			val2.SetOwner(original.GetOwner());
		}

		private static int Scale(int stack, float multiplier)
		{
			float num = (float)stack * multiplier;
			int num2 = Mathf.FloorToInt(num);
			if (Random.value < num - (float)num2)
			{
				num2++;
			}
			return num2;
		}

		private static void RemoveSwapBack<T>(List<T> list, int index)
		{
			int index2 = list.Count - 1;
			list[index] = list[index2];
			list.RemoveAt(index2);
		}
	}
	[HarmonyPatch]
	internal static class Patches
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void ZNetScene_Awake(ZNetScene __instance)
		{
			DropTracker.Reset();
			SourceIndex.Build(__instance);
			ZDOMan instance = ZDOMan.instance;
			instance.m_onZDODestroyed = (Action<ZDO>)Delegate.Combine(instance.m_onZDODestroyed, new Action<ZDO>(DropTracker.OnZdoDestroyed));
		}

		[HarmonyPatch(typeof(ZNet), "Update")]
		[HarmonyPostfix]
		private static void ZNet_Update()
		{
			Plugin.Instance.OnNetUpdate();
		}

		[HarmonyPatch(typeof(ZDOMan), "CreateNewZDO", new Type[]
		{
			typeof(ZDOID),
			typeof(Vector3),
			typeof(int)
		})]
		[HarmonyPostfix]
		private static void ZDOMan_CreateNewZDO(ZDO __result)
		{
			DropTracker.OnZdoCreated(__result);
		}

		[HarmonyPatch(typeof(ZRoutedRpc), "HandleRoutedRPC")]
		[HarmonyPrefix]
		private static void ZRoutedRpc_HandleRoutedRPC(RoutedRPCData data)
		{
			DropTracker.OnRoutedRpc(data);
		}
	}
	[BepInPlugin("thelm.ServersideResourceMultiplier", "ServersideResourceMultiplier", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "thelm.ServersideResourceMultiplier";

		public const string ModName = "ServersideResourceMultiplier";

		public const string ModVersion = "1.0.0";

		private const string GeneralSection = "1 - General";

		private const string AdvancedSection = "2 - Advanced";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> GlobalMultiplier;

		internal static ConfigEntry<float> MatchWindowSeconds;

		internal static ConfigEntry<bool> LogMatches;

		internal static ConfigEntry<bool> LogSources;

		private static readonly Dictionary<Category, ConfigEntry<float>> s_categoryMultipliers = new Dictionary<Category, ConfigEntry<float>>();

		private static readonly Dictionary<(Category, int), ConfigEntry<float>> s_itemMultipliers = new Dictionary<(Category, int), ConfigEntry<float>>();

		private FileSystemWatcher _watcher;

		private volatile bool _reloadRequested;

		private DateTime _ignoreWatcherUntil;

		private void Awake()
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Turns the mod on or off. Only does anything on the machine that hosts the world (dedicated server, player-hosted server or single player).");
			GlobalMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "GlobalMultiplier", 1f, Range("Applied to every resource drop, on top of the category and per-item multipliers. Final amount = GlobalMultiplier x MiningMultiplier/WoodcuttingMultiplier x item multiplier."));
			s_categoryMultipliers[Category.Mining] = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "MiningMultiplier", 1f, Range("Applied to everything broken with a pickaxe: rocks, ore veins, Leviathans, ruins..."));
			s_categoryMultipliers[Category.Woodcutting] = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "WoodcuttingMultiplier", 1f, Range("Applied to everything broken with an axe: trees, logs, stumps..."));
			MatchWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Advanced", "MatchWindowSeconds", 2f, new ConfigDescription("How far apart in time (seconds) a resource breaking and its drops appearing may be and still count as the same event. Raise it if players with high ping miss the bonus.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			LogMatches = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Advanced", "LogMatches", false, "Writes a log line for every drop the mod changes. Useful to check it is working.");
			LogSources = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Advanced", "LogSources", false, "Lists every resource node the mod recognised, by category, when a world loads.");
			new Harmony("thelm.ServersideResourceMultiplier").PatchAll(typeof(Plugin).Assembly);
			WatchConfigFile();
		}

		private void OnDestroy()
		{
			_watcher?.Dispose();
		}

		internal void OnNetUpdate()
		{
			if (_reloadRequested)
			{
				_reloadRequested = false;
				ReloadConfig();
			}
			DropTracker.Tick();
		}

		internal static float GetMultiplier(Category category, int itemPrefabHash)
		{
			ConfigEntry<float> value;
			float num = (s_itemMultipliers.TryGetValue((category, itemPrefabHash), out value) ? value.Value : 1f);
			return GlobalMultiplier.Value * s_categoryMultipliers[category].Value * num;
		}

		internal static void BindItems(IEnumerable<SourceIndex.ItemInfo> items)
		{
			ConfigFile config = ((BaseUnityPlugin)Instance).Config;
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			try
			{
				foreach (SourceIndex.ItemInfo item in items.OrderBy<SourceIndex.ItemInfo, string>((SourceIndex.ItemInfo i) => i.Name, StringComparer.OrdinalIgnoreCase))
				{
					if (!s_itemMultipliers.ContainsKey((item.Category, item.Hash)))
					{
						string text = string.Join(", ", item.Sources.Take(6)) + ((item.Sources.Count > 6) ? ", ..." : "");
						s_itemMultipliers[(item.Category, item.Hash)] = config.Bind<float>(SectionFor(item.Category), item.Name, 1f, Range("Multiplier for " + item.Name + " from " + text + "."));
					}
				}
				Instance._ignoreWatcherUntil = DateTime.UtcNow.AddSeconds(2.0);
				config.Save();
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private static string SectionFor(Category category)
		{
			if (category != Category.Mining)
			{
				return "4 - Woodcutting items";
			}
			return "3 - Mining items";
		}

		private static ConfigDescription Range(string description)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>());
		}

		private void WatchConfigFile()
		{
			_watcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
				IncludeSubdirectories = false,
				EnableRaisingEvents = true
			};
			FileSystemEventHandler onChange = delegate
			{
				if (DateTime.UtcNow > _ignoreWatcherUntil)
				{
					_reloadRequested = true;
				}
			};
			_watcher.Changed += onChange;
			_watcher.Created += onChange;
			_watcher.Renamed += delegate
			{
				onChange(null, null);
			};
		}

		private void ReloadConfig()
		{
			if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				return;
			}
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				Log.LogInfo((object)"Config reloaded.");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not reload config: " + ex.Message));
			}
		}
	}
	internal enum Category
	{
		Mining,
		Woodcutting
	}
	internal static class SourceIndex
	{
		internal sealed class SourceInfo
		{
			public string Name;

			public Category Category;

			public float Radius;

			public readonly HashSet<int> Items = new HashSet<int>();
		}

		internal sealed class ItemInfo
		{
			public int Hash;

			public string Name;

			public Category Category;

			public readonly List<string> Sources = new List<string>();
		}

		private const float DestructibleRadius = 8f;

		private const float MineRockRadius = 30f;

		private const float TreeRadius = 12f;

		private const float LogMargin = 6f;

		private static readonly Dictionary<int, SourceInfo> s_sources = new Dictionary<int, SourceInfo>();

		private static readonly Dictionary<(Category, int), ItemInfo> s_items = new Dictionary<(Category, int), ItemInfo>();

		private static readonly HashSet<int> s_itemHashes = new HashSet<int>();

		internal static bool Ready { get; private set; }

		internal static bool TryGetSource(int prefabHash, out SourceInfo source)
		{
			return s_sources.TryGetValue(prefabHash, out source);
		}

		internal static bool IsResourceItem(int prefabHash)
		{
			return s_itemHashes.Contains(prefabHash);
		}

		internal static void Build(ZNetScene scene)
		{
			s_sources.Clear();
			s_items.Clear();
			s_itemHashes.Clear();
			foreach (GameObject prefab in scene.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<Piece>() != (Object)null) && !((Object)(object)prefab.GetComponent<Character>() != (Object)null))
				{
					MineRock component = prefab.GetComponent<MineRock>();
					if ((Object)(object)component != (Object)null)
					{
						Add(prefab, component.m_dropItems, Category.Mining, 30f);
					}
					MineRock5 component2 = prefab.GetComponent<MineRock5>();
					if ((Object)(object)component2 != (Object)null)
					{
						Add(prefab, component2.m_dropItems, Category.Mining, 30f);
					}
					TreeLog component3 = prefab.GetComponent<TreeLog>();
					if ((Object)(object)component3 != (Object)null)
					{
						Add(prefab, component3.m_dropWhenDestroyed, Category.Woodcutting, component3.m_spawnDistance + 6f);
					}
					TreeBase component4 = prefab.GetComponent<TreeBase>();
					if ((Object)(object)component4 != (Object)null)
					{
						Add(prefab, component4.m_dropWhenDestroyed, Category.Woodcutting, 12f);
					}
					Destructible component5 = prefab.GetComponent<Destructible>();
					DropOnDestroyed component6 = prefab.GetComponent<DropOnDestroyed>();
					if ((Object)(object)component5 != (Object)null && (Object)(object)component6 != (Object)null && TryClassify(component5, out var category))
					{
						Add(prefab, component6.m_dropWhenDestroyed, category, 8f);
					}
				}
			}
			Ready = s_sources.Count > 0;
			Plugin.Log.LogInfo((object)$"Found {s_sources.Count} resource nodes dropping {s_itemHashes.Count} different items.");
			if (Plugin.LogSources.Value)
			{
				foreach (IGrouping<Category, SourceInfo> item in from s in s_sources.Values
					group s by s.Category)
				{
					Plugin.Log.LogInfo((object)string.Format("{0}: {1}", item.Key, string.Join(", ", from s in item
						select s.Name into n
						orderby n
						select n)));
				}
			}
			Plugin.BindItems(s_items.Values);
		}

		private static bool TryClassify(Destructible destructible, out Category category)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000f: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			category = Category.Woodcutting;
			if ((int)destructible.m_destructibleType == 2)
			{
				return true;
			}
			DamageModifiers damages = destructible.m_damages;
			if (Hurts(damages.m_blunt) || Hurts(damages.m_slash) || Hurts(damages.m_pierce))
			{
				return false;
			}
			bool flag = Hurts(damages.m_pickaxe);
			bool flag2 = Hurts(damages.m_chop);
			if (flag == flag2)
			{
				return false;
			}
			category = ((!flag) ? Category.Woodcutting : Category.Mining);
			return true;
		}

		private static bool Hurts(DamageModifier modifier)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)modifier != 3)
			{
				return (int)modifier != 4;
			}
			return false;
		}

		private static void Add(GameObject prefab, DropTable table, Category category, float radius)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			if (table == null || table.m_drops == null)
			{
				return;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
			foreach (DropData drop in table.m_drops)
			{
				if (!((Object)(object)drop.m_item == (Object)null) && !((Object)(object)drop.m_item.GetComponent<ItemDrop>() == (Object)null))
				{
					if (!s_sources.TryGetValue(stableHashCode, out var value))
					{
						value = new SourceInfo
						{
							Name = ((Object)prefab).name,
							Category = category,
							Radius = radius
						};
						s_sources.Add(stableHashCode, value);
					}
					value.Radius = Mathf.Max(value.Radius, radius);
					int stableHashCode2 = StringExtensionMethods.GetStableHashCode(((Object)drop.m_item).name);
					value.Items.Add(stableHashCode2);
					s_itemHashes.Add(stableHashCode2);
					if (!s_items.TryGetValue((value.Category, stableHashCode2), out var value2))
					{
						value2 = new ItemInfo
						{
							Hash = stableHashCode2,
							Name = ((Object)drop.m_item).name,
							Category = value.Category
						};
						s_items.Add((value.Category, stableHashCode2), value2);
					}
					if (!value2.Sources.Contains(((Object)prefab).name))
					{
						value2.Sources.Add(((Object)prefab).name);
					}
				}
			}
		}
	}
}