Decompiled source of Achievement Enabler Plus v2.0.3

BepInEx/plugins/AchievementEnablerPlus/AchievementEnablerPlus.dll

Decompiled 3 hours ago
using System;
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.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("AchievementEnablerPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.3.0")]
[assembly: AssemblyInformationalVersion("2.0.3")]
[assembly: AssemblyProduct("AchievementEnablerPlus")]
[assembly: AssemblyTitle("AchievementEnablerPlus")]
[assembly: AssemblyVersion("2.0.3.0")]
namespace Robgob.ValheimAchievementEligibility;

[BepInPlugin("com.robgob.valheim.achievementeligibility", "Achievement Enabler+", "2.0.3")]
public sealed class AchievementEligibilityPlugin : BaseUnityPlugin
{
	internal const string PluginGuid = "com.robgob.valheim.achievementeligibility";

	internal const string PluginName = "Achievement Enabler+";

	internal const string PluginVersion = "2.0.3";

	private static readonly string[] RecoveryChecks = new string[6] { "CheckAchievementProgressUnlockEnemyStat", "CheckAchievementProgressUnlockItemPickup", "CheckAchievementProgressUnlockItemCraft", "CheckAchievementProgressUnlockPickable", "CheckAchievementsProgressUnlockFoodEaten", "CheckAchievementProgressUnlockBuildPiecesPlaced" };

	internal static ManualLogSource PluginLogger;

	private float nextRecoveryAttempt = 15f;

	private int recoveryAttempts;

	private Player sessionPlayer;

	private float nextCleanup;

	private Harmony harmony;

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		PluginLogger = ((BaseUnityPlugin)this).Logger;
		harmony = new Harmony("com.robgob.valheim.achievementeligibility");
		try
		{
			harmony.PatchAll(typeof(AchievementEligibilityPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Achievement Enabler+ 2.0.3 loaded: achievements enabled; item and character cheat cleanup active.");
		}
		catch (Exception ex)
		{
			harmony.UnpatchSelf();
			((Behaviour)this).enabled = false;
			((BaseUnityPlugin)this).Logger.LogError((object)("Unable to apply all patches; plugin disabled: " + ex));
		}
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}

	private void Update()
	{
		Player localPlayer = Player.m_localPlayer;
		if (localPlayer != sessionPlayer)
		{
			sessionPlayer = localPlayer;
			recoveryAttempts = 0;
			nextRecoveryAttempt = Time.unscaledTime + 15f;
			nextCleanup = 0f;
		}
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		if (Time.unscaledTime >= nextCleanup)
		{
			nextCleanup = Time.unscaledTime + 1f;
			CharacterSanitizer.CleanLocal();
		}
		if (recoveryAttempts < 3 && !(Time.unscaledTime < nextRecoveryAttempt))
		{
			nextRecoveryAttempt = Time.unscaledTime + 15f;
			if (RunRecoveryChecks())
			{
				recoveryAttempts++;
			}
		}
	}

	private bool RunRecoveryChecks()
	{
		Achievements val = Object.FindAnyObjectByType<Achievements>();
		if ((Object)(object)val == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
		{
			return false;
		}
		int num = 0;
		string[] recoveryChecks = RecoveryChecks;
		foreach (string text in recoveryChecks)
		{
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Achievements), text, (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					methodInfo.Invoke(val, null);
					num++;
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Recovery check " + text + " failed: " + ex.GetBaseException().Message));
			}
		}
		if (num > 0)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Ran {num} achievement progress recovery checks (attempt {recoveryAttempts + 1}/3).");
		}
		return num > 0;
	}
}
[HarmonyPatch(typeof(Achievements), "CanGetAchievements")]
internal static class CanGetAchievementsPatch
{
	[HarmonyPriority(0)]
	private static bool Prefix(ref bool __result)
	{
		__result = true;
		return false;
	}

	[HarmonyPriority(0)]
	private static void Postfix(ref bool __result)
	{
		__result = true;
	}
}
internal static class CharacterSanitizer
{
	internal static void Clean(PlayerProfile profile)
	{
		if (profile == null)
		{
			return;
		}
		profile.m_usedCheats = false;
		if (profile.m_playerStats == null)
		{
			return;
		}
		PlayerStats[] playerStats = profile.m_playerStats;
		foreach (PlayerStats val in playerStats)
		{
			if (val?.m_stats != null)
			{
				val.m_stats[(PlayerStatType)4] = 0f;
			}
		}
	}

	internal static void CleanLocal()
	{
		if ((Object)(object)Game.instance != (Object)null)
		{
			Clean(Game.instance.GetPlayerProfile());
		}
		if ((Object)(object)Player.m_localPlayer != (Object)null)
		{
			Sanitizer.Clean(((Humanoid)Player.m_localPlayer).GetInventory());
		}
	}
}
[HarmonyPatch]
internal static class ProfileCleanupPatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		string[] array = new string[6] { "Load", "LoadPlayerFromDisk", "LoadPlayerData", "Save", "SavePlayerToDisk", "SavePlayerData" };
		foreach (string text in array)
		{
			yield return AccessTools.Method(typeof(PlayerProfile), text, (Type[])null, (Type[])null);
		}
	}

	private static void Prefix(PlayerProfile __instance)
	{
		CharacterSanitizer.Clean(__instance);
	}

	private static void Postfix(PlayerProfile __instance)
	{
		CharacterSanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ConsoleCommand), "RunAction")]
internal static class CommandCleanupPatch
{
	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		MethodInfo method = typeof(Achievements).GetMethod("IsCheatedAtAll", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		int num = 0;
		foreach (CodeInstruction item in list)
		{
			if (!(item.opcode != OpCodes.Call) && object.Equals(item.operand, method))
			{
				item.opcode = OpCodes.Ldc_I4_1;
				item.operand = null;
				num++;
			}
		}
		if (num != 1)
		{
			throw new InvalidOperationException("Expected one command cheat-confirmation check; found " + num);
		}
		return list;
	}

	private static void Prefix()
	{
		CharacterSanitizer.CleanLocal();
	}

	private static void Postfix()
	{
		CharacterSanitizer.CleanLocal();
	}
}
[HarmonyPatch(typeof(PlayerProfile), "IncrementStat")]
internal static class CheatCounterPatch
{
	private static bool Prefix(PlayerProfile __instance, PlayerStatType __0)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		if ((int)__0 != 4)
		{
			return true;
		}
		CharacterSanitizer.Clean(__instance);
		return false;
	}
}
[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
internal static class LocalPlayerCleanupPatch
{
	private static void Postfix()
	{
		CharacterSanitizer.CleanLocal();
	}
}
[HarmonyPatch(typeof(Achievements), "IsCheatedAtAll")]
internal static class AchievementCheatStatusPatch
{
	private static bool Prefix(ref bool __result)
	{
		CharacterSanitizer.CleanLocal();
		__result = false;
		return false;
	}

	[HarmonyPriority(0)]
	private static void Postfix(ref bool __result)
	{
		__result = false;
	}
}
internal static class Sanitizer
{
	internal static bool Clean(ItemData item)
	{
		if (item == null || !item.m_cheated)
		{
			return false;
		}
		item.m_cheated = false;
		return true;
	}

	internal static int Clean(Inventory inventory)
	{
		if (inventory == null)
		{
			return 0;
		}
		int num = 0;
		List<ItemData> allItems = inventory.GetAllItems();
		for (int i = 0; i < allItems.Count; i++)
		{
			if (Clean(allItems[i]))
			{
				num++;
			}
		}
		return num;
	}

	internal static void Clean(ItemDrop drop)
	{
		if ((Object)(object)drop != (Object)null)
		{
			Clean(drop.m_itemData);
		}
	}
}
[HarmonyPatch(typeof(Inventory), "Changed")]
internal static class InventoryChangedPatch
{
	[HarmonyPriority(0)]
	private static void Prefix(Inventory __instance, ref bool cheatedStateChanged, ref bool ___m_cheatedPopup)
	{
		Sanitizer.Clean(__instance);
		cheatedStateChanged = false;
		___m_cheatedPopup = false;
	}

	private static void Postfix(Inventory __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(Inventory), "Save")]
internal static class InventorySavePatch
{
	private static void Prefix(Inventory __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch]
internal static class InventoryIngressPatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name == "Load" || methodInfo.Name == "LoadOld" || methodInfo.Name == "AddItem" || methodInfo.Name == "AddTempItem")
			{
				yield return methodInfo;
			}
		}
	}

	private static void Prefix(object[] __args)
	{
		if (__args != null)
		{
			foreach (object obj in __args)
			{
				Sanitizer.Clean((ItemData)((obj is ItemData) ? obj : null));
			}
		}
	}

	private static void Postfix(Inventory __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(Inventory), "MoveInventoryToGrave")]
internal static class GraveTransferPatch
{
	private static void Prefix(Inventory __instance, Inventory original)
	{
		Sanitizer.Clean(original);
		Sanitizer.Clean(__instance);
	}

	private static void Postfix(Inventory __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ItemDrop), "Save")]
internal static class WorldItemSavePatch
{
	private static void Prefix(ItemDrop __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ItemDrop), "Load")]
internal static class WorldItemLoadPatch
{
	private static void Postfix(ItemDrop __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ItemDrop), "OnPlayerDrop")]
internal static class PlayerDropPatch
{
	private static void Prefix(ItemDrop __instance)
	{
		Sanitizer.Clean(__instance);
	}

	private static void Postfix(ItemDrop __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ItemDrop), "OnCreateNew", new Type[]
{
	typeof(GameObject),
	typeof(bool)
})]
internal static class NewWorldItemPatch
{
	private static void Prefix(ref bool cheated)
	{
		cheated = false;
	}
}
[HarmonyPatch(typeof(ItemDrop), "OnCreateNew", new Type[]
{
	typeof(ItemDrop),
	typeof(bool)
})]
internal static class CopiedWorldItemPatch
{
	private static void Prefix(ItemDrop item, ref bool cheated)
	{
		cheated = false;
		Sanitizer.Clean(item);
	}
}
[HarmonyPatch(typeof(ItemDrop), "SaveToZDO")]
internal static class ZdoWritePatch
{
	private static void Prefix(ItemData itemData)
	{
		Sanitizer.Clean(itemData);
	}
}
[HarmonyPatch(typeof(ItemDrop), "LoadFromZDO")]
internal static class ZdoReadPatch
{
	private static void Postfix(ItemData itemData)
	{
		Sanitizer.Clean(itemData);
	}
}
[HarmonyPatch(typeof(ItemDrop), "Pickup")]
internal static class PickupPatch
{
	private static void Prefix(ItemDrop __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ItemDrop), "GetHoverText")]
internal static class HoverTextPatch
{
	private static void Prefix(ItemDrop __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })]
internal static class TooltipPatch
{
	private static void Prefix(ItemData __instance)
	{
		Sanitizer.Clean(__instance);
	}
}
[HarmonyPatch(typeof(Container), "Save")]
internal static class ContainerSavePatch
{
	private static void Prefix(Container __instance)
	{
		Sanitizer.Clean(__instance.GetInventory());
	}
}
[HarmonyPatch(typeof(Container), "Load")]
internal static class ContainerLoadPatch
{
	private static void Postfix(Container __instance)
	{
		Sanitizer.Clean(__instance.GetInventory());
	}
}