using System; using System.Collections; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace ValueRaceFix; [BepInPlugin("valuerace.fix.runtime", "ValueRace Fix", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static ConfigEntry DebugLogging; private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; DebugLogging = ((BaseUnityPlugin)this).Config.Bind("General", "DebugLogging", false, "Enable extra logs for ValueRace Fix."); Harmony harmony = new Harmony("valuerace.fix.runtime"); ValueRaceGenerateDoneGuard.Apply(harmony); } } internal static class ModLog { private static bool loggedMissingTarget; private static bool loggedMissingUiPrefab; private static bool loggedPatchFailure; public static void Info(string message) { if (Plugin.Log != null) { Plugin.Log.LogInfo((object)message); } } public static void Warning(string message) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)message); } } public static void Debug(string message) { if (Plugin.DebugLogging != null && Plugin.DebugLogging.Value && Plugin.Log != null) { Plugin.Log.LogInfo((object)("[Debug] " + message)); } } public static void MissingTarget() { if (!loggedMissingTarget) { Warning("REPO_ValueRace GenerateDone patch target was not found."); loggedMissingTarget = true; } } public static void MissingUiPrefab() { if (!loggedMissingUiPrefab) { Warning("REPO_ValueRace UI prefab was not available; leaderboard display will wait for the original mod to load it."); loggedMissingUiPrefab = true; } } public static void PatchFailure(Exception ex) { if (loggedPatchFailure) { Debug("ValueRace GenerateDone guard failed again: " + ex.GetType().Name + ": " + ex.Message); return; } Warning("ValueRace GenerateDone guard handled an unexpected error: " + ex.GetType().Name + ": " + ex.Message); loggedPatchFailure = true; } } internal static class ValueRaceGenerateDoneGuard { private const string PatchTypeName = "REPO_ValueRace.Patch"; private const string PatchNestedTypeName = "REPO_ValueRace.Patch+LevelGenerator_Patch"; private const string UiManagerTypeName = "REPO_ValueRace.ValueRaceUIManager"; private const string PluginTypeName = "REPO_ValueRace.Plugin"; public static void Apply(Harmony harmony) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown Type type = AccessTools.TypeByName("REPO_ValueRace.Patch+LevelGenerator_Patch"); MethodInfo methodInfo = AccessTools.Method(type, "GenerateDone_Postfix", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ValueRaceGenerateDoneGuard), "Prefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ModLog.MissingTarget(); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ModLog.Info("Patched REPO_ValueRace level generation guard."); } private static bool Prefix() { try { RunSafeGenerateDone(); } catch (Exception ex) { ModLog.PatchFailure(ex); } return false; } private static void RunSafeGenerateDone() { if (SemiFunc.RunIsLevel()) { SetDateDone(value: false); if (SemiFunc.IsMasterClientOrSingleplayer()) { ResetRoundState(); } } else if (SemiFunc.RunIsShop()) { object obj = EnsureUiManager(); if (obj != null && GetStaticBool("REPO_ValueRace.Patch", "hasRankData")) { ApplyStoredRankData(obj); } } } private static object EnsureUiManager() { object uiManagerInstance = GetUiManagerInstance(); if (uiManagerInstance != null) { return uiManagerInstance; } Type ownerType = AccessTools.TypeByName("REPO_ValueRace.Plugin"); object staticField = GetStaticField(ownerType, "instance"); object instanceField = GetInstanceField(staticField, "mainUI"); GameObject val = (GameObject)((instanceField is GameObject) ? instanceField : null); if ((Object)(object)val == (Object)null) { ModLog.MissingUiPrefab(); return null; } GameObject val2 = Object.Instantiate(val); Type type = AccessTools.TypeByName("REPO_ValueRace.ValueRaceUIManager"); if (type == null) { return null; } uiManagerInstance = val2.GetComponent(type) ?? val2.AddComponent(type); Object.DontDestroyOnLoad((Object)(object)val2); if (GetUiManagerInstance() == null && uiManagerInstance != null) { SetStaticField(type, "instance", uiManagerInstance); } ModLog.Debug("Created REPO_ValueRace UI manager safely."); return uiManagerInstance; } private static object GetUiManagerInstance() { Type ownerType = AccessTools.TypeByName("REPO_ValueRace.ValueRaceUIManager"); return GetStaticField(ownerType, "instance"); } private static void SetDateDone(bool value) { object uiManagerInstance = GetUiManagerInstance(); if (uiManagerInstance != null) { SetInstanceField(uiManagerInstance, "dateDone", value); } } private static void ResetRoundState() { Type ownerType = AccessTools.TypeByName("REPO_ValueRace.Patch"); ClearStaticCollection(ownerType, "playerGained"); ClearStaticCollection(ownerType, "playerDamaged"); ClearStaticCollection(ownerType, "playerFinal"); ClearStaticCollection(ownerType, "extractionPointValueable"); SetStaticField(ownerType, "hasRankData", false); SetStaticField(ownerType, "lastRanks", null); SetStaticField(ownerType, "lastNames", null); SetStaticField(ownerType, "lastValues", null); SetStaticField(ownerType, "lastDamages", null); SetStaticField(ownerType, "lastFinals", null); ModLog.Debug("Reset REPO_ValueRace round state."); } private static void ApplyStoredRankData(object manager) { Type ownerType = AccessTools.TypeByName("REPO_ValueRace.Patch"); object[] parameters = new object[5] { GetStaticField(ownerType, "lastRanks"), GetStaticField(ownerType, "lastNames"), GetStaticField(ownerType, "lastValues"), GetStaticField(ownerType, "lastDamages"), GetStaticField(ownerType, "lastFinals") }; MethodInfo methodInfo = AccessTools.Method(manager.GetType(), "ApplyRankData", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(manager, parameters); } MethodInfo methodInfo2 = AccessTools.Method(manager.GetType(), "ShowUI", (Type[])null, (Type[])null); if (methodInfo2 != null) { methodInfo2.Invoke(manager, new object[1] { 5f }); } ModLog.Debug("Applied stored REPO_ValueRace leaderboard data."); } private static void ClearStaticCollection(Type ownerType, string fieldName) { object staticField = GetStaticField(ownerType, fieldName); if (staticField == null) { return; } if (staticField is IDictionary dictionary) { dictionary.Clear(); return; } MethodInfo methodInfo = AccessTools.Method(staticField.GetType(), "Clear", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(staticField, null); } } private static bool GetStaticBool(string typeName, string fieldName) { object staticField = GetStaticField(AccessTools.TypeByName(typeName), fieldName); if (staticField is bool) { return (bool)staticField; } return false; } private static object GetStaticField(Type ownerType, string fieldName) { FieldInfo fieldInfo = AccessTools.Field(ownerType, fieldName); if (!(fieldInfo == null)) { return fieldInfo.GetValue(null); } return null; } private static void SetStaticField(Type ownerType, string fieldName, object value) { FieldInfo fieldInfo = AccessTools.Field(ownerType, fieldName); if (fieldInfo != null) { fieldInfo.SetValue(null, value); } } private static object GetInstanceField(object owner, string fieldName) { if (owner == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(owner.GetType(), fieldName); if (!(fieldInfo == null)) { return fieldInfo.GetValue(owner); } return null; } private static void SetInstanceField(object owner, string fieldName, object value) { if (owner != null) { FieldInfo fieldInfo = AccessTools.Field(owner.GetType(), fieldName); if (fieldInfo != null) { fieldInfo.SetValue(owner, value); } } } }