Decompiled source of GrubAdoption v0.2.1

com.anonymousfroggo.grubadoption.dll

Decompiled 2 days 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 System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using GrubAdoption.Assets;
using GrubAdoption.Rescuing;
using GrubAdoption.Stats;
using GrubAdoption.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using WKLib.Assets;
using WKLib.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.anonymousfroggo.grubadoption")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.1.0")]
[assembly: AssemblyInformationalVersion("0.2.1+d01fbfb03a7f654059ed71cd8d032b7382e254f4")]
[assembly: AssemblyProduct("Grub Adoption")]
[assembly: AssemblyTitle("com.anonymousfroggo.grubadoption")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.1.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 GrubAdoption
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.anonymousfroggo.grubadoption", "Grub Adoption", "0.2.1")]
	public class Plugin : BaseUnityPlugin
	{
		private bool initialized;

		public static Plugin Instance { get; private set; }

		public ModContext ModContext { get; private set; }

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			ModContext = ModRegistry.Register("com.anonymousfroggo.grubadoption", "0.2.1");
			new Harmony("com.anonymousfroggo.grubadoption").PatchAll();
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			switch (((Scene)(ref scene)).name)
			{
			case "Intro":
				Initialize();
				break;
			case "Game-Main":
			case "Playground":
				OnGameLoaded(scene);
				break;
			}
		}

		private async void Initialize()
		{
			if (!initialized)
			{
				Log.Initialize(((BaseUnityPlugin)this).Logger);
				CustomScriptManager.RegisterAssembly(Assembly.GetExecutingAssembly(), ModContext);
				await GrubAdoptionAssets.Initialize();
				initialized = true;
			}
		}

		private void OnGameLoaded(Scene scene)
		{
		}

		public static GameObject FindGameManagerGameObject(Scene scene)
		{
			GameObject val = (from gameObject in ((Scene)(ref scene)).GetRootGameObjects()
				where ((Object)gameObject).name == "GameManager"
				select gameObject).FirstOrDefault();
			if ((Object)(object)val == (Object)null)
			{
				Log.Error("Finding GameManager failed");
				return null;
			}
			return val;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.anonymousfroggo.grubadoption";

		public const string PLUGIN_NAME = "Grub Adoption";

		public const string PLUGIN_VERSION = "0.2.1";
	}
}
namespace GrubAdoption.Utils
{
	public static class AssetUtils
	{
		public const string BASE_DATABASE = "basedatabase";

		public static GameObject GetAsset(string name)
		{
			return CL_AssetManager.GetAssetGameObject(name, "basedatabase");
		}

		public static Item GetItem(string itemName)
		{
			return GetAsset(itemName).GetComponent<Item_Object>().itemData;
		}
	}
	public class DebugHelper : MonoBehaviour
	{
		public static void Initialize(Scene scene)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Plugin.FindGameManagerGameObject(scene);
			if (obj != null)
			{
				obj.AddComponent<DebugHelper>();
			}
		}

		private void Start()
		{
			CommandConsole.AddCommand("grubsstored", (Action<string[]>)GrubsStoredCommand, false);
			CommandConsole.AddCommand("liststats", (Action<string[]>)ListStatsCommand, false);
			CommandConsole.AddCommand("savestats", (Action<string[]>)SaveStatsCommand, false);
			CommandConsole.AddCommand("win", (Action<string[]>)WinCommand, false);
		}

		private static void GrubsStoredCommand(string[] args)
		{
			CommandConsole.Log(GrubRescueStation.GetGrubsStored().ToString(), false);
		}

		private static void ListStatsCommand(string[] args)
		{
			StatUtils.StatSource result;
			if (args.Length == 0)
			{
				PrintStatsList(StatUtils.StatSource.global);
				PrintStatsList(StatUtils.StatSource.gamemode);
				PrintStatsList(StatUtils.StatSource.session);
			}
			else if (!Enum.TryParse<StatUtils.StatSource>(args[0], ignoreCase: true, out result))
			{
				CommandConsole.LogError("Not a valid stat source: " + args[0]);
			}
			else
			{
				PrintStatsList(result);
			}
			static void PrintStatsList(StatUtils.StatSource source)
			{
				List<Statistic> list = new List<Statistic>(StatUtils.GetStats(source).statistics);
				list.Sort((Statistic x, Statistic y) => x.id.CompareTo(y.id));
				foreach (Statistic item in list)
				{
					CommandConsole.Log($"Stat ({source}): {item.id} = {item.GetString()}", false);
				}
			}
		}

		private static void SaveStatsCommand(string[] args)
		{
			//IL_0036: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			ActivateCheats();
			foreach (Statistic statistic in StatManager.sessionStats.statistics)
			{
				StatManager.saveData.gameStats.UpdateStatistic(statistic.id, statistic.GetValue(), statistic.type, statistic.defaultModType, statistic.displayType, (ModType)1);
			}
			if ((Object)(object)CL_GameManager.gamemode != (Object)null)
			{
				StatManager.saveData.UpdateGamemodeStats(CL_GameManager.GetGamemodeName(true, false), StatManager.sessionStats);
			}
			File.WriteAllText(Path.Combine(Application.persistentDataPath, "save.json"), JsonUtility.ToJson((object)StatManager.saveData, true));
			StatManager.instance.UpdateUI();
		}

		private static void WinCommand(string[] args)
		{
			ActivateCheats();
			CL_GameManager.gMan.Win();
		}

		private static void ActivateCheats()
		{
			if (!CommandConsole.cheatsEnabled)
			{
				CommandConsole.instance.ExecuteCommand("cheats");
			}
		}
	}
	public static class InventoryUtils
	{
		public static int TotalItemCount(string itemName)
		{
			return BagItemCount(itemName) + HandItemCount(itemName);
		}

		public static int BagItemCount(string itemName)
		{
			return ENT_Player.GetInventory().bagItems.Count((Item bagItem) => bagItem.itemName.Equals(itemName));
		}

		public static int HandItemCount(string itemName)
		{
			return ENT_Player.GetInventory().itemHands.Count((ItemHand itemHand) => itemHand.currentItem != null && itemHand.currentItem.itemName.Equals(itemName));
		}

		public static void LoadItemIntoBag(Item item)
		{
			//IL_0017: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//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_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_0041: 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)
			Item clone = item.GetClone();
			clone.bagPosition = new Vector3(0f, 0f, 1f) + Random.insideUnitSphere * 0.01f;
			clone.bagRotation = Quaternion.LookRotation(clone.upDirection);
			Inventory.instance.AddItemToInventoryScreen(clone.bagPosition, clone, true, true);
			clone.inventory = Inventory.instance;
		}
	}
	public static class Log
	{
		private static ManualLogSource log;

		internal static void Initialize(ManualLogSource log)
		{
			Log.log = log;
		}

		public static void Info(object msg)
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogInfo(msg);
			}
		}

		public static void Warn(object msg)
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogWarning(msg);
			}
		}

		public static void Error(object msg)
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogError(msg);
			}
		}

		public static void Debug(object msg)
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogDebug(msg);
			}
		}
	}
	public static class Names
	{
		public static class Denizens
		{
			public const string GRUB = "Denizen_SlugGrub";
		}

		public static class Gamemodes
		{
			public const string CAMPAIGN = "GM_Campaign";

			public const string PLAYGROUND = "GM_Playground";
		}

		public static class Items
		{
			public const string GRUB = "SlugGrub";
		}

		public static class Scenes
		{
			public const string INTRO = "Intro";

			public const string MAIN_MENU = "Main-Menu";

			public const string GAME_MAIN = "Game-Main";

			public const string PLAYGROUND = "Playground";
		}

		public static class Stats
		{
		}

		public static class Ui
		{
			public const string SCORE_PANEL_STANDARD_PREFIX = "ScorePanel_Standard";

			public const string SCORE_SCREEN_SESSION_STAT_PREFIX = "session-stat:";

			public const string SCORE_SCREEN_GAMEMODE_STAT_PREFIX = "gamemode-stat:";

			public const string GAMEMODE_STAT_PREFIX = "stat-";

			public const string LOGBOOK_STAT_PREFIX = "stat-";
		}

		public const string GAME_MANAGER = "GameManager";

		public static string Instantiated(string name)
		{
			return name + "(Clone)";
		}
	}
	public static class Paths
	{
	}
	public static class StatUtils
	{
		public enum StatSource
		{
			session,
			gamemode,
			global
		}

		public const string STAT_PICKUP_ITEM_PREFIX = "pickup-item-";

		public const string STAT_ITEMS_USED = "items-used";

		public const string DEFAULT_TEXT_REDACTED = "[REDACTED]";

		public static string GetText(CustomStat stat, StatSource statSource)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			GameStats val = (GameStats)((int)statSource switch
			{
				2 => StatManager.sessionStats, 
				0 => StatManager.saveData.GetGameMode(CL_GameManager.GetGamemodeName(true, false)).stats, 
				3 => StatManager.saveData.gameStats, 
				_ => null, 
			});
			if (!val.HasStatistic(stat.GetId()))
			{
				return stat.GetDefaultText(statSource);
			}
			return stat.GetTextPrefix(statSource) + val.GetStatistic(stat.GetId()).GetString();
		}

		public static bool HasStat(string id)
		{
			if (!StatManager.saveData.gameStats.HasStatistic(id))
			{
				return StatManager.sessionStats.HasStatistic(id);
			}
			return true;
		}

		public static bool HasPickedUpItem(string itemName)
		{
			return HasStat("pickup-item-" + itemName);
		}

		public static object GetValueOrDefault(string id, object defaultValue, StatSource source)
		{
			Statistic stat = GetStat(id, source);
			return ((stat != null) ? stat.GetValue() : null) ?? defaultValue;
		}

		public static Statistic GetStat(string id, StatSource source)
		{
			GameStats stats = GetStats(source);
			if (stats == null)
			{
				return null;
			}
			return stats.GetStatistic(id);
		}

		public static GameStats GetStats(StatSource source)
		{
			return (GameStats)(source switch
			{
				StatSource.session => StatManager.sessionStats, 
				StatSource.gamemode => StatManager.saveData.GetGameMode(CL_GameManager.GetGamemodeName(true, false))?.stats, 
				StatSource.global => StatManager.saveData.gameStats, 
				_ => null, 
			});
		}
	}
	public static class UiUtils
	{
		public static void Destroy(Transform child)
		{
			Object.Destroy((Object)(object)((Component)child).gameObject);
		}

		public static void DestroyChild(string childName, Transform parent)
		{
			Transform val = parent.Find(childName);
			if ((Object)(object)val == (Object)null)
			{
				Log.Error("Child " + childName + " of " + ((Object)parent).name + " not found");
			}
			else
			{
				Destroy(val);
			}
		}
	}
}
namespace GrubAdoption.Stats
{
	public abstract class CustomStat
	{
		private readonly string id;

		protected object value;

		private readonly DataType type;

		private readonly ModType modType;

		private readonly DisplayType displayType;

		private readonly ModType globalModType;

		protected CustomStat(string id, object initialValue, DataType dataType, ModType modType, DisplayType displayType, ModType globalModType)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			//IL_0026: 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)
			this.id = id;
			value = initialValue;
			type = dataType;
			this.modType = modType;
			this.displayType = displayType;
			this.globalModType = globalModType;
			base..ctor();
		}

		public void EndGameStatUpdate(bool win)
		{
			if (CalculateValueOnEndGame(win))
			{
				WriteToSessionStats();
			}
		}

		protected virtual bool CalculateValueOnEndGame(bool win)
		{
			return false;
		}

		private void WriteToSessionStats()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			StatManager.sessionStats.UpdateStatistic(id, value, type, modType, displayType, globalModType);
		}

		public string GetId()
		{
			return id;
		}

		public abstract string GetDefaultText(StatSource statSource);

		public abstract string GetTextPrefix(StatSource statSource);

		public abstract bool ShouldAddToScoreScreenSession(bool win);

		public abstract bool ShouldAddToScoreScreenGamemode(bool win);

		public abstract bool ShouldAddToGamemode(M_Gamemode gamemode);

		public abstract bool ShouldAddToLogbook();

		public virtual int GetScoreScreenSessionIndex()
		{
			return 0;
		}

		public virtual int GetScoreScreenGamemodeIndex()
		{
			return 0;
		}

		public virtual int GetGamemodeIndex()
		{
			return 0;
		}

		public virtual int GetLogbookIndex()
		{
			return 0;
		}
	}
	[HarmonyPatch]
	public class CustomStatManager
	{
		public enum StatSource
		{
			gamemode = 0,
			session = 2,
			global = 3
		}

		private static readonly CustomStatManager instance = new CustomStatManager();

		private readonly CustomStat[] customStats = new CustomStat[2]
		{
			new GrubsAdopted(),
			new MaxGrubsAdopted()
		};

		public static bool Win { get; set; }

		[HarmonyPatch(typeof(CL_GameManager), "EndGameStatUpdate")]
		[HarmonyPostfix]
		public static void EndGameStatUpdate(bool win)
		{
			Win = win;
			CustomStat[] array = instance.customStats;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].EndGameStatUpdate(Win);
			}
			GrubStats.UpdateGrubScore();
		}

		[HarmonyPatch(typeof(UI_ScoreScreen), "ShowScreen")]
		[HarmonyPostfix]
		public static void AddStatsToScoreScreen(UI_ScoreScreen __instance)
		{
			if (!((Object)((Component)__instance).gameObject).name.StartsWith("ScorePanel_Standard"))
			{
				return;
			}
			Transform val = ((Component)__instance).gameObject.transform.Find("Session Page/Board/Stats/SessionStats/Game Stats Simplified");
			Transform val2 = ((Component)__instance).gameObject.transform.Find("Session Page/Board/Stats/Best Stats/Top Score");
			CustomStat[] array = instance.customStats;
			foreach (CustomStat customStat in array)
			{
				if (customStat.ShouldAddToScoreScreenSession(Win))
				{
					GameObject obj = Object.Instantiate<GameObject>(((Component)val.GetChild(4)).gameObject, val);
					((Object)obj).name = "session-stat:" + customStat.GetId();
					obj.transform.SetSiblingIndex(customStat.GetScoreScreenSessionIndex());
					((TMP_Text)obj.GetComponent<TextMeshProUGUI>()).text = StatUtils.GetText(customStat, (StatSource)2);
				}
				if (customStat.ShouldAddToScoreScreenGamemode(Win))
				{
					Transform transform = Object.Instantiate<GameObject>(((Component)val2.GetChild(3)).gameObject, val2).transform;
					((Object)((Component)transform).gameObject).name = "gamemode-stat:" + customStat.GetId();
					transform.SetSiblingIndex(customStat.GetScoreScreenGamemodeIndex());
					((TMP_Text)((Component)transform).GetComponent<TextMeshProUGUI>()).text = StatUtils.GetText(customStat, (StatSource)0);
				}
			}
		}

		[HarmonyPatch(typeof(UI_GamemodeScreen), "Initialize")]
		[HarmonyPostfix]
		public static void AddStatsToGamemode(UI_GamemodeScreen __instance, M_Gamemode mode)
		{
			Transform val = ((Component)__instance).gameObject.transform.Find("Gamemode_Panel_Base_Campaign(Clone)/Mode Page/Board/Stats/Stats/Scoregrid-Extra/");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			CustomStat[] array = instance.customStats;
			foreach (CustomStat customStat in array)
			{
				Transform val2 = val.Find("stat-" + customStat.GetId());
				if ((Object)(object)val2 != (Object)null)
				{
					UiUtils.Destroy(val2);
				}
				if (customStat.ShouldAddToGamemode(mode))
				{
					val2 = InstantiateStatText(customStat, val, "stat-", 1);
					val2.SetSiblingIndex(customStat.GetGamemodeIndex());
					((Component)val2).GetComponent<UT_StatText>().Refresh();
				}
			}
		}

		[HarmonyPatch(typeof(UI_MenuScreen), "Initialize")]
		[HarmonyPostfix]
		public static void AddStatsToLogbook(UI_MenuScreen __instance)
		{
			if (!((Object)__instance).name.Equals("Logbook"))
			{
				return;
			}
			Transform parent = ((Component)__instance).gameObject.transform.Find("Stat Page/Board/Stats/Stats/Scoregrid-Extra");
			UiUtils.DestroyChild("Break-Roaches.02", parent);
			UiUtils.DestroyChild("Break-Roaches", parent);
			CustomStat[] array = instance.customStats;
			foreach (CustomStat customStat in array)
			{
				if (customStat.ShouldAddToLogbook())
				{
					InstantiateStatText(customStat, parent, "stat-", 1).SetSiblingIndex(customStat.GetLogbookIndex());
				}
			}
		}

		private static Transform InstantiateStatText(CustomStat stat, Transform parent, string uiNamePrefix, int instantiationIndex)
		{
			//IL_0038: 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)
			Transform transform = Object.Instantiate<GameObject>(((Component)parent.GetChild(instantiationIndex)).gameObject, parent).transform;
			((Object)((Component)transform).gameObject).name = uiNamePrefix + stat.GetId();
			UT_StatText component = ((Component)transform).GetComponent<UT_StatText>();
			component.defaultText = stat.GetDefaultText(component.source);
			component.textPrefix = stat.GetTextPrefix(component.source);
			((Object)component).name = uiNamePrefix + stat.GetId();
			component.statistic = stat.GetId();
			return transform;
		}
	}
	public class GrubsAdopted : CustomStat
	{
		public const string ID = "grubs-adopted";

		public const string DEFAULT_TEXT_NO_GRUBS = "Don't you care about Grubs? :(";

		public const string DEFAULT_TEXT_DEATH_WITH_GRUB = "You left your Grub alone T.T";

		public const string DEFAULT_TEXT_DEATH_WITH_GRUBS = "You left your Grubs alone T.T";

		public const string TEXT_PREFIX_SESSION = "Grubs Adopted: ";

		public const string TEXT_PREFIX_GLOBAL = "Total Grubs Adopted: ";

		public GrubsAdopted()
			: base("grubs-adopted", 0, (DataType)0, (ModType)1, (DisplayType)0, (ModType)1)
		{
		}

		protected override bool CalculateValueOnEndGame(bool win)
		{
			if (!win)
			{
				return false;
			}
			if (GrubStats.GetRescuedGrubsCount() == 0)
			{
				return false;
			}
			value = GrubStats.GetRescuedGrubsCount();
			return true;
		}

		public override string GetDefaultText(StatSource statSource)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!StatUtils.HasPickedUpItem("SlugGrub"))
			{
				return "[REDACTED]";
			}
			if ((int)statSource == 2)
			{
				return GrubStats.GetRescuedGrubsCount() switch
				{
					0 => "Don't you care about Grubs? :(", 
					1 => "You left your Grub alone T.T", 
					_ => "You left your Grubs alone T.T", 
				};
			}
			return GetTextPrefix(statSource) + 0;
		}

		public override string GetTextPrefix(StatSource statSource)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)statSource != 2)
			{
				return "Total Grubs Adopted: ";
			}
			return "Grubs Adopted: ";
		}

		public override bool ShouldAddToScoreScreenSession(bool win)
		{
			if (ShouldAddToGamemode(CL_GameManager.gamemode))
			{
				return StatUtils.HasPickedUpItem("SlugGrub");
			}
			return false;
		}

		public override bool ShouldAddToScoreScreenGamemode(bool win)
		{
			if (ShouldAddToGamemode(CL_GameManager.gamemode))
			{
				return StatUtils.HasPickedUpItem("SlugGrub");
			}
			return false;
		}

		public override bool ShouldAddToGamemode(M_Gamemode gamemode)
		{
			if (!((Object)gamemode).name.Equals("GM_Campaign"))
			{
				return ((Object)gamemode).name.Equals("GM_Playground");
			}
			return true;
		}

		public override bool ShouldAddToLogbook()
		{
			return true;
		}

		public override int GetScoreScreenSessionIndex()
		{
			return 7;
		}

		public override int GetScoreScreenGamemodeIndex()
		{
			return 7;
		}

		public override int GetGamemodeIndex()
		{
			return 14;
		}

		public override int GetLogbookIndex()
		{
			return 13;
		}
	}
	public static class GrubStats
	{
		public const string ID_GRUB_SCORE = "grub-score";

		public static float winScoreMultiplier = 5f;

		public static void UpdateGrubScore()
		{
			if (CL_GameManager.gMan.GetGameTime() != 0f)
			{
				float playerBestTravelDistance = CL_GameManager.gMan.GetPlayerBestTravelDistance();
				int rescuedGrubsCount = GetRescuedGrubsCount();
				float num = CL_GameManager.gMan.GetGameTime() / 60f;
				float num2 = (float)rescuedGrubsCount / num;
				float num3 = playerBestTravelDistance * num2;
				if (CustomStatManager.Win)
				{
					num3 *= winScoreMultiplier;
				}
				num3 = (float)Math.Round(num3, 2, MidpointRounding.AwayFromZero);
				Log.Info($"Grub Score: {num3}");
				Log.Info($" = {num2} (#Grubs/Minute that made it out) * {(int)playerBestTravelDistance} Meters (Distance)" + (CustomStatManager.Win ? " * 5 (Because you escaped)" : ""));
				StatManager.sessionStats.UpdateStatistic("grub-score", (object)num3, (DataType)2, (ModType)0, (DisplayType)0, (ModType)2);
				string text = StatUtils.GetStat("grub-score", StatUtils.StatSource.gamemode)?.value.ToString();
				Log.Info("Previous Best: " + (text ?? "N/A"));
			}
		}

		public static int GetRescuedGrubsCount()
		{
			int num = GrubRescueStation.GetGrubsStored();
			if (CustomStatManager.Win)
			{
				num += InventoryUtils.TotalItemCount("SlugGrub");
			}
			return num;
		}
	}
	public class MaxGrubsAdopted : CustomStat
	{
		public MaxGrubsAdopted()
			: base("max-grubs-adopted", 0, (DataType)0, (ModType)2, (DisplayType)0, (ModType)2)
		{
		}

		protected override bool CalculateValueOnEndGame(bool win)
		{
			if (!win)
			{
				return false;
			}
			if (GrubStats.GetRescuedGrubsCount() == 0)
			{
				return false;
			}
			value = GrubStats.GetRescuedGrubsCount();
			return true;
		}

		public override string GetDefaultText(StatSource statSource)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!StatUtils.HasPickedUpItem("SlugGrub"))
			{
				return "[REDACTED]";
			}
			return GetTextPrefix(statSource) + 0;
		}

		public override string GetTextPrefix(StatSource statSource)
		{
			return "Most Adopted in a Run: ";
		}

		public override bool ShouldAddToScoreScreenSession(bool win)
		{
			return false;
		}

		public override bool ShouldAddToScoreScreenGamemode(bool win)
		{
			if (ShouldAddToGamemode(CL_GameManager.gamemode))
			{
				return StatUtils.HasPickedUpItem("SlugGrub");
			}
			return false;
		}

		public override bool ShouldAddToGamemode(M_Gamemode gamemode)
		{
			if (!((Object)gamemode).name.Equals("GM_Campaign"))
			{
				return ((Object)gamemode).name.Equals("GM_Playground");
			}
			return true;
		}

		public override bool ShouldAddToLogbook()
		{
			return true;
		}

		public override int GetScoreScreenGamemodeIndex()
		{
			return 8;
		}

		public override int GetGamemodeIndex()
		{
			return 15;
		}

		public override int GetLogbookIndex()
		{
			return 14;
		}
	}
	public class StatRequirement : CustomScript
	{
		public enum OverrideMode
		{
			replace,
			and,
			or
		}

		public string id;

		public int fromInt = int.MinValue;

		public int toInt = int.MaxValue;

		public string matchString;

		public float fromFloat = float.NegativeInfinity;

		public float toFloat = float.PositiveInfinity;

		public StatUtils.StatSource source;

		public OverrideMode overrideMode;

		public bool metWhenUndefined;

		private void Start()
		{
			GameObject gameObject = ((Component)this).gameObject;
			gameObject.SetActive(overrideMode switch
			{
				OverrideMode.replace => IsMet(), 
				OverrideMode.and => ((Component)this).gameObject.activeInHierarchy && IsMet(), 
				OverrideMode.or => ((Component)this).gameObject.activeInHierarchy || IsMet(), 
				_ => ((Component)this).gameObject.activeInHierarchy, 
			});
		}

		private bool IsMet()
		{
			//IL_0024: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected I4, but got Unknown
			Statistic stat = StatUtils.GetStat(id, source);
			if (stat == null)
			{
				return metWhenUndefined;
			}
			object value = stat.GetValue();
			DataType type = stat.type;
			return (int)type switch
			{
				0 => fromInt <= (int)value && (int)value <= toInt, 
				1 => (string)value == matchString, 
				2 => fromFloat <= (float)value && (float)value <= toFloat, 
				_ => false, 
			};
		}
	}
}
namespace GrubAdoption.Rescuing
{
	public class GrubDispenser : CustomScript, Clickable
	{
		[CompilerGenerated]
		private sealed class <<Interact>g__PlaySound|3_0>d : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public GrubDispenser <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <<Interact>g__PlaySound|3_0>d(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				GrubDispenser grubDispenser = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(Random.value * grubDispenser.delayRangeDispenseGrub);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					grubDispenser.clipHandler.PlaySound("grub-dispensing:dispense-grub");
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public float delayRangeDispenseGrub = 0.8f;

		private UT_AudioClipHandler clipHandler;

		private void Start()
		{
			clipHandler = ((Component)this).GetComponent<UT_AudioClipHandler>();
		}

		public void Interact(ENT_Player p, string s)
		{
			clipHandler.PlaySound("grub-dispensing:boop");
			int grubsStored = GrubRescueStation.GetGrubsStored();
			Log.Info($"Dispensing grubs: {grubsStored}");
			if (grubsStored != 0)
			{
				Item item = AssetUtils.GetItem("Denizen_SlugGrub");
				for (int i = 0; i < grubsStored; i++)
				{
					InventoryUtils.LoadItemIntoBag(item);
					((MonoBehaviour)this).StartCoroutine(PlaySound());
				}
				GrubRescueStation.ResetGrubsStored();
			}
			[IteratorStateMachine(typeof(<<Interact>g__PlaySound|3_0>d))]
			IEnumerator PlaySound()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <<Interact>g__PlaySound|3_0>d(0)
				{
					<>4__this = this
				};
			}
		}

		public bool CanInteract(ENT_Player p, Hand hand)
		{
			return true;
		}

		public ObjectTagger GetTagger()
		{
			return ((Component)this).gameObject.GetComponent<ObjectTagger>();
		}

		public GameObject GetGameObject()
		{
			return ((Component)this).gameObject;
		}
	}
	public class GrubRescueStation : CustomScript
	{
		[CompilerGenerated]
		private sealed class <<InsertGrub>g__PlaySounds|5_0>d : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public GrubRescueStation <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <<InsertGrub>g__PlaySounds|5_0>d(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0087: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Expected O, but got Unknown
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Expected O, but got Unknown
				int num = <>1__state;
				GrubRescueStation grubRescueStation = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (grubRescueStation.clipHandler.GetGroup("grub-rescuing").GetSet("exit-inventory").aud.isPlaying)
					{
						<>2__current = (object)new WaitForSeconds(grubRescueStation.delayRangeExitInventory);
						<>1__state = 1;
						return true;
					}
					goto IL_0070;
				case 1:
					<>1__state = -1;
					goto IL_0070;
				case 2:
					{
						<>1__state = -1;
						grubRescueStation.clipHandler.PlaySound("grub-rescuing:enter-station");
						return false;
					}
					IL_0070:
					grubRescueStation.clipHandler.PlaySound("grub-rescuing:exit-inventory");
					<>2__current = (object)new WaitForSeconds(grubRescueStation.delayEnterStation);
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string FLAG_GRUBS_STORED = "grubs-stored";

		public float delayRangeExitInventory = 0.1f;

		public float delayEnterStation = 0.15f;

		private UT_AudioClipHandler clipHandler;

		private void Start()
		{
			clipHandler = ((Component)this).GetComponent<UT_AudioClipHandler>();
		}

		public void InsertGrub()
		{
			((MonoBehaviour)this).StartCoroutine(PlaySounds());
			SetGrubsStored(GetGrubsStored() + 1);
			Log.Info($"Grub inserted (stored: {GetGrubsStored()})");
			[IteratorStateMachine(typeof(<<InsertGrub>g__PlaySounds|5_0>d))]
			IEnumerator PlaySounds()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <<InsertGrub>g__PlaySounds|5_0>d(0)
				{
					<>4__this = this
				};
			}
		}

		public static int GetGrubsStored()
		{
			SessionFlag gameFlag = CL_GameManager.GetGameFlag("grubs-stored");
			if (gameFlag == null || gameFlag.data == null)
			{
				return 0;
			}
			return int.Parse(gameFlag.data);
		}

		public static void ResetGrubsStored()
		{
			SetGrubsStored(0);
		}

		private static void SetGrubsStored(int amount)
		{
			CL_GameManager.SetGameFlag("grubs-stored", true, amount.ToString(), false, false);
		}
	}
	public class GrubSlot : CustomScript, Clickable
	{
		private const string INTERACTOR_TAG = "GrubSlot";

		private GrubRescueStation rescueStation;

		private void Start()
		{
			rescueStation = ((Component)this).GetComponentInParent<GrubRescueStation>();
			if ((int)StatUtils.GetValueOrDefault("grubs-adopted", 0, StatUtils.StatSource.global) <= 0)
			{
				GetTagger().tags.Remove("GrubSlot");
			}
		}

		public void Interact(ENT_Player p, string s = "")
		{
			rescueStation.InsertGrub();
		}

		public bool CanInteract(ENT_Player p, Hand hand)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)hand.interactState == 5)
			{
				return hand.inventoryHand.currentItem.itemName == "SlugGrub";
			}
			return false;
		}

		public ObjectTagger GetTagger()
		{
			return ((Component)this).gameObject.GetComponent<ObjectTagger>();
		}

		public GameObject GetGameObject()
		{
			return ((Component)this).gameObject;
		}
	}
	[HarmonyPatch]
	public static class GrubUsagePrevention
	{
		private static readonly Dictionary<int, Clickable> interactorClickables = new Dictionary<int, Clickable>
		{
			{ 0, null },
			{ 1, null }
		};

		[HarmonyPatch(typeof(HandItem_Buff), "Use")]
		[HarmonyPrefix]
		public static bool PreventGrubUse(HandItem_Buff __instance)
		{
			Clickable interactorClickable = GetInteractorClickable(((Hand_Base)__instance).hand.id);
			if (((HandItem)__instance).item.itemName == "SlugGrub" && (interactorClickable is GrubSlot || interactorClickable is GrubDispenser))
			{
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(Item_Interactor_Insertable), "Interact")]
		[HarmonyPostfix]
		public static void SetInteractorClickables(Hand curhand, Clickable clickable)
		{
			interactorClickables[curhand.id] = clickable;
		}

		[HarmonyPatch(typeof(Inventory), "Update")]
		[HarmonyPostfix]
		public static void ResetInteractorClickables()
		{
			interactorClickables[0] = null;
			interactorClickables[1] = null;
		}

		public static Clickable GetInteractorClickable(int handId)
		{
			if (!interactorClickables.ContainsKey(handId))
			{
				return null;
			}
			return interactorClickables[handId];
		}
	}
}
namespace GrubAdoption.Assets
{
	public class CustomScript : MonoBehaviour
	{
		private const char KEY_VALUE_SEPARATOR = ':';

		public void Initialize(UT_Null initializer)
		{
			Dictionary<string, string> dictionary = ParseData(initializer);
			Log.Info("Initializing " + initializer.id + " at " + ((Object)((Component)initializer).gameObject).name);
			foreach (string key in dictionary.Keys)
			{
				FieldInfo field = ((object)this).GetType().GetField(key);
				if (field == null)
				{
					CustomScriptManager.Error(initializer, "No public field \"" + key + "\" found in script");
					break;
				}
				object obj = ChangeType(dictionary[key], field.FieldType);
				if (obj == null)
				{
					CustomScriptManager.Error(initializer, $"Couldn't parse {dictionary[key]} to type {field.GetType()}");
				}
				field.SetValue(this, obj);
			}
		}

		private static Dictionary<string, string> ParseData(UT_Null initializer)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string datum in initializer.data)
			{
				string[] array = datum.Split(':');
				if (array.Length != 2)
				{
					CustomScriptManager.Error(initializer, "\"" + datum + "\" is not a valid key-value pair");
				}
				else
				{
					dictionary.Add(array[0], array[1]);
				}
			}
			return dictionary;
		}

		private static object ChangeType(string value, Type type)
		{
			if (type.IsEnum)
			{
				return Enum.Parse(type, value, ignoreCase: true);
			}
			return Convert.ChangeType(value, type);
		}
	}
	public class CustomScriptManager
	{
		private const char MOD_ID_SCRIPT_NAME_SEPARATOR = ':';

		private static MethodInfo addComponentGeneric;

		private readonly Dictionary<string, Type> scriptTypes = new Dictionary<string, Type>();

		public static CustomScriptManager Instance { get; private set; }

		private static void Initialize()
		{
			Instance = new CustomScriptManager();
			addComponentGeneric = typeof(GameObject).GetMethod("AddComponent", Array.Empty<Type>());
			UT_Null._OnAwake = (Action<UT_Null>)Delegate.Combine(UT_Null._OnAwake, new Action<UT_Null>(Instance.ReplaceInitializer));
		}

		public static void RegisterAssembly(Assembly assembly, ModContext modContext)
		{
			if (Instance == null)
			{
				Initialize();
			}
			IEnumerable<Type> enumerable = from type in assembly.GetTypes()
				where type.IsSubclassOf(typeof(CustomScript))
				select type;
			Log.Info($"In assembly {assembly.GetName().Name}: Found {enumerable.Count()} CustomScript type(s)");
			foreach (Type item in enumerable)
			{
				RegisterScriptType(item, modContext);
			}
		}

		public static void RegisterScriptType(Type scriptType, ModContext modContext)
		{
			if (Instance == null)
			{
				Initialize();
			}
			Instance.scriptTypes.Add(modContext.ModID + ":" + scriptType.Name, scriptType);
		}

		private void ReplaceInitializer(UT_Null initializer)
		{
			GameObject gameObject = ((Component)initializer).gameObject;
			if (!scriptTypes.ContainsKey(initializer.id))
			{
				if (!initializer.id.Contains(':'))
				{
					Error(initializer, $"id must be of the form \"<mod context id>{':'}<CustomScript name>\"");
				}
				else
				{
					Error(initializer, "Unknown CustomScript name. Did you register your assembly in the CustomScriptManager?");
				}
				return;
			}
			Type type = scriptTypes[initializer.id];
			CustomScript obj = (CustomScript)addComponentGeneric.MakeGenericMethod(type).Invoke(gameObject, Array.Empty<object>());
			if ((Object)(object)obj == (Object)null)
			{
				Error(initializer, "AddComponent failed");
			}
			obj.Initialize(initializer);
			Object.Destroy((Object)(object)initializer);
		}

		public static void Error(UT_Null initializer, string msg)
		{
			Log.Error("Error while parsing UT_Null script \"" + initializer.id + "\" for " + ((Object)((Component)initializer).gameObject).name + ": " + msg);
		}
	}
	[HarmonyPatch]
	public static class GrubAdoptionAssets
	{
		private static readonly string ASSET_BUNDLE_FILE = Path.Combine("..", "anonymousfroggo-GrubAdoption", "grub-adoption.assets");

		private static AssetService assetService;

		private static AssetBundle assetBundle;

		public static GameObject LevelModifications_Campaign { get; private set; }

		public static Item_Interactor_Insertable Interactor_Grub { get; private set; }

		public static GameObject LevelModifications_Debug { get; private set; }

		public static async Task Initialize()
		{
			if (assetService == null)
			{
				assetService = new AssetService(Plugin.Instance.ModContext);
				assetBundle = await assetService.LoadBundleRelativeAsync(ASSET_BUNDLE_FILE, (IProgress<float>)null);
				InitializeLevelModifications();
				InitializeGrubInteractor();
			}
		}

		private static void InitializeLevelModifications()
		{
			LevelModificationLoader levelModificationLoader = new LevelModificationLoader(Plugin.Instance.ModContext, (M_Gamemode gamemode) => ((Object)gamemode).name == "GM_Campaign" && !gamemode.IsIronKnuckle());
			LevelModifications_Campaign = assetBundle.LoadAsset<GameObject>("LevelModifications_Campaign");
			levelModificationLoader.RegisterModificationsFromChildren(LevelModifications_Campaign);
		}

		private static void InitializeGrubInteractor()
		{
			Interactor_Grub = assetBundle.LoadAsset<Item_Interactor_Insertable>("Interactor_Grub");
		}

		[HarmonyPatch(typeof(Item), "InitializeInHand")]
		[HarmonyPostfix]
		public static void TrySetInteractor(Item __instance, ref Item_Interactor ___interactor)
		{
			//IL_0013: 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)
			if (!(__instance.itemName != "SlugGrub") && (int)__instance.interactType == 0)
			{
				___interactor = (Item_Interactor)(object)Object.Instantiate<Item_Interactor_Insertable>(Interactor_Grub);
				__instance.interactType = (InteractType)2;
				Log.Info("Set interactor to " + ((Object)Interactor_Grub).name);
			}
		}
	}
	public class LevelModification
	{
		private const string ASSET_PREFIX = "LM_";

		private readonly GameObject asset;

		private readonly LevelModificationLoader loader;

		public string Level { get; }

		public LevelModification(GameObject asset, LevelModificationLoader loader)
		{
			this.asset = asset;
			this.loader = loader;
			string name = ((Object)asset).name;
			if (!name.StartsWith("LM_"))
			{
				Log.Error("Error while loading LevelModification " + name + ": Name must match pattern LM_<level name>");
				return;
			}
			string text = name;
			int length = "LM_".Length;
			Level = text.Substring(length, text.Length - length);
		}

		public void InjectInto(GameObject levelObject)
		{
			Log.Info("Injecting a LevelModification into " + Level);
			InjectRecursive(asset.transform, levelObject.transform);
		}

		private void InjectRecursive(Transform assetNode, Transform levelObjectNode)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			foreach (Transform item in assetNode)
			{
				Transform val = item;
				Transform val2 = levelObjectNode.Find(((Object)val).name);
				if ((Object)(object)val2 != (Object)null)
				{
					InjectRecursive(val, val2);
					continue;
				}
				Log.Info("Injecting " + ((Object)val).name + " at " + ((Object)levelObjectNode).name);
				((Object)Object.Instantiate<Transform>(val, levelObjectNode)).name = loader.GetScopedName(((Object)val).name);
			}
		}
	}
	[HarmonyPatch]
	public class LevelModificationLoader
	{
		private static readonly List<LevelModificationLoader> loaders = new List<LevelModificationLoader>();

		private readonly ModContext modContext;

		private readonly Func<M_Gamemode, bool> LoadInGamemode;

		private readonly Dictionary<string, LevelModification> modificationsDict = new Dictionary<string, LevelModification>();

		public LevelModificationLoader(ModContext modContext, Func<M_Gamemode, bool> LoadInGamemode = null)
		{
			this.modContext = modContext;
			this.LoadInGamemode = LoadInGamemode ?? ((Func<M_Gamemode, bool>)((M_Gamemode _) => true));
			loaders.Add(this);
		}

		public void RegisterModification(GameObject modificationAsset)
		{
			LevelModification levelModification = new LevelModification(modificationAsset, this);
			modificationsDict.Add(levelModification.Level, levelModification);
			Log.Info("Registered LevelModification for " + levelModification.Level);
		}

		public void RegisterModificationsFromChildren(GameObject parent)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			foreach (Transform item in parent.transform)
			{
				Transform val = item;
				RegisterModification(((Component)val).gameObject);
			}
		}

		public string GetScopedName(string name)
		{
			return name + "(" + modContext.ModID + ")";
		}

		[HarmonyPatch(typeof(M_Level), "Awake")]
		[HarmonyPostfix]
		public static void InjectLevelModifications(M_Level __instance)
		{
			foreach (LevelModificationLoader item in loaders.Where((LevelModificationLoader loader) => loader.LoadInGamemode(CL_GameManager.gamemode) && loader.modificationsDict.ContainsKey(__instance.levelName)))
			{
				item.modificationsDict[__instance.levelName].InjectInto(((Component)__instance).gameObject);
			}
		}
	}
}