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
{
}
}