Decompiled source of BiggerStations v1.1.0

Mods/BiggerStations.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BiggerStations;
using Il2CppInterop.Runtime.InteropTypes;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "BiggerStations", "1.1.0", "LordValdomod", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BiggerStations")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("BiggerStations")]
[assembly: AssemblyTitle("BiggerStations")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BiggerStations
{
	public class Mod : MelonMod
	{
		private const int MaxAllowed = 9999;

		private const int IntervalMs = 10000;

		private static readonly (string type, string field)[] Targets = new(string, string)[2]
		{
			("Il2CppScheduleOne.ObjectScripts.DryingRack", "ItemCapacity"),
			("Il2CppScheduleOne.ObjectScripts.MixingStation", "MaxMixQuantity")
		};

		private MelonPreferences_Entry<int> limitEntry;

		private readonly Stopwatch clock = Stopwatch.StartNew();

		private readonly Dictionary<long, int> originals = new Dictionary<long, int>();

		private readonly HashSet<string> logged = new HashSet<string>();

		private List<(Type type, PropertyInfo prop, object il2cppType)> resolved;

		private MethodInfo findAll;

		private long nextScan = -1L;

		private bool inGame;

		public override void OnInitializeMelon()
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("BiggerStations", "Bigger Stations");
			limitEntry = val.CreateEntry<int>("StationLimit", 100, "Limite das estações", "Capacidade do varal de secagem e quantidade máxima das estações de mistura (2 a 9999).", false, false, (ValueValidator)null, (string)null);
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			inGame = sceneName == "Main";
			nextScan = clock.ElapsedMilliseconds + 3000;
		}

		public override void OnUpdate()
		{
			if (nextScan < 0 || clock.ElapsedMilliseconds < nextScan)
			{
				return;
			}
			nextScan = (inGame ? (clock.ElapsedMilliseconds + 10000) : (-1));
			try
			{
				Apply();
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Falha ao aplicar: " + ex);
				nextScan = -1L;
			}
		}

		private void Apply()
		{
			if (!Resolve())
			{
				nextScan = -1L;
				return;
			}
			int num = Math.Max(2, Math.Min(9999, limitEntry.Value));
			foreach (var (type, propertyInfo, obj) in resolved)
			{
				if (!(findAll.Invoke(null, new object[1] { obj }) is IEnumerable enumerable))
				{
					continue;
				}
				int num2 = 0;
				foreach (object item2 in enumerable)
				{
					Il2CppObjectBase val = (Il2CppObjectBase)((item2 is Il2CppObjectBase) ? item2 : null);
					if (val != null && !(val.Pointer == IntPtr.Zero))
					{
						object obj2;
						try
						{
							obj2 = Activator.CreateInstance(type, val.Pointer);
						}
						catch
						{
							continue;
						}
						int num3 = (int)propertyInfo.GetValue(obj2);
						long key = val.Pointer.ToInt64();
						if (!originals.TryGetValue(key, out var value))
						{
							value = (originals[key] = num3);
						}
						if (value >= 2 && num3 != num)
						{
							propertyInfo.SetValue(obj2, num);
							num2++;
						}
					}
				}
				string item = $"{type.Name}.{propertyInfo.Name}={num}";
				if (num2 > 0 && logged.Add(item))
				{
					((MelonBase)this).LoggerInstance.Msg($"{type.Name}.{propertyInfo.Name} -> {num}");
				}
			}
		}

		private bool Resolve()
		{
			if (resolved != null)
			{
				return resolved.Count > 0;
			}
			resolved = new List<(Type, PropertyInfo, object)>();
			findAll = FindType("UnityEngine.Resources")?.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfTypeAll" && !m.IsGenericMethod && m.GetParameters().Length == 1);
			MethodInfo methodInfo = (from m in typeof(Il2CppObjectBase).Assembly.GetType("Il2CppInterop.Runtime.Il2CppType")?.GetMethods(BindingFlags.Static | BindingFlags.Public)
				where m.Name == "From" && m.GetParameters().FirstOrDefault()?.ParameterType == typeof(Type)
				orderby m.GetParameters().Length
				select m).FirstOrDefault();
			if (findAll == null || methodInfo == null)
			{
				((MelonBase)this).LoggerInstance.Error("API da Unity não encontrada.");
				return false;
			}
			(string, string)[] targets = Targets;
			for (int num = 0; num < targets.Length; num++)
			{
				(string, string) tuple = targets[num];
				string item = tuple.Item1;
				string item2 = tuple.Item2;
				Type t = FindType(item);
				PropertyInfo propertyInfo = t?.GetProperty(item2, BindingFlags.Instance | BindingFlags.Public);
				if (t == null || propertyInfo == null || propertyInfo.PropertyType != typeof(int) || !propertyInfo.CanWrite)
				{
					((MelonBase)this).LoggerInstance.Warning(item + "." + item2 + " não encontrado. Versão do jogo incompatível?");
					continue;
				}
				object[] parameters = methodInfo.GetParameters().Select((ParameterInfo pi, int i) => (i != 0) ? ((!(pi.ParameterType == typeof(bool))) ? pi.DefaultValue : ((object)false)) : t).ToArray();
				object obj = methodInfo.Invoke(null, parameters);
				if (obj != null)
				{
					resolved.Add((t, propertyInfo, obj));
				}
			}
			return resolved.Count > 0;
		}

		private static Type FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type type = null;
				try
				{
					type = assembly.GetType(fullName, throwOnError: false);
				}
				catch
				{
				}
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
}