Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NoCheatText v1.4.0
NoCheatText.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NoCheatText")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.4.0.0")] [assembly: AssemblyInformationalVersion("1.4.0")] [assembly: AssemblyProduct("NoCheatText")] [assembly: AssemblyTitle("NoCheatText")] [assembly: AssemblyVersion("1.4.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 NoCheatText { [BepInPlugin("codex.valheim.nocheattext", "No Cheat Text", "1.4.0")] [BepInProcess("valheim.exe")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "codex.valheim.nocheattext"; public const string PluginName = "No Cheat Text"; public const string PluginVersion = "1.4.0"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> EnableAchievements; internal static ConfigEntry<bool> HideCommandConfirmation; internal static ConfigEntry<bool> RepairMissingRecipes; private static Plugin _instance; private static FieldRef<Player, HashSet<string>> _knownMaterials; private Action<Player> _updateKnownRecipes; private Harmony _harmony; private Coroutine _recovery; private Player _pendingPlayer; private Player _reconciledPlayer; private FieldInfo _localizationCache; private MethodInfo _evictLocalizationCache; private readonly List<MethodInfo> _installingTargets = new List<MethodInfo>(); private void Awake() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown _instance = this; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Hide cheat-related UI without changing saved cheat flags."); EnableAchievements = ((BaseUnityPlugin)this).Config.Bind<bool>("Achievements", "Enabled", true, "Allow achievements despite modded or cheated state. Does not grant achievements automatically."); HideCommandConfirmation = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HideCommandConfirmation", true, "Hide the cheat-command confirmation text, not the confirmation requirement."); RepairMissingRecipes = ((BaseUnityPlugin)this).Config.Bind<bool>("Recipes", "RepairMissingRecipesOnLogin", true, "Fix upgrader-only resource discovery gates and reconcile missing unlocks once per local player login. Crafting costs remain unchanged."); _harmony = new Harmony("codex.valheim.nocheattext"); InstallFeature("cheat text", delegate { _localizationCache = AccessTools.Field(typeof(Localization), "m_cache"); if (_localizationCache == null) { throw new MissingFieldException("Localization.m_cache"); } _evictLocalizationCache = AccessTools.Method(_localizationCache.FieldType, "EvictAll", Type.EmptyTypes, (Type[])null); if (_evictLocalizationCache == null) { throw new MissingMethodException("Localization cache EvictAll"); } Patch(AccessTools.Method(typeof(Localization), "Translate", new Type[1] { typeof(string) }, (Type[])null), "HideTranslation", null, null, typeof(TextPatches)); Patch(AccessTools.Method(typeof(TextsDialog), "AddStats", Type.EmptyTypes, (Type[])null), null, null, "FilterStatsLiteral", typeof(TextPatches)); Enabled.SettingChanged += OnTextSettingChanged; HideCommandConfirmation.SettingChanged += OnTextSettingChanged; EvictTextCache(); }); InstallFeature("achievements", delegate { Patch(AccessTools.Method(typeof(Achievements), "CanGetAchievements", new Type[1] { typeof(bool) }, (Type[])null), "AllowAchievements", null, null, typeof(TextPatches)); Patch(AccessTools.Method(typeof(Achievements), "IsCheatedAtAll", Type.EmptyTypes, (Type[])null), "ReportNotCheated", null, null, typeof(TextPatches)); Patch(AccessTools.Method(typeof(Achievements), "IsWorldCheated", Type.EmptyTypes, (Type[])null), null, "OverrideWorldStatus", null, typeof(TextPatches)); }); InstallFeature("recipe discovery", delegate { _knownMaterials = AccessTools.FieldRefAccess<Player, HashSet<string>>("m_knownMaterial"); MethodInfo methodInfo = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", Type.EmptyTypes, (Type[])null); if (methodInfo == null) { throw new MissingMethodException("Player.UpdateKnownRecipesList"); } _updateKnownRecipes = AccessTools.MethodDelegate<Action<Player>>(methodInfo, (object)null, true); Patch(AccessTools.Method(typeof(Player), "HaveRequirementItems", new Type[4] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) }, (Type[])null), null, "RecoverDiscovery"); Patch(AccessTools.Method(typeof(Player), "OnSpawned", new Type[1] { typeof(bool) }, (Type[])null), null, "OnPlayerSpawned"); }); ((BaseUnityPlugin)this).Logger.LogInfo((object)"No Cheat Text 1.4.0 loaded. Client-only; saved cheat markers and recipe costs are unchanged."); } private void InstallFeature(string name, Action install) { _installingTargets.Clear(); try { install(); } catch (Exception ex) { for (int i = 0; i < _installingTargets.Count; i++) { _harmony.Unpatch((MethodBase)_installingTargets[i], (HarmonyPatchType)0, "codex.valheim.nocheattext"); } ((BaseUnityPlugin)this).Logger.LogError((object)("Disabled incompatible feature '" + name + "': " + ex.GetBaseException().Message + ". Other features are independent.")); } finally { _installingTargets.Clear(); } } private void Patch(MethodInfo target, string prefix = null, string postfix = null, string transpiler = null, Type patchType = null) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (target == null) { throw new MissingMethodException("Required Valheim patch target is absent"); } Type type = patchType ?? typeof(Plugin); _installingTargets.Add(target); _harmony.Patch((MethodBase)target, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(type, prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(type, postfix, (Type[])null), (transpiler == null) ? ((HarmonyMethod)null) : new HarmonyMethod(type, transpiler, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } private static void RecoverDiscovery(Player __instance, Recipe __0, bool __1, ref bool __result) { if (!__result && __1 && RepairMissingRecipes.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)__0 == (Object)null) && RecipeRequirements.TryRecover(__0, _knownMaterials.Invoke(__instance), out var result)) { __result = result; } } private static void OnPlayerSpawned(Player __instance) { if (!((Object)(object)_instance == (Object)null) && RepairMissingRecipes.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { _instance.QueueRecovery(__instance); } } private void QueueRecovery(Player player) { if (!((Object)(object)player == (Object)(object)_pendingPlayer) && !((Object)(object)player == (Object)(object)_reconciledPlayer)) { if (_recovery != null) { ((MonoBehaviour)this).StopCoroutine(_recovery); } _pendingPlayer = player; _recovery = ((MonoBehaviour)this).StartCoroutine(ReconcileAfterLogin(player)); } } private IEnumerator ReconcileAfterLogin(Player player) { yield return (object)new WaitForSecondsRealtime(5f); float deadline = Time.realtimeSinceStartup + 25f; WaitForSecondsRealtime poll = new WaitForSecondsRealtime(0.5f); while ((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && RepairMissingRecipes.Value && ((Object)(object)Game.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)MessageHud.instance == (Object)null) && Time.realtimeSinceStartup < deadline) { yield return poll; } if ((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && RepairMissingRecipes.Value && (Object)(object)Game.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)MessageHud.instance != (Object)null) { try { _updateKnownRecipes(player); _reconciledPlayer = player; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Reconciled missing recipe/build-piece unlocks from this character's discovery history."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Login recipe reconciliation failed: " + ex.GetBaseException().Message)); } } else if ((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && RepairMissingRecipes.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Login recipe reconciliation skipped: game databases/HUD were not ready within 30 seconds."); } _pendingPlayer = null; _recovery = null; } private void OnTextSettingChanged(object sender, EventArgs args) { EvictTextCache(); } private void EvictTextCache() { if (Localization.instance == null || _localizationCache == null || _evictLocalizationCache == null) { return; } try { _evictLocalizationCache.Invoke(_localizationCache.GetValue(Localization.instance), null); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not refresh localization cache: " + ex.GetBaseException().Message)); } } private void OnDestroy() { if (_recovery != null) { ((MonoBehaviour)this).StopCoroutine(_recovery); } if (Enabled != null) { Enabled.SettingChanged -= OnTextSettingChanged; } if (HideCommandConfirmation != null) { HideCommandConfirmation.SettingChanged -= OnTextSettingChanged; } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } EvictTextCache(); _pendingPlayer = null; _reconciledPlayer = null; if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } } internal static class RecipeRequirements { internal static bool TryRecover(Recipe recipe, HashSet<string> knownMaterials, out bool result) { bool result2 = false; bool flag = true; bool flag2 = false; Requirement[] resources = recipe.m_resources; if (resources != null) { foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null)) { if (val.m_upgraderResource) { result2 = true; } else if (val.m_amount > 0) { bool flag3 = knownMaterials.Contains(val.m_resItem.m_itemData.m_shared.m_name); flag2 = flag2 || flag3; flag = flag && flag3; } } } } result = (recipe.m_requireOnlyOneIngredient ? flag2 : flag); return result2; } } internal static class TextPatches { private static readonly MethodInfo FilterLiteralMethod = typeof(TextPatches).GetMethod("FilterLiteral", BindingFlags.Static | BindingFlags.NonPublic); internal static bool HideTranslation(string __0, ref string __result) { if (!Plugin.Enabled.Value) { return true; } switch (__0) { case "achievements_cheated_item_inventory": case "achievements_picked_up_cheated_item": case "achievements_dropped_cheated_item": case "achievements_temporarily_cheated": case "achievements_permanently_cheated_character": case "achievements_permanently_cheated_world": case "achievements_permanently_cheated_bypass": __result = string.Empty; return false; case "achievements_confirm_cheat": if (!Plugin.HideCommandConfirmation.Value) { return true; } __result = string.Empty; return false; default: return true; } } internal static bool AllowAchievements(ref bool __result) { if (!Plugin.EnableAchievements.Value) { return true; } __result = true; return false; } internal static bool ReportNotCheated(ref bool __result) { if (!Plugin.EnableAchievements.Value) { return true; } __result = false; return false; } internal static void OverrideWorldStatus(ref bool __result) { if (Plugin.EnableAchievements.Value) { __result = false; } } internal static IEnumerable<CodeInstruction> FilterStatsLiteral(IEnumerable<CodeInstruction> instructions) { bool found = false; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string text && text.IndexOf("Cheater!", StringComparison.Ordinal) >= 0) { yield return new CodeInstruction(OpCodes.Call, (object)FilterLiteralMethod); found = true; } } if (!found) { throw new InvalidOperationException("TextsDialog.AddStats cheat literal changed; refusing a silent no-op patch."); } } internal static string FilterLiteral(string original) { if (!Plugin.Enabled.Value) { return original; } return string.Empty; } } }