Decompiled source of MVP Tracker v2.0.0

MVP_Tracker.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
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 MVP_Tracker;
using MelonLoader;
using Microsoft.CodeAnalysis;
using ScheduleOne.DevUtilities;
using ScheduleOne.Economy;
using ScheduleOne.ItemFramework;
using ScheduleOne.Map;
using ScheduleOne.NPCs;
using ScheduleOne.Persistence;
using ScheduleOne.Persistence.Datas;
using ScheduleOne.PlayerScripts;
using ScheduleOne.Product;
using ScheduleOne.Quests;
using ScheduleOne.UI.Compass;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "MVP Tracker", "2.0.0", "Stehlel", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MVP_Tracker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+d99c5979ca98e3809bb6c05bd855a2ca8d0fc37a")]
[assembly: AssemblyProduct("MVP_Tracker")]
[assembly: AssemblyTitle("MVP_Tracker")]
[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 MVP_Tracker
{
	public class Core : MelonMod
	{
		[CompilerGenerated]
		private sealed class <CooldownTicker>d__12 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Core <>4__this;

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

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

			[DebuggerHidden]
			public <CooldownTicker>d__12(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

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

			private bool MoveNext()
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				int num = <>1__state;
				Core core = <>4__this;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					core.Update();
				}
				else
				{
					<>1__state = -1;
				}
				<>2__current = (object)new WaitForSecondsRealtime(1f);
				<>1__state = 1;
				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();
			}
		}

		[CompilerGenerated]
		private sealed class <InitializeNextFrame>d__11 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Core <>4__this;

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

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

			[DebuggerHidden]
			public <InitializeNextFrame>d__11(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

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

			private bool MoveNext()
			{
				int num = <>1__state;
				Core core = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					core.quest = QuestManaging.CreateQuest("MVP Tracker");
					core.quest.ClearEntries();
					try
					{
						core.quest.InitializeQuest("MVP Tracker", "Helps you keep track of the richest customers", Array.Empty<QuestEntryData>(), QuestManaging.guid);
						SaveManager instance = Singleton<SaveManager>.Instance;
						instance.Saveables.Remove((ISaveable)(object)core.quest);
						Quest quest = core.quest;
						IBaseSaveable val = (IBaseSaveable)(object)((quest is IBaseSaveable) ? quest : null);
						if (val != null)
						{
							instance.BaseSaveables.Remove(val);
						}
					}
					catch (Exception ex)
					{
						MelonLogger.Error((object)ex);
						return false;
					}
					core.quest.Begin(true);
					Customer.onCustomerUnlocked = (Action<Customer>)Delegate.Combine(Customer.onCustomerUnlocked, new Action<Customer>(core.HandleCustomerUnlocked));
					foreach (Customer unlockedCustomer in Customer.UnlockedCustomers)
					{
						core.HandleCustomerUnlocked(unlockedCustomer);
					}
					MelonCoroutines.Start(core.CooldownTicker());
					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();
			}
		}

		private static readonly HashSet<string> RelevantFirstNames = new HashSet<string>
		{
			"Fiona", "Herbert", "Jen", "Lily", "Michael", "Pearl", "Ray", "Tobias", "Walter", "Jessi",
			"Carl", "Dean", "George", "Geraldine", "Alison", "Dennis", "Hank", "Harold", "Jack", "Jackie",
			"Jeremy", "Karen", "Chris"
		};

		private List<QuestEntry> questEntries = new List<QuestEntry>();

		private HashSet<string> entries = new HashSet<string>();

		private HashSet<string> onCd = new HashSet<string>();

		private readonly Dictionary<string, NPCPoI> pois = new Dictionary<string, NPCPoI>();

		private readonly Dictionary<string, Element> compassEls = new Dictionary<string, Element>();

		public Quest quest;

		private const int CooldownSeconds = 360;

		public override void OnInitializeMelon()
		{
			MelonLogger.Msg("MVP Tracker loaded");
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			SaveManager instance = Singleton<SaveManager>.Instance;
			instance.onSaveStart.AddListener(new UnityAction(OnBeforeSave));
			instance.onSaveComplete.AddListener(new UnityAction(OnAfterSave));
			Customer.onCustomerUnlocked = (Action<Customer>)Delegate.Remove(Customer.onCustomerUnlocked, new Action<Customer>(HandleCustomerUnlocked));
			if (!((Scene)(ref scene)).name.Equals("Main", StringComparison.OrdinalIgnoreCase))
			{
				MelonCoroutines.Stop((object)CooldownTicker());
				quest.ClearEntries();
				if ((Object)(object)quest != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)quest).gameObject);
				}
				quest = null;
				Customer.onCustomerUnlocked = (Action<Customer>)Delegate.Remove(Customer.onCustomerUnlocked, new Action<Customer>(HandleCustomerUnlocked));
				return;
			}
			entries.Clear();
			onCd.Clear();
			pois.Clear();
			compassEls.Clear();
			questEntries.Clear();
			QuestManaging.guid = null;
			if ((Object)(object)Player.Local != (Object)null)
			{
				MelonCoroutines.Start(InitializeNextFrame());
				return;
			}
			Player.onLocalPlayerSpawned = (Action)Delegate.Combine(Player.onLocalPlayerSpawned, (Action)delegate
			{
				MelonCoroutines.Start(InitializeNextFrame());
			});
		}

		private void OnBeforeSave()
		{
			Singleton<SaveManager>.Instance.Saveables.Remove((ISaveable)(object)quest);
			if (!((Object)(object)quest == (Object)null))
			{
				Quest.Quests.Remove(quest);
				Debug.Log((object)"[MVP Tracker] Dynamic quest suppressed from save");
			}
		}

		private void OnAfterSave()
		{
			if (!((Object)(object)quest == (Object)null))
			{
				if (!Quest.Quests.Contains(quest))
				{
					Quest.Quests.Add(quest);
				}
				Debug.Log((object)"[MVP Tracker] Dynamic quest restored after save");
			}
		}

		[IteratorStateMachine(typeof(<InitializeNextFrame>d__11))]
		private IEnumerator InitializeNextFrame()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitializeNextFrame>d__11(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<CooldownTicker>d__12))]
		private IEnumerator CooldownTicker()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CooldownTicker>d__12(0)
			{
				<>4__this = this
			};
		}

		private void HandleCustomerUnlocked(Customer cust)
		{
			if (!((Object)(object)((cust != null) ? cust.NPC : null) == (Object)null) && RelevantFirstNames.Contains(cust.NPC.FirstName))
			{
				Create(cust);
			}
		}

		internal void Create(Customer cust)
		{
			string iD = cust.NPC.ID;
			if (!entries.Contains(iD))
			{
				createPOICompass(cust);
				entries.Add(iD);
				QuestEntry item = quest.AddEntry(cust.NPC.FirstName);
				questEntries.Add(item);
			}
		}

		internal void Update()
		{
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			foreach (string entry in entries)
			{
				string id = entry.ToString();
				Customer val = Customer.UnlockedCustomers.Find((Customer c) => c.NPC.ID == id);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				bool flag = (Object)(object)val.AssignedDealer != (Object)null;
				float num = val.TimeSinceInstantDealOffered;
				bool flag2 = num < 360f;
				bool flag3 = onCd.Contains(id);
				if (!pois.ContainsKey(id))
				{
					continue;
				}
				NPCPoI val2 = pois[id];
				Element val3 = compassEls[id];
				foreach (QuestEntry questEntry in questEntries)
				{
					if (!questEntry.Title.Contains(val.NPC.FirstName))
					{
						continue;
					}
					if (!flag)
					{
						if (flag2)
						{
							int num2 = 360 - (int)num;
							questEntry.SetActive(true);
							questEntry.SetEntryTitle($"<color=orange>{val.NPC.FirstName}: {num2 / 60}h {num2 % 60}m</color>");
							((Component)val2).gameObject.SetActive(false);
							val3.Visible = false;
							if (!flag3)
							{
								onCd.Add(id);
							}
							continue;
						}
						int num3 = calculateChance(val);
						(ProductDefinition, float, float, int) optimalProductAndPrice = GetOptimalProductAndPrice(val);
						float num4 = calculateDailyBudget(val);
						questEntry.SetActive(true);
						questEntry.SetEntryTitle($"<color=green>{val.NPC.FirstName} ({num3}%): Budget: {num4}$, {optimalProductAndPrice.Item4}x{((ItemDefinition)optimalProductAndPrice.Item1).Name} ({optimalProductAndPrice.Item2}$ ,{optimalProductAndPrice.Item3}%)</color>");
						((Component)val2).transform.position = ((Component)val.NPC).transform.position;
						((POI)val2).SetMainText(val.NPC.FirstName);
						((Component)val2).gameObject.SetActive(true);
						val3.Visible = true;
						if (flag3)
						{
							onCd.Remove(id);
						}
					}
					else
					{
						questEntry.SetActive(true);
						questEntry.SetEntryTitle("<color=red>" + val.NPC.FirstName + " Warning: Dealer assigned! " + ((Object)val.AssignedDealer).name + "</color> ");
						((Component)val2).gameObject.SetActive(false);
						val3.Visible = false;
					}
				}
			}
		}

		public (ProductDefinition product, float optimalPrice, float acceptanceProbability, int optimalQuantity) GetOptimalProductAndPrice(Customer cust, int priceStep = 5)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			int count = cust.CustomerData.GetOrderDays(cust.CurrentAddiction, cust.NPC.RelationData.RelationDelta / 5f).Count;
			count = Mathf.Max(count, 1);
			float num = cust.CustomerData.GetAdjustedWeeklySpend(cust.NPC.RelationData.RelationDelta / 5f) / (float)count;
			EQuality correspondingQuality = StandardsMethod.GetCorrespondingQuality(cust.CustomerData.Standards);
			ProductDefinition val = null;
			float num2 = 0f;
			float num3 = 0f;
			float num4 = 0f;
			List<ProductDefinition> allProducts = NetworkSingleton<ProductManager>.Instance.AllProducts;
			if (allProducts == null || allProducts.Count == 0)
			{
				return (null, 0f, 0f, 0);
			}
			foreach (ProductDefinition item2 in allProducts)
			{
				ItemInstance defaultInstance = ((ItemDefinition)item2).GetDefaultInstance(1);
				ProductItemInstance val2 = (ProductItemInstance)(object)((defaultInstance is ProductItemInstance) ? defaultInstance : null);
				if (val2 != null)
				{
					((QualityItemInstance)val2).Quality = correspondingQuality;
					if (item2.ValidPackaging != null && item2.ValidPackaging.Length != 0)
					{
						val2.SetPackaging(item2.ValidPackaging[1]);
					}
				}
				List<ItemInstance> list = new List<ItemInstance> { defaultInstance };
				float num5 = Mathf.Max(item2.Price, (float)priceStep);
				float num6 = Mathf.Floor(num * 3f / (float)priceStep) * (float)priceStep;
				num6 = Mathf.Max(num5, num6);
				for (float num7 = num5; num7 <= num6; num7 += (float)priceStep)
				{
					float offerSuccessChance = cust.GetOfferSuccessChance(list, num7);
					float num8 = num7 * offerSuccessChance;
					if (num8 > num3)
					{
						num3 = num8;
						num2 = num7;
						val = item2;
						num4 = offerSuccessChance;
					}
				}
			}
			int item = 1;
			if ((Object)(object)val != (Object)null && num2 > 0f)
			{
				float productEnjoyment = cust.GetProductEnjoyment(val, correspondingQuality);
				float num9 = Mathf.Lerp(0.66f, 1.5f, productEnjoyment);
				int num10 = Mathf.RoundToInt(num * num9 / val.Price);
				num10 = Mathf.Clamp(num10, 1, 1000);
				if (num10 >= 14)
				{
					num10 = Mathf.RoundToInt((float)num10 / 5f) * 5;
				}
				item = num10;
				_ = num2 / (float)num10;
			}
			num4 = Mathf.RoundToInt(num4 * 100f);
			num2 = Mathf.RoundToInt(num2);
			return (val, num2, num4, item);
		}

		internal int calculateChance(Customer cust)
		{
			double num = (double)Mathf.Clamp01((float)cust.TimeSinceLastDealCompleted / 1440f) * 0.5;
			float num2 = cust.NPC.RelationData.NormalizedRelationDelta * 0.3f;
			float num3 = cust.CurrentAddiction * 0.2f;
			return Mathf.RoundToInt(((float)(num + (double)num2) + num3) * 100f);
		}

		internal float calculateDailyBudget(Customer cust)
		{
			float adjustedWeeklySpend = cust.CustomerData.GetAdjustedWeeklySpend(cust.NPC.RelationData.RelationDelta / 5f);
			int count = cust.CustomerData.GetOrderDays(cust.CurrentAddiction, cust.NPC.RelationData.RelationDelta / 5f).Count;
			return MathF.Round(adjustedWeeklySpend / (float)count);
		}

		internal ProductDefinition bestProduct(Customer cust)
		{
			//IL_0019: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			EQuality q = StandardsMethod.GetCorrespondingQuality(cust.CustomerData.Standards);
			return (from def in cust.OrderableProducts
				select new
				{
					def = def,
					Appeal = cust.GetProductEnjoyment(def, q) + Mathf.Lerp(1f, -1f, def.Price / def.MarketValue / 2f)
				} into x
				orderby x.Appeal descending
				select x).First().def;
		}

		internal void createPOICompass(Customer cust)
		{
			NPCPoI val = Object.Instantiate<NPCPoI>(NetworkSingleton<NPCManager>.Instance.PotentialCustomerPoIPrefab, ((Component)cust.NPC).transform);
			val.SetNPC(cust.NPC);
			((POI)val).SetMainText(cust.NPC.FirstName);
			pois[cust.NPC.ID] = val;
			Element value = Singleton<CompassManager>.Instance.AddElement(((Component)val).transform, ((Component)((POI)val).UI).GetComponent<RectTransform>(), true);
			compassEls[cust.NPC.ID] = value;
		}
	}
	public static class QuestManaging
	{
		public static string guid;

		public static Quest CreateQuest(string title)
		{
			if (string.IsNullOrEmpty(guid))
			{
				guid = Guid.NewGuid().ToString();
			}
			return Object.Instantiate<GameObject>(((Component)NetworkSingleton<QuestManager>.Instance.DefaultQuests[0]).gameObject, NetworkSingleton<QuestManager>.Instance.QuestContainer).GetComponent<Quest>();
		}

		public static QuestEntry AddEntry(this Quest quest, string entryTitle)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//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)
			QuestEntryData data = new QuestEntryData(entryTitle, (EQuestState)0);
			GameObject val = new GameObject(entryTitle);
			val.transform.SetParent(((Component)quest).transform, false);
			QuestEntry val2 = val.AddComponent<QuestEntry>();
			quest.Entries.Add(val2);
			val2.SetData(data);
			return val2;
		}

		public static void ClearEntries(this Quest quest)
		{
			QuestEntry[] array = quest.Entries.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				Object.Destroy((Object)(object)((Component)array[i]).gameObject);
			}
			quest.Entries.Clear();
		}
	}
}