Decompiled source of MTFO Extension Scans v1.0.0

MTFO.Ext.Scans.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using ChainedPuzzles;
using GTFO.API;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.InteropTypes.Fields;
using Il2CppSystem.Collections.Generic;
using MTFO.API;
using MTFO.Ext.Scans.CustomPuzzleData;
using MTFO.Ext.Scans.Dependencies;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MTFO.Ext.Scans")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+26f1ca6ff513e2899b328a9001395ac50d60c4fa")]
[assembly: AssemblyProduct("MTFO.Ext.Scans")]
[assembly: AssemblyTitle("MTFO.Ext.Scans")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace MTFO.Ext.Scans
{
	internal static class DinoLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("MTFO.Ext.Scans");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
	[BepInPlugin("MTFO.Extension.Scans", "MTFO.Ext.Scans", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "MTFO.Ext.Scans";

		public override void Load()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!MTFOWrapper.HasCustomContent)
			{
				((BasePlugin)this).Log.LogMessage((object)"No Custom folder, not loading...");
				return;
			}
			if (MTFOWrapper.GetCorePuzzleData == null)
			{
				DinoLogger.Error("Unable to find method to get CorePuzzleData, not loading...");
				return;
			}
			ScanDataManager.Init();
			new Harmony("MTFO.Ext.Scans").PatchAll();
			LevelAPI.OnLevelCleanup += ScanDataManager.OnCleanup;
			((BasePlugin)this).Log.LogMessage((object)"Loaded MTFO.Ext.Scans");
		}
	}
}
namespace MTFO.Ext.Scans.Patches
{
	[HarmonyPatch]
	internal static class BioscanPatches
	{
		[HarmonyPatch(typeof(CP_Bioscan_Core), "OnDestroy")]
		[HarmonyPostfix]
		private static void CleanupDeadScanner(CP_Bioscan_Core __instance)
		{
			ScanDataManager.RemoveCacheData(__instance);
		}

		[HarmonyPatch(typeof(CP_Bioscan_Core), "Master_OnPlayerScanChangedCheckProgress")]
		[HarmonyPostfix]
		private static void UpdateFullTeamMultiChange(CP_Bioscan_Core __instance, List<PlayerAgent> playersInScan, int inScanMax)
		{
			if (!ScanDataManager.TryGetScanData(((Component)__instance).gameObject, out ScanData data) || data.FullTeamScanMulti == 0f || !ScanDataManager.TryCacheScanData(__instance, out (float[], CP_PlayerScanner) cachedData))
			{
				return;
			}
			Il2CppStructArray<float> scanSpeeds = cachedData.Item2.m_scanSpeeds;
			if (inScanMax == playersInScan.Count)
			{
				for (int i = 0; i < cachedData.Item1.Length; i++)
				{
					((Il2CppArrayBase<float>)(object)scanSpeeds)[i] = data.FullTeamScanMulti;
				}
			}
			else
			{
				for (int j = 0; j < cachedData.Item1.Length; j++)
				{
					((Il2CppArrayBase<float>)(object)scanSpeeds)[j] = cachedData.Item1[j];
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class ScannerPatches
	{
		[HarmonyPatch(typeof(CP_PlayerScanner), "StartScan")]
		[HarmonyPriority(600)]
		[HarmonyPrefix]
		private static void CleanupDeadScanner(CP_PlayerScanner __instance)
		{
			if (!SNet.IsMaster || __instance.m_scanActive || !ScanDataManager.TryGetScanData(((Component)__instance).gameObject, out ScanData data) || data.PerTeamSizeScanMultis == null)
			{
				return;
			}
			int count = PlayerManager.PlayerAgentsInLevel.Count;
			if (TryGetScanMultis(data.PerTeamSizeScanMultis, count, out float[] scanMultis))
			{
				if (scanMultis.Length > 4)
				{
					__instance.m_scanSpeeds = Il2CppStructArray<float>.op_Implicit(new float[scanMultis.Length]);
				}
				for (int i = 0; i < ((Il2CppArrayBase<float>)(object)__instance.m_scanSpeeds).Length; i++)
				{
					((Il2CppArrayBase<float>)(object)__instance.m_scanSpeeds)[i] = scanMultis[Math.Min(i, scanMultis.Length - 1)];
				}
			}
		}

		private static bool TryGetScanMultis(float[][] lists, int playerCount, [MaybeNullWhen(false)] out float[] scanMultis)
		{
			for (int i = playerCount - 1; i < lists.Length; i++)
			{
				if (lists[i].Length != 0)
				{
					scanMultis = lists[i];
					return true;
				}
			}
			scanMultis = null;
			return false;
		}
	}
}
namespace MTFO.Ext.Scans.Dependencies
{
	internal static class MTFOWrapper
	{
		public const string PLUGIN_GUID = "com.dak.MTFO";

		public static readonly MethodInfo GetCorePuzzleData;

		public static readonly FieldInfo GetCorePuzzleDataID;

		public static string GameDataPath => MTFOPathAPI.RundownPath;

		public static string CustomPath => MTFOPathAPI.CustomPath;

		public static bool HasCustomContent => MTFOPathAPI.HasRundownPath;

		static MTFOWrapper()
		{
			PluginInfo val = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins["com.dak.MTFO"];
			try
			{
				Type type = (((val == null) ? null : val.Instance?.GetType()?.Assembly) ?? throw new Exception("Assembly is missing!")).GetTypes().First((Type t) => t.Name == "CorePuzzleData");
				if ((object)type == null)
				{
					throw new Exception("Unable to find CorePuzzleData class!");
				}
				GetCorePuzzleDataID = type.GetField("PersistentID", BindingFlags.Instance | BindingFlags.Public);
				if ((object)GetCorePuzzleDataID == null)
				{
					throw new Exception("Unable to find PersistentID field in CorePuzzleData!");
				}
				GetCorePuzzleData = (typeof(GameObject).GetMethod("GetComponent", BindingFlags.Instance | BindingFlags.Public, Array.Empty<Type>()) ?? throw new Exception("Unable to find GetComponent function!")).MakeGenericMethod(type);
			}
			catch (Exception value)
			{
				DinoLogger.Log($"Exception thrown while trying to find method to get CorePuzzleData:\n{value}");
			}
		}
	}
}
namespace MTFO.Ext.Scans.CustomPuzzleData
{
	public class ScanData
	{
		public float FullTeamScanMulti { get; set; }

		public float[][] PerTeamSizeScanMultis { get; set; } = Array.Empty<float[]>();


		public uint PersistentID { get; set; }
	}
	internal class ScanDataHolder
	{
		public List<ScanData> Scans { get; set; }

		public List<EmptyClusterHolder> Clusters { get; set; }
	}
	internal class EmptyClusterHolder
	{
	}
	public static class ScanDataManager
	{
		private static readonly Dictionary<uint, ScanData> _scanData = new Dictionary<uint, ScanData>();

		private static readonly Dictionary<IntPtr, (float[] multis, CP_PlayerScanner scanner)> _originalMultis = new Dictionary<IntPtr, (float[], CP_PlayerScanner)>();

		internal static void Init()
		{
			string path = Path.Combine(MTFOPathAPI.CustomPath, "PuzzleTypes.json");
			if (!File.Exists(path))
			{
				DinoLogger.Error("Datablocks exist, but PuzzleTypes.json does not exist!");
				return;
			}
			JsonSerializerOptions options = new JsonSerializerOptions
			{
				ReadCommentHandling = JsonCommentHandling.Skip,
				IncludeFields = true,
				PropertyNameCaseInsensitive = true
			};
			List<ScanData> list = JsonSerializer.Deserialize<ScanDataHolder>(File.ReadAllText(path), options)?.Scans;
			if (list == null)
			{
				DinoLogger.Error("Unable to read data from PuzzleTypes.json!");
				return;
			}
			foreach (ScanData item in list)
			{
				_scanData.TryAdd(item.PersistentID, item);
			}
		}

		public static bool TryGetScanData(GameObject go, [MaybeNullWhen(false)] out ScanData data)
		{
			data = null;
			object obj = MTFOWrapper.GetCorePuzzleData.Invoke(go, null);
			if (obj == null)
			{
				return false;
			}
			return TryGetScanData(Il2CppValueField<uint>.op_Implicit((Il2CppValueField<uint>)MTFOWrapper.GetCorePuzzleDataID.GetValue(obj)), out data);
		}

		public static bool TryGetScanData(uint id, [MaybeNullWhen(false)] out ScanData data)
		{
			return _scanData.TryGetValue(id, out data);
		}

		public static bool TryCacheScanData(CP_Bioscan_Core scan, [MaybeNullWhen(false)] out (float[] multis, CP_PlayerScanner scanner) cachedData)
		{
			IntPtr pointer = ((Il2CppObjectBase)scan).Pointer;
			if (_originalMultis.TryGetValue(pointer, out cachedData))
			{
				return true;
			}
			if (scan.PlayerScanner == null)
			{
				return false;
			}
			CP_PlayerScanner val = ((Il2CppObjectBase)scan.PlayerScanner).Cast<CP_PlayerScanner>();
			float[] array = new float[((Il2CppArrayBase<float>)(object)val.m_scanSpeeds).Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = ((Il2CppArrayBase<float>)(object)val.m_scanSpeeds)[i];
			}
			cachedData = (array, val);
			_originalMultis.Add(pointer, cachedData);
			return true;
		}

		public static void RemoveCacheData(CP_Bioscan_Core scan)
		{
			_originalMultis.Remove(((Il2CppObjectBase)scan).Pointer);
		}

		public static void OnCleanup()
		{
			_originalMultis.Clear();
		}
	}
}