Decompiled source of ExpandRecipe v0.2.0

ExpandRecipe.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using ExpandRecipe;
using HarmonyLib;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.StationFramework;
using Il2CppScheduleOne.UI.Phone.ProductManagerApp;
using Il2CppScheduleOne.UI.Tooltips;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Main), "ExpandRecipe", "0.2.0", "Robb Manes", "https://github.com/robbmanes/Schedule1_ExpandRecipe")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ExpandRecipe")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a5df1431d5ba73febb258438632c9750b62963c2")]
[assembly: AssemblyProduct("ExpandRecipe")]
[assembly: AssemblyTitle("ExpandRecipe")]
[assembly: NeutralResourcesLanguage("en-US")]
[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 ExpandRecipe
{
	public class Main : MelonMod
	{
		public string testedVersion = "0.3.4f4";

		public static ProductManager productManager;

		public static ProductManagerApp productManagerApp;

		public override void OnInitializeMelon()
		{
			MelonLogger.Msg("Tested on Schedule I version \"" + testedVersion + "\"");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (sceneName == "Main")
			{
				try
				{
					productManager = Object.FindObjectsOfType<ProductManager>()[0];
				}
				catch (Exception value)
				{
					MelonLogger.Error($"Failed to find base Product Manager: {value}");
				}
			}
			((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName);
		}

		public static List<List<IngredientQuantity>> GetExpandedRecipes(ProductEntry productEntry)
		{
			List<StationRecipe> recipes = productEntry.Definition.Recipes;
			List<List<IngredientQuantity>> list = new List<List<IngredientQuantity>>();
			return GetExpandedRecipesInternal(recipes);
		}

		private static List<List<IngredientQuantity>> GetExpandedRecipesInternal(List<StationRecipe> baseRecipes)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Invalid comparison between Unknown and I4
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Expected O, but got Unknown
			List<List<IngredientQuantity>> list = new List<List<IngredientQuantity>>();
			if (baseRecipes.Count > 0)
			{
				Enumerator<StationRecipe> enumerator = baseRecipes.GetEnumerator();
				while (enumerator.MoveNext())
				{
					StationRecipe current = enumerator.Current;
					List<IngredientQuantity> list2 = new List<IngredientQuantity>();
					Enumerator<IngredientQuantity> enumerator2 = current.Ingredients.GetEnumerator();
					while (enumerator2.MoveNext())
					{
						IngredientQuantity current2 = enumerator2.Current;
						list2 = (((int)current2.Item.Category != 0) ? list2.Prepend(current2).ToList() : list2.Append(current2).ToList());
					}
					foreach (IngredientQuantity ingredient in list2)
					{
						bool flag = false;
						if ((int)ingredient.Item.Category == 0)
						{
							Func<ProductDefinition, bool> func = (ProductDefinition x) => ((ItemDefinition)x).ID == ingredient.Item.ID;
							ProductDefinition val = productManager.AllProducts.Find(Predicate<ProductDefinition>.op_Implicit(func)) ?? throw new Exception("Could not find base product for \"'" + ingredient.Item.Name + "'\"");
							if (val.Recipes.Count <= 0)
							{
								if (list.Count > 0 && list[list.Count - 1].Count > 0)
								{
									list[list.Count - 1] = list[list.Count - 1].Prepend(ingredient).ToList();
								}
								flag = true;
								break;
							}
							for (int i = 0; i < val.Recipes.Count; i++)
							{
								StationRecipe val2 = val.Recipes[i];
								Enumerator<IngredientQuantity> enumerator4 = val2.Ingredients.GetEnumerator();
								while (enumerator4.MoveNext())
								{
									IngredientQuantity current3 = enumerator4.Current;
									IngredientQuantity val3 = new IngredientQuantity();
									if (val2.Ingredients.Contains(ingredient))
									{
										val3 = current3;
										if (list.Count > 0 && list[list.Count - 1].Count > 0)
										{
											list[list.Count - 1] = list[list.Count - 1].Prepend(ingredient).ToList();
										}
										flag = true;
										break;
									}
								}
							}
							if (flag)
							{
								break;
							}
							List<List<IngredientQuantity>> expandedRecipesInternal = GetExpandedRecipesInternal(val.Recipes);
							foreach (List<IngredientQuantity> item in expandedRecipesInternal)
							{
								item.AddRange(list2);
								item.Remove(ingredient);
								list.Add(item);
							}
						}
						else
						{
							List<IngredientQuantity> list3 = new List<IngredientQuantity>();
							list3.Add(ingredient);
							list.Add(list3);
						}
					}
				}
			}
			foreach (List<IngredientQuantity> item2 in list.ToList())
			{
				foreach (List<IngredientQuantity> item3 in list.ToList())
				{
					if (item2 != item3 && !item3.Except(item2).Any() && item3.Except(item2).ToList().Count <= 0)
					{
						list.Remove(item3);
					}
				}
			}
			return list;
		}

		public static GameObject CreateExpandedRecipesTextUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject)
		{
			Transform val = parentGameObject.transform.Find("ExpandedRecipesText");
			GameObject gameObject;
			if ((Object)(object)val == (Object)null)
			{
				gameObject = Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
				((Object)gameObject).name = "ExpandedRecipesText";
				gameObject.GetComponent<Text>().text = "Expanded Recipe(s)";
			}
			else
			{
				gameObject = ((Component)val).gameObject;
			}
			gameObject.gameObject.SetActive(true);
			return gameObject;
		}

		public static GameObject GetOrCreateExpandedRecipesUIGameObject(GameObject parentGameObject)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			Transform val = parentGameObject.transform.Find("ExpandedRecipes");
			GameObject gameObject;
			if ((Object)(object)val == (Object)null)
			{
				gameObject = Object.Instantiate<GameObject>(new GameObject(), parentGameObject.transform).gameObject;
				((Object)gameObject).name = "ExpandedRecipes";
				VerticalLayoutGroup val2 = gameObject.gameObject.AddComponent<VerticalLayoutGroup>();
				((HorizontalOrVerticalLayoutGroup)val2).spacing = 8f;
				((HorizontalOrVerticalLayoutGroup)val2).childScaleHeight = false;
				((HorizontalOrVerticalLayoutGroup)val2).childScaleWidth = false;
				((HorizontalOrVerticalLayoutGroup)val2).childControlHeight = false;
				((HorizontalOrVerticalLayoutGroup)val2).childControlWidth = false;
				((HorizontalOrVerticalLayoutGroup)val2).childForceExpandHeight = false;
				((HorizontalOrVerticalLayoutGroup)val2).childForceExpandWidth = false;
			}
			else
			{
				gameObject = ((Component)val).gameObject;
				gameObject.DestroyChildren();
			}
			gameObject.gameObject.SetActive(true);
			return gameObject;
		}

		public static GameObject CreateExpandedRecipeUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject)
		{
			GameObject gameObject = Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
			gameObject.gameObject.SetActive(true);
			HorizontalLayoutGroup val = gameObject.gameObject.AddComponent<HorizontalLayoutGroup>();
			((LayoutGroup)val).childAlignment = (TextAnchor)4;
			((HorizontalOrVerticalLayoutGroup)val).childScaleHeight = false;
			((HorizontalOrVerticalLayoutGroup)val).childScaleWidth = false;
			((HorizontalOrVerticalLayoutGroup)val).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)val).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)val).childForceExpandWidth = false;
			gameObject.DestroyChildren();
			return gameObject;
		}

		public static GameObject CreateBaseProductUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject, List<IngredientQuantity> expandedRecipe)
		{
			IngredientQuantity val = expandedRecipe.First();
			GameObject gameObject = Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
			gameObject.GetComponent<Image>().sprite = val.Item.Icon;
			gameObject.GetComponent<Image>().preserveAspect = true;
			gameObject.GetComponent<Tooltip>().text = ((Object)val.Item).name;
			return gameObject;
		}

		public static GameObject CreatePlusUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject)
		{
			GameObject gameObject = Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
			gameObject.GetComponent<Image>().preserveAspect = true;
			return gameObject;
		}

		public static GameObject CreateMixUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject, IngredientQuantity ingredient)
		{
			GameObject gameObject = Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
			gameObject.GetComponent<Image>().sprite = ingredient.Item.Icon;
			gameObject.GetComponent<Image>().preserveAspect = true;
			gameObject.GetComponent<Tooltip>().text = ((Object)ingredient.Item).name;
			return gameObject;
		}

		public static GameObject CreateArrowUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject)
		{
			return Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
		}

		public static GameObject CreateOutputUIGameObject(GameObject gameObjectToClone, GameObject parentGameObject, ItemQuantity finalProduct)
		{
			GameObject gameObject = Object.Instantiate<GameObject>(gameObjectToClone, parentGameObject.transform).gameObject;
			gameObject.GetComponent<Image>().sprite = finalProduct.Item.Icon;
			gameObject.GetComponent<Image>().preserveAspect = true;
			gameObject.GetComponent<Tooltip>().text = ((Object)finalProduct.Item).name;
			return gameObject;
		}

		public static void BuildUIWithRecipe(ProductEntry productEntry, List<List<IngredientQuantity>> expandedRecipes, GameObject recipeTextUI, GameObject recipesContainerUI)
		{
			ItemQuantity product = productEntry.Definition.Recipes[0].Product;
			GameObject val = ((Component)recipesContainerUI.transform.Find("Recipe")).gameObject ?? throw new Exception("Unable to find recipeUI GameObject");
			GameObject gameObjectToClone = ((Component)val.transform.Find("Product")).gameObject ?? throw new Exception("Unable to find productUI GameObject");
			GameObject gameObjectToClone2 = ((Component)val.transform.Find("Plus")).gameObject ?? throw new Exception("Unable to find plusUI GameObject");
			GameObject gameObjectToClone3 = ((Component)val.transform.Find("Mixer")).gameObject ?? throw new Exception("Unable to find mixerUI GameObject");
			GameObject gameObjectToClone4 = ((Component)val.transform.Find("Arrow")).gameObject ?? throw new Exception("Unable to find arrowUI GameObject");
			GameObject gameObjectToClone5 = ((Component)val.transform.Find("Output")).gameObject ?? throw new Exception("Unable to find outputUI GameObject");
			CreateExpandedRecipesTextUIGameObject(recipeTextUI, recipesContainerUI);
			GameObject orCreateExpandedRecipesUIGameObject = GetOrCreateExpandedRecipesUIGameObject(recipesContainerUI);
			foreach (List<IngredientQuantity> expandedRecipe in expandedRecipes)
			{
				GameObject parentGameObject = CreateExpandedRecipeUIGameObject(val, orCreateExpandedRecipesUIGameObject);
				CreateBaseProductUIGameObject(gameObjectToClone, parentGameObject, expandedRecipe);
				expandedRecipe.Remove(expandedRecipe[0]);
				int num = expandedRecipe.Count;
				foreach (IngredientQuantity item in expandedRecipe)
				{
					if (num >= 0)
					{
						CreatePlusUIGameObject(gameObjectToClone2, parentGameObject);
					}
					CreateMixUIGameObject(gameObjectToClone3, parentGameObject, item);
					num--;
				}
				CreateArrowUIGameObject(gameObjectToClone4, parentGameObject);
				CreateOutputUIGameObject(gameObjectToClone5, parentGameObject, product);
			}
		}
	}
	public static class GameObjectExtensions
	{
		public static void DestroyChildren(this GameObject thisGameObject)
		{
			int childCount = thisGameObject.transform.GetChildCount();
			for (int num = childCount - 1; num >= 0; num--)
			{
				Transform child = thisGameObject.transform.GetChild(num);
				Object.Destroy((Object)(object)((Component)child).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(ProductManagerApp), "SelectProduct")]
	public static class ProductManager_SelectProduct_Patch
	{
		public static void Prefix(ProductManagerApp __instance, ProductEntry entry)
		{
			Main.productManagerApp = __instance;
			Transform val;
			Transform val2;
			try
			{
				ProductAppDetailPanel detailPanel = __instance.DetailPanel;
				val = ((Component)detailPanel).transform.Find("Scroll View/Viewport/Content/RecipesContainer");
				if ((Object)(object)val == (Object)null)
				{
					MelonLogger.Error("Can't find RecipesContainer object in current scene");
					return;
				}
				val2 = ((Component)detailPanel).transform.Find("Scroll View/Viewport/Content/Recipes");
				if ((Object)(object)val2 == (Object)null)
				{
					MelonLogger.Error("Can't find Recipes object in current scene");
					return;
				}
				Transform val3 = val.Find("ExpandedRecipes");
				if ((Object)(object)val3 != (Object)null)
				{
					((Component)val3).gameObject.SetActive(false);
				}
			}
			catch (Exception value)
			{
				MelonLogger.Error($"Failed to find Phone UI components: {value}");
				return;
			}
			List<List<IngredientQuantity>> expandedRecipes;
			try
			{
				expandedRecipes = Main.GetExpandedRecipes(entry);
				foreach (List<IngredientQuantity> item in expandedRecipes)
				{
					string name = ((ItemDefinition)entry.Definition).Name;
					string text = "";
					foreach (IngredientQuantity item2 in item)
					{
						if (text.Length > 0)
						{
							text += " + ";
						}
						text += ((Object)item2.Item).name;
					}
					MelonLogger.Msg("Expanded Recipe for \"" + name + "\": " + text);
				}
			}
			catch (Exception value2)
			{
				MelonLogger.Error($"Failed to get expanded recipe list: {value2}");
				return;
			}
			try
			{
				Main.BuildUIWithRecipe(entry, expandedRecipes, ((Component)val2).gameObject, ((Component)val).gameObject);
			}
			catch (Exception value3)
			{
				MelonLogger.Error($"Exception raised building UI component: {value3}");
			}
		}
	}
}