Decompiled source of SubMeshFix v1.0.0

SubMeshFix.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Microsoft.CodeAnalysis;
using SubMeshFix.Interop;
using SubMeshFix.Patches;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("SubMeshFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SubMeshFix")]
[assembly: AssemblyTitle("SubMeshFix")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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 SubMeshFix
{
	internal static class Logger
	{
		private static ManualLogSource _mLogSource;

		public static bool Ready => _mLogSource != null;

		public static void Setup()
		{
			_mLogSource = Logger.CreateLogSource("io.takina.gtfo.SubMeshFix");
		}

		public static void SetupFromInit(ManualLogSource logSource)
		{
			_mLogSource = logSource;
		}

		private static string Format(object data)
		{
			return data.ToString();
		}

		public static void Debug(object msg)
		{
			if (Plugin.Debug)
			{
				_mLogSource.LogDebug((object)Format(msg));
			}
		}

		public static void Debug(string fmt, params object[] args)
		{
			if (Plugin.Debug)
			{
				_mLogSource.LogDebug((object)Format(string.Format(fmt, args)));
			}
		}

		public static void Info(object msg)
		{
			_mLogSource.LogInfo((object)Format(msg));
		}

		public static void Info(string fmt, params object[] args)
		{
			_mLogSource.LogInfo((object)Format(string.Format(fmt, args)));
		}

		public static void Warn(object msg)
		{
			_mLogSource.LogWarning((object)Format(msg));
		}

		public static void Warn(string fmt, params object[] args)
		{
			_mLogSource.LogWarning((object)Format(string.Format(fmt, args)));
		}

		public static void Error(object msg)
		{
			_mLogSource.LogError((object)Format(msg));
		}

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

		public static void Fatal(object msg)
		{
			_mLogSource.LogFatal((object)Format(msg));
		}

		public static void Fatal(string fmt, params object[] args)
		{
			_mLogSource.LogFatal((object)Format(string.Format(fmt, args)));
		}
	}
	[BepInPlugin("io.takina.gtfo.SubMeshFix", "SubMeshFix", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public const string NAME = "SubMeshFix";

		public const string GUID = "io.takina.gtfo.SubMeshFix";

		public const string VERSION = "1.0.0";

		private static ConfigEntry<bool>? _debug;

		public static bool Debug => _debug?.Value ?? false;

		public override void Load()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			Logger.Setup();
			Logger.Info("SubMeshFix [io.takina.gtfo.SubMeshFix @ 1.0.0]");
			_debug = ((BasePlugin)this).Config.Bind<bool>("Dev", "Enable Debug Logs", false, "debug logging");
			RegisterIl2CppTypes();
			Logger.Info("Patching...");
			ApplyPatches(new Harmony("io.takina.gtfo.SubMeshFix"));
			Logger.Info("Finished Patching");
			((BasePlugin)this).AddComponent<SubMeshSync>();
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static void ApplyPatches(Harmony h)
		{
			h.PatchAll(typeof(SubMeshPatches));
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static void RegisterIl2CppTypes()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				if (type.GetCustomAttribute<RegisterIl2CppAttribute>() != null)
				{
					ClassInjector.RegisterTypeInIl2Cpp(type);
				}
			}
		}
	}
	[RegisterIl2Cpp]
	public class SubMeshSync : MonoBehaviour
	{
		private void LateUpdate()
		{
			SubMeshPatches.LateTick();
		}
	}
}
namespace SubMeshFix.Patches
{
	[HarmonyPatch]
	public class SubMeshPatches
	{
		private static readonly List<(MeshRenderer main, MeshRenderer sub)> Pairs = new List<(MeshRenderer, MeshRenderer)>();

		private static readonly HashSet<int> Tracked = new HashSet<int>();

		private static readonly MaterialPropertyBlock Scratch = new MaterialPropertyBlock();

		private static readonly Dictionary<int, int> Hidden = new Dictionary<int, int>();

		private const int MaxHiddenFrames = 10;

		private static void Track(MeshRenderer? main, MeshRenderer? sub)
		{
			if (!((Object)(object)main == (Object)null) && !((Object)(object)sub == (Object)null) && Tracked.Add(((Object)sub).GetInstanceID()))
			{
				Pairs.Add((main, sub));
				if (!Sync(main, sub))
				{
					((Renderer)sub).forceRenderingOff = true;
					Hidden[((Object)sub).GetInstanceID()] = Time.frameCount;
				}
			}
		}

		private static bool Sync(MeshRenderer main, MeshRenderer sub)
		{
			if (((Renderer)sub).sortingLayerID != ((Renderer)main).sortingLayerID)
			{
				((Renderer)sub).sortingLayerID = ((Renderer)main).sortingLayerID;
			}
			if (((Renderer)sub).sortingOrder != ((Renderer)main).sortingOrder)
			{
				((Renderer)sub).sortingOrder = ((Renderer)main).sortingOrder;
			}
			if (!((Renderer)main).HasPropertyBlock())
			{
				return false;
			}
			((Renderer)main).GetPropertyBlock(Scratch);
			((Renderer)sub).SetPropertyBlock(Scratch);
			if (((Renderer)sub).forceRenderingOff)
			{
				((Renderer)sub).forceRenderingOff = false;
				Hidden.Remove(((Object)sub).GetInstanceID());
			}
			return true;
		}

		[HarmonyPatch(typeof(TMP_SubMesh), "AddSubTextObject")]
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		private static void Postfix__AddSubTextObject(TextMeshPro textComponent, TMP_SubMesh __result)
		{
			if (!((Object)(object)textComponent == (Object)null) && !((Object)(object)__result == (Object)null))
			{
				MeshRenderer component = ((Component)textComponent).GetComponent<MeshRenderer>();
				MeshRenderer component2 = ((Component)__result).GetComponent<MeshRenderer>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
				{
					((Renderer)component2).sortingLayerID = ((Renderer)component).sortingLayerID;
					((Renderer)component2).sortingOrder = ((Renderer)component).sortingOrder;
					Evaluate(((Component)__result).gameObject);
				}
			}
		}

		[HarmonyPatch(typeof(UIClipFeeder), "Setup")]
		[HarmonyPostfix]
		[HarmonyWrapSafe]
		private static void Postfix__UIClipFeeder_Setup(UIClipFeeder __instance)
		{
			Transform val = (((Object)(object)__instance != (Object)null) ? __instance.m_clippingScanRoot : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			foreach (TMP_SubMesh componentsInChild in ((Component)val).GetComponentsInChildren<TMP_SubMesh>(true))
			{
				if ((Object)(object)componentsInChild != (Object)null)
				{
					Evaluate(((Component)componentsInChild).gameObject);
				}
			}
		}

		private static void Evaluate(GameObject subObject)
		{
			if ((Object)(object)subObject == (Object)null)
			{
				return;
			}
			MeshRenderer component = subObject.GetComponent<MeshRenderer>();
			if (!((Object)(object)component == (Object)null) && !Tracked.Contains(((Object)component).GetInstanceID()))
			{
				TextMeshPro val = FindAbove<TextMeshPro>(subObject.transform);
				UIClipFeeder val2 = (((Object)(object)val != (Object)null) ? FindAbove<UIClipFeeder>(val.transform) : null);
				Transform val3 = (((Object)(object)val2 != (Object)null) ? val2.m_clippingScanRoot : null);
				if ((Object)(object)val3 != (Object)null && subObject.transform.IsChildOf(val3))
				{
					Track(((Component)val).GetComponent<MeshRenderer>(), component);
				}
			}
		}

		private static T? FindAbove<T>(Transform from) where T : Component
		{
			Transform val = from;
			while ((Object)(object)val != (Object)null)
			{
				T component = ((Component)val).GetComponent<T>();
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
				val = val.parent;
			}
			return default(T);
		}

		internal static void LateTick()
		{
			for (int num = Pairs.Count - 1; num >= 0; num--)
			{
				var (val, val2) = Pairs[num];
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					Pairs.RemoveAt(num);
					if (Pairs.Count == 0)
					{
						Tracked.Clear();
						Hidden.Clear();
					}
				}
				else if (((Component)val2).gameObject.activeInHierarchy && !Sync(val, val2) && ((Renderer)val2).forceRenderingOff)
				{
					int instanceID = ((Object)val2).GetInstanceID();
					if (!Hidden.TryGetValue(instanceID, out var value) || Time.frameCount - value > 10)
					{
						((Renderer)val2).forceRenderingOff = false;
						Hidden.Remove(instanceID);
					}
				}
			}
		}
	}
}
namespace SubMeshFix.Interop
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false)]
	public class RegisterIl2CppAttribute : Attribute
	{
	}
}