Decompiled source of CallumCustomPerks v1.0.0

customgentlemensdisputes.dll

Decompiled 5 months ago
using System;
using System.Collections;
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 System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using Character;
using Core;
using DisputeLib;
using FishNet;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Managing.Object;
using FishNet.Object;
using Game;
using HarmonyLib;
using Player;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using customgentlemensdisputes.Maps;
using customgentlemensdisputes.maps;
using customgentlemensdisputes.perks;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("customgentlemensdisputes")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("customgentlemensdisputes")]
[assembly: AssemblyTitle("customgentlemensdisputes")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace customgentlemensdisputes
{
	public static class Constants
	{
		public const string PERK_ASSET_BUNDLE_NAME = "perkicons.bundle";

		public const string PERK_ICON_PATH = "Assets/CustomPerkIcons/";

		public static Type[] PERKS_TO_LOAD = new Type[2]
		{
			typeof(FastAsFuckBoiCustomPerk),
			typeof(ComingForYourAssCustomPerk)
		};

		public const string MAP_ASSET_BUNDLE_NAME = "custommaps.bundle";

		public const string MAP_ASSET_PATH = "Assets/CustomMaps/";

		public static CustomMap[] MAPS_TO_LOAD = new CustomMap[0];
	}
	public abstract class CustomPerk : Perk
	{
		public virtual string displayTitle => "Custom Perk";

		public virtual string displayDesc => "Perk Description";

		public virtual string perkIconKey => "trap";

		public string displayTitleKey => ((object)this).GetType().Name + "_Title";

		public string displayDescKey => ((object)this).GetType().Name + "_Desc";

		public virtual void OnEnable()
		{
			((Object)this).name = displayTitle;
		}
	}
	public static class PerkAssetBundleLoader
	{
		public static AssetBundle PerkIconBundle { get; private set; }

		public static AudioClip LoadAudio(string name)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			if ((Object)(object)PerkIconBundle == (Object)null)
			{
				return null;
			}
			string text = Path.Combine("Assets/CustomPerkIcons/", name) + ".wav";
			AudioClip val = PerkIconBundle.LoadAsset<AudioClip>(text);
			if ((Object)(object)val != (Object)null && (int)val.loadState != 2)
			{
				val.LoadAudioData();
			}
			return val;
		}

		public static Sprite LoadSprite(string name)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine("Assets/CustomPerkIcons/", name) + ".png";
			Texture2D val = PerkIconBundle.LoadAsset<Texture2D>(text);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("[CustomPerkSystem] Texture not found at: " + text));
				return null;
			}
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		public static void Init(PluginInfo info)
		{
			string text = Path.Combine(Path.GetDirectoryName(info.Location), "perkicons.bundle");
			PerkIconBundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)PerkIconBundle == (Object)null)
			{
				Debug.LogError((object)"[MGD] Failed to load perk icon bundle.");
			}
			else
			{
				Debug.Log((object)"[MGD] Perk icon bundle loaded.");
			}
		}
	}
	public static class CustomPerkSystem
	{
		private static readonly List<CustomPerk> _customPerks = new List<CustomPerk>();

		public static void RegisterAll()
		{
			Type[] pERKS_TO_LOAD = Constants.PERKS_TO_LOAD;
			foreach (Type type in pERKS_TO_LOAD)
			{
				CustomPerk perk = (CustomPerk)(object)ScriptableObject.CreateInstance(type);
				Debug.Log((object)("[CustomPerkSystem] Registering " + type.Name));
				RegisterCustomPerk(perk);
			}
		}

		public static void RegisterCustomPerk(CustomPerk perk)
		{
			if (!_customPerks.Contains(perk))
			{
				_customPerks.Add(perk);
				AddToGameDesignData(perk);
			}
		}

		private static void AddToGameDesignData(CustomPerk perk)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GameSingleton.Instance == (Object)null)
			{
				Debug.LogError((object)"[CustomPerkSystem] GameSingleton.Instance is null");
				return;
			}
			Perk[] perks = GameSingleton.Instance.gameDesignData.perks;
			if (perks.Contains((Perk)(object)perk))
			{
				return;
			}
			Perk[] array = (Perk[])(object)new Perk[perks.Length + 1];
			Array.Copy(perks, array, perks.Length);
			array[^1] = (Perk)(object)perk;
			GameSingleton.Instance.gameDesignData.perks = array;
			((Perk)perk).availability = (Availability)5;
			((Perk)perk).dontIncludeInPool = false;
			if (perk != null)
			{
				if (true)
				{
					SetupCustomPerk(perk);
				}
			}
		}

		private static void SetupCustomPerk(CustomPerk perk)
		{
			if (!string.IsNullOrEmpty(perk.perkIconKey) && (Object)(object)PerkAssetBundleLoader.PerkIconBundle != (Object)null)
			{
				Sprite val = PerkAssetBundleLoader.LoadSprite(perk.perkIconKey);
				if ((Object)(object)val != (Object)null)
				{
					((Perk)perk).icon = val;
				}
				else
				{
					Plugin.Log.LogWarning((object)("[CustomPerkSystem] Sprite '" + perk.perkIconKey + "' not found in bundle. Available assets: " + string.Join(", ", PerkAssetBundleLoader.PerkIconBundle.GetAllAssetNames())));
				}
			}
			if (!string.IsNullOrEmpty(perk.displayTitle))
			{
				InjectAndAssignStrings(perk);
			}
		}

		private static void InjectAndAssignStrings(CustomPerk perk)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			LocalizedString val = null;
			Perk[] perks = GameSingleton.GameDesignData.perks;
			foreach (Perk val2 in perks)
			{
				if (!((Object)(object)val2 == (Object)null) && !(val2 is CustomPerk) && val2.translatedTitle != null)
				{
					TableReference tableReference = ((LocalizedReference)val2.translatedTitle).TableReference;
					if (!string.IsNullOrEmpty(((object)(TableReference)(ref tableReference)).ToString()))
					{
						val = val2.translatedTitle;
						break;
					}
				}
			}
			if (val != null)
			{
				TableReference tableReference2 = ((LocalizedReference)val).TableReference;
				AsyncOperationHandle<StringTable> tableAsync = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTableAsync(tableReference2, (Locale)null);
				tableAsync.WaitForCompletion();
				if (tableAsync.IsDone && !((Object)(object)tableAsync.Result == (Object)null))
				{
					StringTable result = tableAsync.Result;
					result.AddOrUpdate(perk.displayTitleKey, perk.displayTitle);
					result.AddOrUpdate(perk.displayDescKey, perk.displayDesc);
					((Perk)perk).translatedTitle = new LocalizedString(tableReference2, TableEntryReference.op_Implicit(perk.displayTitleKey));
					((Perk)perk).translatedDesc = new LocalizedString(tableReference2, TableEntryReference.op_Implicit(perk.displayDescKey));
				}
			}
		}

		private static void AddOrUpdate(this StringTable table, string key, string value)
		{
			if (((DetailedLocalizationTable<StringTableEntry>)(object)table).GetEntry(key) == null)
			{
				((DetailedLocalizationTable<StringTableEntry>)(object)table).AddEntry(key, value);
			}
			else
			{
				((DetailedLocalizationTable<StringTableEntry>)(object)table).GetEntry(key).Value = value;
			}
		}
	}
	[HarmonyPatch(typeof(GameSingleton), "Awake")]
	public static class Patch_RegisterCustomPerks
	{
		private static void Postfix()
		{
			if (!((Object)(object)GameSingleton.Instance == (Object)null))
			{
				CustomPerkSystem.RegisterAll();
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.callumcustomperks.plugins.moregentlemandisputes";

		public const string PLUGIN_NAME = "Custom Gentleman Dispute Perks from Callum";

		public const string PLUGIN_VERSION = "1.0.0.0";
	}
	[BepInPlugin("com.callumcustomperks.plugins.moregentlemandisputes", "Custom Gentleman Dispute Perks from Callum", "1.0.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("com.callumcustomperks.plugins.moregentlemandisputes");
			_harmony.PatchAll();
			Log.LogInfo((object)"Custom Gentleman Dispute Perks from Callum loaded!");
			PerkAssetBundleLoader.Init(((BaseUnityPlugin)this).Info);
			CustomMapLoader.Init(((BaseUnityPlugin)this).Info);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "customgentlemensdisputes";

		public const string PLUGIN_NAME = "customgentlemensdisputes";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace customgentlemensdisputes.Maps
{
	public static class CustomMapRegistry
	{
		private static readonly List<CustomMap> _maps = new List<CustomMap>();

		public static IReadOnlyList<CustomMap> Maps => _maps;

		public static void RegisterAll()
		{
			CustomMap[] mAPS_TO_LOAD = Constants.MAPS_TO_LOAD;
			foreach (CustomMap map in mAPS_TO_LOAD)
			{
				RegisterMap(map);
			}
		}

		public static void RegisterMap(CustomMap map)
		{
			if (_maps.Any((CustomMap m) => m.SceneName == map.SceneName))
			{
				Plugin.Log.LogWarning((object)("[MapRegistry] '" + map.SceneName + "' already registered, skipping."));
				return;
			}
			_maps.Add(map);
			Plugin.Log.LogInfo((object)("[MapRegistry] Queued map: '" + map.DisplayName + "' (scene: " + map.SceneName + ")"));
		}

		public static void InjectQueuedMaps()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			foreach (CustomMap map in Maps)
			{
				List<MapEntry> levels = GameSingleton.Instance.gameDesignData.levels;
				if (levels.Any((MapEntry e) => e.scenes != null && e.scenes.Contains(map.SceneName)))
				{
					continue;
				}
				MapEntry val = new MapEntry();
				val.scenes = new string[1] { map.SceneName };
				val.availability = (Availability)5;
				val.maxItemSpawnMultiplier = map.MaxItemSpawnMultiplier;
				val.icon = CustomMapLoader.GetCachedIcon(map.SceneName);
				MapEntry val2 = val;
				LocalizedString val3 = ((IEnumerable<MapEntry>)levels).FirstOrDefault((Func<MapEntry, bool>)delegate(MapEntry e)
				{
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					int result;
					if (e?.levelTitle != null)
					{
						TableReference tableReference = ((LocalizedReference)e.levelTitle).TableReference;
						result = ((!string.IsNullOrEmpty(((object)(TableReference)(ref tableReference)).ToString())) ? 1 : 0);
					}
					else
					{
						result = 0;
					}
					return (byte)result != 0;
				})?.levelTitle;
				if (val3 != null)
				{
					string text = "CustomMap_" + map.SceneName + "_Title";
					InjectLocalizedString(((LocalizedReference)val3).TableReference, text, map.DisplayName);
					val2.levelTitle = new LocalizedString(((LocalizedReference)val3).TableReference, TableEntryReference.op_Implicit(text));
				}
				levels.Add(val2);
				Plugin.Log.LogInfo((object)$"[MapRegistry] Injected '{map.DisplayName}' at index {levels.Count - 1}.");
			}
		}

		private static void InjectLocalizedString(TableReference tableRef, string key, string value)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				AsyncOperationHandle<StringTable> tableAsync = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTableAsync(tableRef, (Locale)null);
				tableAsync.WaitForCompletion();
				if (tableAsync.IsDone && !((Object)(object)tableAsync.Result == (Object)null))
				{
					StringTable result = tableAsync.Result;
					if (((DetailedLocalizationTable<StringTableEntry>)(object)result).GetEntry(key) == null)
					{
						((DetailedLocalizationTable<StringTableEntry>)(object)result).AddEntry(key, value);
					}
					else
					{
						((DetailedLocalizationTable<StringTableEntry>)(object)result).GetEntry(key).Value = value;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[MapRegistry] Localization failed for '" + key + "': " + ex.Message));
			}
		}

		public static CustomMap GetBySceneName(string sceneName)
		{
			return _maps.FirstOrDefault((CustomMap m) => m.SceneName == sceneName);
		}
	}
	[HarmonyPatch(typeof(GameDesignData), "Init")]
	public static class Patch_GameDesignData_Init_RegisterMaps
	{
		private static void Postfix(GameDesignData __instance)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Expected O, but got Unknown
			if (CustomMapRegistry.Maps.Count == 0)
			{
				return;
			}
			TableReference? val = null;
			foreach (MapEntry level in __instance.levels)
			{
				if (level?.levelTitle != null)
				{
					TableReference tableReference = ((LocalizedReference)level.levelTitle).TableReference;
					if (!string.IsNullOrEmpty(((object)(TableReference)(ref tableReference)).ToString()))
					{
						val = ((LocalizedReference)level.levelTitle).TableReference;
						break;
					}
				}
			}
			foreach (CustomMap map in CustomMapRegistry.Maps)
			{
				if (!__instance.levels.Any((MapEntry e) => e.scenes != null && e.scenes.Contains(map.SceneName)))
				{
					MapEntry val2 = new MapEntry();
					val2.scenes = new string[1] { map.SceneName };
					val2.availability = (Availability)5;
					val2.maxItemSpawnMultiplier = map.MaxItemSpawnMultiplier;
					val2.icon = CustomMapLoader.GetCachedIcon(map.SceneName);
					MapEntry val3 = val2;
					if (val.HasValue)
					{
						string text = "CustomMap_" + map.SceneName + "_Title";
						InjectLocalizedString(val.Value, text, map.DisplayName);
						val3.levelTitle = new LocalizedString(val.Value, TableEntryReference.op_Implicit(text));
					}
					__instance.levels.Add(val3);
					Plugin.Log.LogInfo((object)("[MapRegistry] Injected '" + map.DisplayName + "' at index " + $"{__instance.levels.Count - 1}."));
				}
			}
		}

		private static void InjectLocalizedString(TableReference tableRef, string key, string value)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				AsyncOperationHandle<StringTable> tableAsync = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase).GetTableAsync(tableRef, (Locale)null);
				tableAsync.WaitForCompletion();
				if (tableAsync.IsDone && !((Object)(object)tableAsync.Result == (Object)null))
				{
					StringTable result = tableAsync.Result;
					if (((DetailedLocalizationTable<StringTableEntry>)(object)result).GetEntry(key) == null)
					{
						((DetailedLocalizationTable<StringTableEntry>)(object)result).AddEntry(key, value);
					}
					else
					{
						((DetailedLocalizationTable<StringTableEntry>)(object)result).GetEntry(key).Value = value;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[MapRegistry] Could not inject localized string '" + key + "': " + ex.Message));
			}
		}
	}
	public static class CustomMapLoader
	{
		public const string TAG_PLAYER_SPAWN = "MGD_PlayerSpawn";

		public const string TAG_ITEM_SPAWN = "MGD_ItemSpawn";

		private const int MIN_PLAYER_SPAWNS = 8;

		private const int MIN_ITEM_SPAWNS = 18;

		private static readonly Dictionary<string, AssetBundle> _bundles = new Dictionary<string, AssetBundle>();

		private static readonly Dictionary<string, Sprite> _iconCache = new Dictionary<string, Sprite>();

		public static AssetBundle CustomMapsBundle { get; private set; }

		public static Sprite GetCachedIcon(string sceneName)
		{
			Sprite value;
			return _iconCache.TryGetValue(sceneName, out value) ? value : null;
		}

		public static void Init(PluginInfo Info)
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
			string text = Path.Combine(Path.GetDirectoryName(Info.Location), "custommaps.bundle");
			CustomMapsBundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)CustomMapsBundle == (Object)null)
			{
				Plugin.Log.LogError((object)("[MapLoader] LoadFromFile returned null at: " + text));
				return;
			}
			foreach (CustomMap map in CustomMapRegistry.Maps)
			{
				LoadBundleForMap(map);
			}
		}

		public static void Shutdown()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private static void LoadBundleForMap(CustomMap map)
		{
			Plugin.Log.LogInfo((object)("[MapLoader] Looking for bundle at: " + Path.Combine("Assets/CustomMaps/", map.SceneName)));
			string[] allScenePaths = CustomMapsBundle.GetAllScenePaths();
			Plugin.Log.LogInfo((object)("[MapLoader] Bundle loaded. Scenes inside: " + string.Join(", ", allScenePaths)));
			_bundles[map.SceneName] = CustomMapsBundle;
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			CustomMap bySceneName = CustomMapRegistry.GetBySceneName(((Scene)(ref scene)).name);
			if (bySceneName != null)
			{
				Plugin.Log.LogInfo((object)("[MapLoader] Custom map scene loaded: '" + ((Scene)(ref scene)).name + "'. Injecting required objects..."));
				CoroutineRunner.Run(InjectMapObjects(bySceneName));
			}
		}

		private static IEnumerator InjectMapObjects(CustomMap map)
		{
			yield return null;
			TryInject("PlayerSpawns", delegate
			{
				InjectPlayerSpawns(map);
			});
			TryInject("ItemSpawns", delegate
			{
				InjectItemSpawns(map);
			});
			if (InstanceFinder.IsServerStarted)
			{
				yield return null;
				TryInject("LoadMarker", SpawnLoadMarker);
			}
			Plugin.Log.LogInfo((object)("[MapLoader] Injection complete for '" + map.SceneName + "'."));
		}

		private static void TryInject(string name, Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[MapLoader] Failed to inject {name}: {arg}");
			}
		}

		private static void InjectPlayerSpawns(CustomMap map)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("MGD_PlayerSpawn");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)("[MapLoader] No GameObject named 'MGD_PlayerSpawns' found in '" + map.SceneName + "'. Create a parent GameObject with this name and place spawn points as children."));
				return;
			}
			int childCount = val.transform.childCount;
			if (childCount == 0)
			{
				Plugin.Log.LogError((object)("[MapLoader] 'MGD_PlayerSpawns' has no children in '" + map.SceneName + "'."));
				return;
			}
			if (childCount < 8)
			{
				Plugin.Log.LogWarning((object)$"[MapLoader] Only {childCount} player spawns (recommend {8}+).");
			}
			GameObject val2 = new GameObject("PlayerSpawns");
			for (int i = 0; i < childCount; i++)
			{
				GameObject val3 = new GameObject($"Spawns ({i})");
				val3.transform.SetParent(val2.transform, false);
				val3.transform.position = val.transform.GetChild(i).position;
				val3.AddComponent<SpawnPoint>();
			}
			Plugin.Log.LogInfo((object)$"[MapLoader] Injected {childCount} player spawns.");
		}

		private static void InjectItemSpawns(CustomMap map)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("MGD_ItemSpawn");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)("[MapLoader] No GameObject named 'MGD_ItemSpawns' found in '" + map.SceneName + "'."));
				return;
			}
			int childCount = val.transform.childCount;
			if (childCount == 0)
			{
				Plugin.Log.LogError((object)"[MapLoader] 'MGD_ItemSpawns' has no children.");
				return;
			}
			if (childCount < 18)
			{
				Plugin.Log.LogWarning((object)$"[MapLoader] Only {childCount} item spawns (recommend {18}+).");
			}
			GameObject val2 = new GameObject("ItemSpawns");
			for (int i = 0; i < childCount; i++)
			{
				GameObject val3 = new GameObject($"Spawns ({i})");
				val3.transform.SetParent(val2.transform, false);
				val3.transform.position = val.transform.GetChild(i).position;
				ItemSpawnPoint val4 = val3.AddComponent<ItemSpawnPoint>();
				val4.itemSpawnType = (ItemSpawnType)2;
			}
			Plugin.Log.LogInfo((object)$"[MapLoader] Injected {childCount} item spawns.");
		}

		private static void SpawnLoadMarker()
		{
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = InstanceFinder.NetworkManager;
			if ((Object)(object)networkManager == (Object)null)
			{
				return;
			}
			NetworkObject val = null;
			PrefabObjects spawnablePrefabs = networkManager.SpawnablePrefabs;
			SinglePrefabObjects val2 = (SinglePrefabObjects)(object)((spawnablePrefabs is SinglePrefabObjects) ? spawnablePrefabs : null);
			if ((Object)(object)val2 != (Object)null)
			{
				foreach (NetworkObject prefab in val2.Prefabs)
				{
					if ((Object)(object)prefab != (Object)null && (Object)(object)((Component)prefab).GetComponent<LoadMarker>() != (Object)null)
					{
						val = prefab;
						break;
					}
				}
			}
			else
			{
				int objectCount = networkManager.SpawnablePrefabs.GetObjectCount();
				for (int i = 0; i < objectCount; i++)
				{
					NetworkObject @object = networkManager.SpawnablePrefabs.GetObject(true, i);
					if ((Object)(object)@object != (Object)null && (Object)(object)((Component)@object).GetComponent<LoadMarker>() != (Object)null)
					{
						val = @object;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"[MapLoader] LoadMarker not found in SpawnablePrefabs. Loading screen will hang. Verify FishNet version matches game.");
				return;
			}
			GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject);
			InstanceFinder.ServerManager.Spawn(val3, (NetworkConnection)null, default(Scene));
			Plugin.Log.LogInfo((object)"[MapLoader] LoadMarker spawned.");
		}
	}
	internal class CoroutineRunner : MonoBehaviour
	{
		private static CoroutineRunner _instance;

		internal static void Run(IEnumerator routine)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)_instance == (Object)null)
			{
				GameObject val = new GameObject("__MapLoaderCoroutineRunner");
				Object.DontDestroyOnLoad((Object)(object)val);
				_instance = val.AddComponent<CoroutineRunner>();
			}
			((MonoBehaviour)_instance).StartCoroutine(routine);
		}
	}
	[HarmonyPatch(typeof(GameSingleton), "Awake")]
	public static class Patch_RegisterCustomMaps
	{
		private static void Postfix()
		{
			if (!((Object)(object)GameSingleton.Instance == (Object)null))
			{
				CustomMapRegistry.RegisterAll();
				CustomMapRegistry.InjectQueuedMaps();
			}
		}
	}
}
namespace customgentlemensdisputes.maps
{
	public abstract class CustomMap
	{
		public abstract string SceneName { get; }

		public abstract string DisplayName { get; }

		public abstract float MaxItemSpawnMultiplier { get; }

		public virtual string IconAssetPath => null;
	}
}
namespace customgentlemensdisputes.perks
{
	public class ComingForYourAssCustomPerk : CustomPerk
	{
		public override string displayTitle => "Coming for Your Ass";

		public override string displayDesc => "Deal and receive double damage while you have the lowest score";

		public override string perkIconKey => "grrmeme";
	}
	[HarmonyPatch(typeof(CoreCharacterController), "DealDamage", new Type[] { typeof(DamageSource) })]
	public static class Patch_DealDamage_ComingForYourAssCustomPerk
	{
		private static void Prefix(ref DamageSource source)
		{
			if (source.Damage.HasValue && !((Object)(object)source.Player == (Object)null) && source.Player.HasPerk<ComingForYourAssCustomPerk>() && IsInLastPlace(source.Player))
			{
				int num = source.Player.GetPerks<ComingForYourAssCustomPerk>().Count();
				source.Damage *= Mathf.Pow(2f, (float)num);
				source.Player.ActivatePerk((Perk)(object)source.Player.GetPerk<ComingForYourAssCustomPerk>(), false);
			}
		}

		private static bool IsInLastPlace(PlayerController player)
		{
			if ((Object)(object)SessionManager.Instance == (Object)null)
			{
				return false;
			}
			int num = SessionManager.Instance.allPlayers.Where((PlayerController p) => (Object)(object)p != (Object)null).Min((PlayerController p) => p.GetScore());
			return player.GetScore() == num;
		}
	}
	public class FastAsFuckBoiCustomPerk : CustomPerk
	{
		public override string displayTitle => "Fast as Fuck Boi";

		public override string displayDesc => "Player's speed is increased by 70%";

		public override string perkIconKey => "fastmeme";
	}
	[HarmonyPatch(typeof(CharacterMovementController), "UpdateVelocity")]
	public class FastAsFuckBoiSpeedPatch
	{
		[HarmonyPatch(typeof(CoreCharacterController), "InitPerks")]
		public class FastAsFuckBoiSetupPatch
		{
			private static void Postfix(CoreCharacterController __instance)
			{
				if ((Object)(object)__instance.Player != (Object)null && __instance.Player.HasPerk<FastAsFuckBoiCustomPerk>())
				{
					CharacterMovementController movementController = __instance.MovementController;
					if ((Object)(object)movementController != (Object)null)
					{
						movementController.moveSpeed *= 1.7f;
						movementController.playerAcceleration *= 1.7f;
						movementController.playerTurnSpeed *= 1.5f;
						Plugin.Log.LogInfo((object)("FastAsFuckBoi Perk Applied: Speed boosted to " + movementController.moveSpeed));
					}
				}
			}
		}
	}
}