Decompiled source of EnemyCountOverlay v1.0.0

BepInEx\plugins\EnemyCountOverlay\EnemyCountOverlay.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("LATA")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EnemyCountOverlay")]
[assembly: AssemblyTitle("EnemyCountOverlay")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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 EnemyCountOverlay
{
	[BepInPlugin("lata.repo.enemycountoverlay", "Enemy Count Overlay", "1.0.0")]
	public sealed class EnemyCountOverlayPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "lata.repo.enemycountoverlay";

		public const string PluginName = "Enemy Count Overlay";

		public const string PluginVersion = "1.0.0";

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<bool> _fallbackContainsEnemy;

		private ConfigEntry<float> _scanInterval;

		private ConfigEntry<int> _fontSize;

		private ConfigEntry<int> _overlayWidth;

		private ConfigEntry<int> _rightOffset;

		private ConfigEntry<int> _bottomOffset;

		private ConfigEntry<string> _enemyComponentNames;

		private ConfigEntry<string> _excludeComponentNames;

		private ConfigEntry<string> _excludeObjectNames;

		private ConfigEntry<string> _blockedSceneNameParts;

		private ConfigEntry<KeyboardShortcut> _toggleKey;

		private ConfigEntry<KeyboardShortcut> _dumpKey;

		private bool _runtimeVisible;

		private float _nextScanTime;

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

		private GUIStyle _labelStyle;

		private GUIStyle _shadowStyle;

		private static readonly Regex CloneRegex = new Regex("\\(Clone\\)", RegexOptions.Compiled);

		private static readonly Regex TrailingNumberRegex = new Regex("\\s*\\(\\d+\\)$", RegexOptions.Compiled);

		private static readonly Regex NoiseRegex = new Regex("[^a-zA-Z0-9]", RegexOptions.Compiled);

		private static readonly Dictionary<string, string> CanonicalEnemyNames = BuildCanonicalEnemyNames();

		private void Awake()
		{
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "敵数オーバーレイを有効にします。");
			_fallbackContainsEnemy = ((BaseUnityPlugin)this).Config.Bind<bool>("Detection", "FallbackContainsEnemy", true, "指定した敵コンポーネント名が見つからない場合、名前に Enemy を含むコンポーネントを敵候補として探索します。");
			_scanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "ScanIntervalSeconds", 0.5f, "敵数を再集計する間隔です。短すぎると負荷が増えます。");
			_enemyComponentNames = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "EnemyComponentNames", "EnemyParent,Enemy", "敵本体として扱うコンポーネント名です。カンマ区切りで指定します。");
			_excludeComponentNames = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "ExcludeComponentNames", "EnemyDirector,EnemySpawner,EnemySpawn,EnemyManager,EnemySetup,EnemyValuable,EnemyDebug,EnemyUI,EnemyCatch,EnemyNear,EnemySighting", "敵数カウントから除外するコンポーネント名です。カンマ区切りで指定します。");
			_excludeObjectNames = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "ExcludeObjectNames", "Manager,Director,Spawner,SpawnPoint,UI,Canvas,Debug,Menu,Password,Shop,Service Station,Enemy Catch,Enemy Near,Enemy Sighting", "敵数カウントから除外するGameObject名です。カンマ区切りで指定します。");
			_blockedSceneNameParts = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "BlockedSceneNameParts", "Lobby,Lobby Menu,Level - Lobby Menu,Menu,Main Menu,Password,Shop,Service Station,Level - Shop,Level - Service Station", "この文字列を含むシーンではオーバーレイを表示しません。カンマ区切りで指定します。");
			_fontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Overlay", "FontSize", 14, "表示文字サイズです。");
			_overlayWidth = ((BaseUnityPlugin)this).Config.Bind<int>("Overlay", "OverlayWidth", 280, "オーバーレイ表示領域の横幅です。");
			_rightOffset = ((BaseUnityPlugin)this).Config.Bind<int>("Overlay", "RightOffset", 24, "画面右端からの距離です。");
			_bottomOffset = ((BaseUnityPlugin)this).Config.Bind<int>("Overlay", "BottomOffset", 36, "画面下からの距離です。");
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keybinds", "ToggleOverlayKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "オーバーレイ表示/非表示の切り替えキーです。");
			_dumpKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keybinds", "DumpCandidateTypesKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Enemyを含むコンポーネント名をBepInExログへ出力します。検出調整用です。");
			_runtimeVisible = _enabled.Value;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Enemy Count Overlay 1.0.0 loaded.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"F8: toggle overlay / F9: dump enemy-like component types");
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = _toggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				_runtimeVisible = !_runtimeVisible;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Overlay visible: {_runtimeVisible}");
			}
			value = _dumpKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				DumpEnemyCandidateTypes();
			}
			if (_enabled.Value && Time.unscaledTime >= _nextScanTime)
			{
				_nextScanTime = Time.unscaledTime + Mathf.Max(0.1f, _scanInterval.Value);
				ScanEnemies();
			}
		}

		private void OnGUI()
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (_enabled.Value && _runtimeVisible && !IsBlockedScene() && _breakdown.Count != 0)
			{
				EnsureGuiStyle();
				string text = BuildOverlayText();
				int num = Mathf.Max(1, text.Split('\n').Length);
				float num2 = Mathf.Max(_fontSize.Value + 4, 16);
				float num3 = Mathf.Clamp(_overlayWidth.Value, 120, Screen.width);
				float num4 = (float)num * num2 + 8f;
				float num5 = (float)Screen.width - num3 - (float)Mathf.Max(0, _rightOffset.Value);
				float num6 = (float)Screen.height - num4 - (float)Mathf.Max(0, _bottomOffset.Value);
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(num5 + 2f, num6 + 2f, num3, num4);
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(num5, num6, num3, num4);
				GUI.Label(val, text, _shadowStyle);
				GUI.Label(val2, text, _labelStyle);
			}
		}

		private void EnsureGuiStyle()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_006c: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Clamp(_fontSize.Value, 10, 48);
			if (_labelStyle == null || _labelStyle.fontSize != num)
			{
				_labelStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = num,
					alignment = (TextAnchor)8,
					wordWrap = true,
					richText = true,
					padding = new RectOffset(0, 0, 0, 0)
				};
				_labelStyle.normal.textColor = Color.white;
				_shadowStyle = new GUIStyle(_labelStyle);
				_shadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.85f);
			}
		}

		private string BuildOverlayText()
		{
			return string.Join("\n", from pair in _breakdown
				orderby pair.Value descending, pair.Key
				select $"{pair.Key}:{pair.Value}");
		}

		private void ScanEnemies()
		{
			_breakdown.Clear();
			if (!IsBlockedScene())
			{
				HashSet<string> exactEnemyNames = ToNameSet(_enemyComponentNames.Value);
				HashSet<string> excludedComponentNames = ToNameSet(_excludeComponentNames.Value);
				HashSet<string> excludedObjectNameParts = ToNameSet(_excludeObjectNames.Value);
				HashSet<int> countedInstanceIds = new HashSet<int>();
				MonoBehaviour[] behaviours = Object.FindObjectsOfType<MonoBehaviour>();
				if (ScanByExactComponentNames(behaviours, exactEnemyNames, excludedComponentNames, excludedObjectNameParts, countedInstanceIds) == 0 && _fallbackContainsEnemy.Value)
				{
					ScanByFallbackEnemyName(behaviours, excludedComponentNames, excludedObjectNameParts, countedInstanceIds);
				}
			}
		}

		private int ScanByExactComponentNames(MonoBehaviour[] behaviours, HashSet<string> exactEnemyNames, HashSet<string> excludedComponentNames, HashSet<string> excludedObjectNameParts, HashSet<int> countedInstanceIds)
		{
			int count = countedInstanceIds.Count;
			foreach (MonoBehaviour val in behaviours)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Type type = ((object)val).GetType();
					string name = type.Name;
					if (exactEnemyNames.Contains(name) && !IsExcludedComponent(name, excludedComponentNames))
					{
						GameObject enemyObject = ResolveEnemyRootObject(((Component)val).gameObject, exactEnemyNames, excludedComponentNames, excludedObjectNameParts, fallbackMode: false);
						AddEnemyObject(enemyObject, countedInstanceIds);
					}
				}
			}
			return countedInstanceIds.Count - count;
		}

		private void ScanByFallbackEnemyName(MonoBehaviour[] behaviours, HashSet<string> excludedComponentNames, HashSet<string> excludedObjectNameParts, HashSet<int> countedInstanceIds)
		{
			foreach (MonoBehaviour val in behaviours)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Type type = ((object)val).GetType();
					string name = type.Name;
					if (name.IndexOf("Enemy", StringComparison.OrdinalIgnoreCase) >= 0 && !IsExcludedComponent(name, excludedComponentNames) && !IsExcludedObject(((Component)val).gameObject, excludedObjectNameParts))
					{
						GameObject enemyObject = ResolveEnemyRootObject(((Component)val).gameObject, new HashSet<string>(), excludedComponentNames, excludedObjectNameParts, fallbackMode: true);
						AddEnemyObject(enemyObject, countedInstanceIds);
					}
				}
			}
		}

		private GameObject ResolveEnemyRootObject(GameObject source, HashSet<string> exactEnemyNames, HashSet<string> excludedComponentNames, HashSet<string> excludedObjectNameParts, bool fallbackMode)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			Transform val = source.transform;
			Transform val2 = val;
			while ((Object)(object)val != (Object)null)
			{
				GameObject gameObject = ((Component)val).gameObject;
				if (!IsExcludedObject(gameObject, excludedObjectNameParts) && HasEnemyMarkerComponent(gameObject, exactEnemyNames, excludedComponentNames, fallbackMode))
				{
					val2 = val;
				}
				val = val.parent;
			}
			if (!((Object)(object)val2 != (Object)null))
			{
				return source;
			}
			return ((Component)val2).gameObject;
		}

		private bool HasEnemyMarkerComponent(GameObject obj, HashSet<string> exactEnemyNames, HashSet<string> excludedComponentNames, bool fallbackMode)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return false;
			}
			MonoBehaviour[] components = obj.GetComponents<MonoBehaviour>();
			MonoBehaviour[] array = components;
			foreach (MonoBehaviour val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string name = ((object)val).GetType().Name;
				if (!IsExcludedComponent(name, excludedComponentNames))
				{
					if (exactEnemyNames.Contains(name))
					{
						return true;
					}
					if (fallbackMode && name.IndexOf("Enemy", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private void AddEnemyObject(GameObject enemyObject, HashSet<int> countedInstanceIds)
		{
			if ((Object)(object)enemyObject == (Object)null || !enemyObject.activeInHierarchy)
			{
				return;
			}
			string text = ResolveCanonicalEnemyName(enemyObject);
			if (string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			int instanceID = ((Object)enemyObject).GetInstanceID();
			if (countedInstanceIds.Add(instanceID))
			{
				if (!_breakdown.ContainsKey(text))
				{
					_breakdown[text] = 0;
				}
				_breakdown[text]++;
			}
		}

		private string ResolveCanonicalEnemyName(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return null;
			}
			List<string> list = new List<string>();
			list.Add(((Object)obj).name);
			Transform val = obj.transform;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)((Component)val).gameObject).name);
				val = val.parent;
			}
			MonoBehaviour[] componentsInChildren = obj.GetComponentsInChildren<MonoBehaviour>(true);
			MonoBehaviour[] array = componentsInChildren;
			foreach (MonoBehaviour val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					list.Add(((object)val2).GetType().Name);
				}
			}
			foreach (string item in list)
			{
				string text = TryGetCanonicalEnemyName(item);
				if (!string.IsNullOrWhiteSpace(text))
				{
					return text;
				}
			}
			return null;
		}

		private string TryGetCanonicalEnemyName(string rawName)
		{
			if (string.IsNullOrWhiteSpace(rawName))
			{
				return null;
			}
			string text = CleanName(rawName);
			if (string.IsNullOrWhiteSpace(text))
			{
				return null;
			}
			string text2 = NormalizeKey(text);
			if (CanonicalEnemyNames.TryGetValue(text2, out var value))
			{
				return value;
			}
			foreach (KeyValuePair<string, string> canonicalEnemyName in CanonicalEnemyNames)
			{
				if (text2.Contains(canonicalEnemyName.Key))
				{
					return canonicalEnemyName.Value;
				}
			}
			return null;
		}

		private string CleanName(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return "";
			}
			string input = name;
			input = CloneRegex.Replace(input, "");
			input = TrailingNumberRegex.Replace(input, "");
			input = input.Replace("_", " ");
			input = input.Replace("-", " ");
			input = input.Replace("EnemyParent", "");
			input = input.Replace("Enemy Parent", "");
			input = input.Replace("Enemy", "");
			input = input.Replace("Parent", "");
			input = input.Replace("(Clone)", "");
			return input.Trim();
		}

		private string NormalizeKey(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return "";
			}
			return NoiseRegex.Replace(name, "").ToLowerInvariant();
		}

		private bool IsBlockedScene()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			string text = ((Scene)(ref activeScene)).name ?? "";
			HashSet<string> hashSet = ToNameSet(_blockedSceneNameParts.Value);
			foreach (string item in hashSet)
			{
				if (text.IndexOf(item, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private bool IsExcludedComponent(string componentName, HashSet<string> excludedComponentNames)
		{
			if (string.IsNullOrWhiteSpace(componentName))
			{
				return true;
			}
			foreach (string excludedComponentName in excludedComponentNames)
			{
				if (componentName.IndexOf(excludedComponentName, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private bool IsExcludedObject(GameObject obj, HashSet<string> excludedObjectNameParts)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return true;
			}
			string text = ((Object)obj).name ?? "";
			foreach (string excludedObjectNamePart in excludedObjectNameParts)
			{
				if (text.IndexOf(excludedObjectNamePart, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private HashSet<string> ToNameSet(string csv)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(csv))
			{
				return hashSet;
			}
			string[] array = csv.Split(',');
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.Trim();
				if (!string.IsNullOrWhiteSpace(text2))
				{
					hashSet.Add(text2);
				}
			}
			return hashSet;
		}

		private static Dictionary<string, string> BuildCanonicalEnemyNames()
		{
			Dictionary<string, string> result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			Add("Apex Predator", new string[4] { "Duck", "Ducky", "Mr Ducky", "EnemyDuck" });
			Add("Animal", new string[1] { "EnemyAnimal" });
			Add("Banger", new string[2] { "Bang", "EnemyBang" });
			Add("Bella", new string[3] { "Tricycle", "EnemyTricycle", "EnemyTricycleVisuals" });
			Add("Birthday Boy", new string[2] { "BirthdayBoy", "EnemyBirthdayBoy" });
			Add("Bowtie", new string[1] { "EnemyBowtie" });
			Add("Chef", new string[1] { "EnemyChef" });
			Add("Cleanup Crew", new string[4] { "CleanupCrew", "BombThrower", "Bomb Thrower", "EnemyBombThrower" });
			Add("Clown", new string[2] { "Beamer", "EnemyBeamer" });
			Add("Elsa", new string[1] { "EnemyElsa" });
			Add("Gambit", new string[3] { "Spinny", "EnemyGambit", "EnemySpinny" });
			Add("Gnome", new string[1] { "EnemyGnome" });
			Add("Headgrab", new string[3] { "HeadGrabber", "Head Grabber", "EnemyHeadGrabber" });
			Add("Headman", new string[2] { "Head", "EnemyHead" });
			Add("Heart Hugger", new string[2] { "HeartHugger", "EnemyHeartHugger" });
			Add("Hidden", new string[1] { "EnemyHidden" });
			Add("Huntsman", new string[2] { "Hunter", "EnemyHunter" });
			Add("Loom", new string[2] { "Shadow", "EnemyShadow" });
			Add("Mentalist", new string[3] { "Floater", "EnemyFloater", "EnemyMentalist" });
			Add("Oogly", new string[2] { "Ugly", "EnemyOogly" });
			Add("Peeper", new string[3] { "CeilingEye", "Ceiling Eye", "EnemyCeilingEye" });
			Add("Reaper", new string[2] { "Runner", "EnemyRunner" });
			Add("Robe", new string[1] { "EnemyRobe" });
			Add("Rugrat", new string[3] { "ValuableThrower", "Valuable Thrower", "EnemyValuableThrower" });
			Add("Shadow Child", new string[2] { "ShadowChild", "EnemyShadowChild" });
			Add("Spewer", new string[3] { "SlowMouth", "Slow Mouth", "EnemySlowMouth" });
			Add("Tick", new string[1] { "EnemyTick" });
			Add("Trudge", new string[3] { "SlowWalker", "Slow Walker", "EnemySlowWalker" });
			Add("Upscream", new string[1] { "EnemyUpscream" });
			return result;
			void Add(string canonicalName, params string[] aliases)
			{
				string key = NoiseRegex.Replace(canonicalName, "").ToLowerInvariant();
				if (!result.ContainsKey(key))
				{
					result.Add(key, canonicalName);
				}
				foreach (string input in aliases)
				{
					string key2 = NoiseRegex.Replace(input, "").ToLowerInvariant();
					if (!result.ContainsKey(key2))
					{
						result.Add(key2, canonicalName);
					}
				}
			}
		}

		private void DumpEnemyCandidateTypes()
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			MonoBehaviour[] array = Object.FindObjectsOfType<MonoBehaviour>();
			MonoBehaviour[] array2 = array;
			foreach (MonoBehaviour val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string name = ((object)val).GetType().Name;
				if (name.IndexOf("Enemy", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					if (!dictionary.ContainsKey(name))
					{
						dictionary[name] = 0;
					}
					dictionary[name]++;
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"==== Enemy-like component types ====");
			foreach (KeyValuePair<string, int> item in dictionary.OrderBy((KeyValuePair<string, int> pair) => pair.Key))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"{item.Key}: {item.Value}");
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"====================================");
		}
	}
}