Decompiled source of GAP Perfect Gear v1.0.0

plugins/GapPerfectGear.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using EpicLoot;
using EpicLoot.ShardStones;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("gap.perfectgear", "GAP Perfect Gear", "1.0.0")]
public class GapPerfectGear : BaseUnityPlugin
{
	private string testDirectory;

	private bool tested;

	private float nextCheck;

	private void Awake()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Expected O, but got Unknown
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		string[] commandLineArgs = Environment.GetCommandLineArgs();
		int num = Array.IndexOf(commandLineArgs, "-gapgearselftest");
		if (num >= 0 && num + 1 < commandLineArgs.Length)
		{
			testDirectory = commandLineArgs[num + 1];
		}
		new ConsoleCommand("perfectgear", "perfectgear sword|bow|trinket|both|all [empty] - Ancient endgame gear, host only", new ConsoleEvent(Run), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"perfectgear registered; host-only, no automatic inventory changes.");
	}

	private void Run(ConsoleEventArgs args)
	{
		try
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				throw new Exception("Only the local world host may use perfectgear.");
			}
			if (args.Args.Length < 2)
			{
				throw new Exception("Usage: perfectgear sword|bow|trinket|both|all [empty]");
			}
			string text = args.Args[1].ToLowerInvariant();
			if (text != "sword" && text != "bow" && text != "bowprecision" && text != "trinket" && text != "both" && text != "all")
			{
				throw new Exception("Choose sword, bow, trinket, both or all.");
			}
			bool flag = args.Args.Length == 3 && args.Args[2].ToLowerInvariant() == "empty";
			if (args.Args.Length > 3 || (args.Args.Length == 3 && !flag))
			{
				throw new Exception("Optional argument: empty");
			}
			List<ItemData> list = new List<ItemData>();
			switch (text)
			{
			case "sword":
			case "both":
			case "all":
				list.Add(Build("sword", flag));
				break;
			}
			switch (text)
			{
			case "bow":
			case "both":
			case "all":
				list.Add(Build("bow", flag));
				break;
			}
			if (text == "trinket" || text == "all")
			{
				list.Add(Build("trinket", flag));
			}
			if (text == "bowprecision")
			{
				list.Add(Build("bowprecision", flag));
			}
			Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
			if (inventory.GetEmptySlots() < list.Count)
			{
				throw new Exception("Free " + list.Count + " inventory slots first.");
			}
			foreach (ItemData item in list)
			{
				if (!inventory.AddItem(item))
				{
					throw new Exception("Inventory rejected item; no item was dropped.");
				}
			}
			args.Context.AddString("Created " + list.Count + " Ancient item(s), 8 maximally tempered effects, 4 " + (flag ? "empty" : "filled") + " sockets.");
		}
		catch (Exception ex)
		{
			args.Context.AddString("perfectgear: " + ex.Message);
			((BaseUnityPlugin)this).Logger.LogWarning((object)ex);
		}
	}

	private static ItemData Clone(string prefab)
	{
		GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
		if ((Object)(object)itemPrefab == (Object)null)
		{
			throw new Exception("Missing prefab: " + prefab);
		}
		ItemData val = itemPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
		val.m_dropPrefab = itemPrefab;
		val.m_stack = 1;
		val.m_equipped = false;
		val.m_customData = new Dictionary<string, string>(val.m_customData);
		return val;
	}

	private static ItemData Build(string choice, bool empty)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected O, but got Unknown
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Expected O, but got Unknown
		string prefab = ((choice == "trinket") ? "TrinketBloodGoldHealth" : ((choice == "sword") ? "SwordGold_FrostFire" : "BowGold_FrostFire"));
		ItemData val = Clone(prefab);
		val.m_quality = val.m_shared.m_maxQuality;
		MagicItem val2 = new MagicItem();
		val2.Rarity = (ItemRarity)5;
		val2.SocketCount = 4;
		MagicItem val3 = val2;
		string[] array = ((choice == "trinket") ? new string[8] { "IncreaseHealth", "IncreaseStamina", "ModifyStaminaRegen", "ModifyMovementSpeed", "CoinHoarder", "DodgeBuff", "DecreaseForsakenCooldown", "IncreaseEitr" } : ((choice == "sword") ? new string[8] { "AddSlashingDamage", "AddSwordsSkill", "ModifyAttackSpeed", "Executioner", "ModifyStaggerDamage", "SpellSword", "ChainLightning", "EitrLeech" } : new string[8] { "AddPiercingDamage", "AddBowsSkill", "QuickDraw", "ExplosiveArrows", "Executioner", "ModifyStaggerDamage", "ModifyBackstab", "ModifyProjectileSpeed" }));
		string[] array2 = array;
		foreach (string text in array2)
		{
			if (!API.GetAvailableEffectTypes(val, JsonConvert.SerializeObject((object)val3), 5).Contains(text))
			{
				throw new Exception("Effect no longer allowed: " + text);
			}
			MagicItemEffectDefinition val4 = MagicItemEffectDefinitions.AllDefinitions[text];
			ValueDef rollRange = MagicItemEffectDefinitions.GetRollRange(val4, val3.Rarity, val3.LegendaryID, (ValueDef)null);
			val3.Effects.Add(new MagicItemEffect(text, rollRange?.MaxValue ?? 1f));
		}
		MagicItemEffect[] array3 = val3.Effects.ToArray();
		foreach (MagicItemEffect val5 in array3)
		{
			val3.Effects.Remove(val5);
			bool flag = API.GetAvailableEffectTypes(val, JsonConvert.SerializeObject((object)val3), 5).Contains(val5.EffectType);
			val3.Effects.Add(val5);
			if (!flag)
			{
				throw new Exception("Conflicting effect: " + val5.EffectType);
			}
		}
		if (!API.ApplyMagicItemJson(val, JsonConvert.SerializeObject((object)val3)))
		{
			throw new Exception("Epic Loot rejected metadata.");
		}
		MaxTemper(val);
		if (!empty)
		{
			string[] array4 = ((choice == "trinket") ? new string[4] { "Orange", "Pink", "LightGreen", "DarkRed" } : ((choice == "sword") ? new string[4] { "Golden", "White", "Black", "Yagluth" } : new string[4] { "Golden", "Golden", "Stormcaller", "Yagluth" }));
			string[] array5 = array4;
			string text3 = default(string);
			foreach (string text2 in array5)
			{
				ItemData val6 = Clone(text2 + "_Ancient_ShardStone");
				if (!ShardSocketManager.CanSocket(val, val6, ref text3))
				{
					throw new Exception("Cannot socket " + text2 + ": " + text3);
				}
				if (!ShardSocketManager.AddShard(val, val6))
				{
					throw new Exception("Failed to socket " + text2);
				}
			}
		}
		val.m_durability = val.GetMaxDurability();
		return val;
	}

	private static void MaxTemper(ItemData item)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Expected O, but got Unknown
		MagicItem magicItem = ItemDataExtensions.GetMagicItem(item);
		if (!TemperMan.IsTemperableRarity(magicItem.Rarity))
		{
			throw new Exception("Ancient tempering is unavailable in the loaded Epic Loot configuration.");
		}
		string[] array = magicItem.Effects.Select((MagicItemEffect x) => x.EffectType).ToArray();
		foreach (string effectType in array)
		{
			int num2 = 0;
			while (true)
			{
				magicItem = ItemDataExtensions.GetMagicItem(item);
				MagicItemEffect val = magicItem.Effects.Single((MagicItemEffect x) => x.EffectType == effectType);
				if (!TemperData.IsTemperable(magicItem, val))
				{
					break;
				}
				TemperData val2 = new TemperData(item, effectType);
				if (float.IsNaN(val2.probability) || float.IsInfinity(val2.probability))
				{
					throw new Exception("Invalid tempering probability: " + effectType);
				}
				if (val2.probability <= 0f)
				{
					break;
				}
				if (num2 >= 4096)
				{
					throw new Exception("No finite tempering maximum found: " + effectType);
				}
				MagicItem updatedMagicItem = val2.GetUpdatedMagicItem();
				int num3 = updatedMagicItem.Effects.FindIndex((MagicItemEffect x) => x.EffectType == effectType);
				float effectValue = updatedMagicItem.Effects[num3].EffectValue;
				if (!(effectValue > val.EffectValue) || float.IsInfinity(effectValue))
				{
					throw new Exception("Invalid tempering increment: " + effectType);
				}
				if (!updatedMagicItem.TemperedEffectIndices.Contains(num3))
				{
					updatedMagicItem.TemperedEffectIndices.Add(num3);
				}
				if (!API.ApplyMagicItemJson(item, JsonConvert.SerializeObject((object)updatedMagicItem)))
				{
					throw new Exception("Epic Loot rejected tempered metadata: " + effectType);
				}
				num2++;
			}
		}
	}

	private static void ValidateTemper(ItemData item)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		MagicItem magicItem = ItemDataExtensions.GetMagicItem(item);
		for (int i = 0; i < magicItem.Effects.Count; i++)
		{
			MagicItemEffect val = magicItem.Effects[i];
			if (TemperData.IsTemperable(magicItem, val))
			{
				if (new TemperData(item, val.EffectType).probability > 0f)
				{
					throw new Exception("Effect can still be tempered: " + val.EffectType);
				}
				ValueDef temperRange = TemperData.GetTemperRange(magicItem, val);
				if (val.EffectValue > temperRange.MaxValue && !magicItem.TemperedEffectIndices.Contains(i))
				{
					throw new Exception("Missing temper history: " + val.EffectType);
				}
			}
		}
	}

	private void Update()
	{
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Expected O, but got Unknown
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Expected O, but got Unknown
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f3: Expected O, but got Unknown
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_020b: Expected O, but got Unknown
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Expected O, but got Unknown
		if (testDirectory == null || tested || Time.realtimeSinceStartup < nextCheck)
		{
			return;
		}
		nextCheck = Time.realtimeSinceStartup + 3f;
		if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ObjectDB.instance.GetItemPrefab("BowGold_BloodLightning") == (Object)null || MagicItemEffectDefinitions.AllDefinitions.Count == 0)
		{
			return;
		}
		tested = true;
		try
		{
			Directory.CreateDirectory(testDirectory);
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			string[] array = new string[7] { "SwordGold_BloodLightning", "BowGold_BloodLightning", "ArrowBloodGold", "THSwordGold_BloodLightning", "SwordGold_FrostFire", "BowGold_FrostFire", "TrinketBloodGoldHealth" };
			foreach (string text in array)
			{
				ItemData val = Clone(text);
				int maxQuality = val.m_shared.m_maxQuality;
				SharedData shared = val.m_shared;
				dictionary[text] = new
				{
					maxQuality = maxQuality,
					damage = shared.m_damages,
					damagePerLevel = shared.m_damagesPerLevel,
					attack = shared.m_attack,
					secondaryAttack = shared.m_secondaryAttack,
					availableEffects = API.GetAvailableEffectTypes(val, (string)null, 5)
				};
			}
			string path = Path.Combine(testDirectory, "probe.json");
			JsonSerializerSettings val2 = new JsonSerializerSettings();
			val2.ReferenceLoopHandling = (ReferenceLoopHandling)1;
			File.WriteAllText(path, JsonConvert.SerializeObject((object)dictionary, (Formatting)1, val2));
			string[] array2 = new string[4] { "sword", "bow", "bowprecision", "trinket" };
			foreach (string text2 in array2)
			{
				bool[] array3 = new bool[2] { true, false };
				foreach (bool flag in array3)
				{
					ItemData val3 = Build(text2, flag);
					ValidateTemper(val3);
					Inventory val4 = new Inventory("GAP isolated self-test", (Sprite)null, 4, 2);
					if (!val4.AddItem(val3))
					{
						throw new Exception("Test inventory add failed");
					}
					ZPackage val5 = new ZPackage();
					val4.Save(val5);
					Inventory val6 = new Inventory("GAP isolated restore", (Sprite)null, 4, 2);
					val6.Load(new ZPackage(val5.GetArray()));
					ItemData val7 = val6.GetAllItems().Single();
					string magicItemJson = API.GetMagicItemJson(val3);
					string magicItemJson2 = API.GetMagicItemJson(val7);
					if (magicItemJson != magicItemJson2 || val3.m_quality != val7.m_quality)
					{
						throw new Exception("Save/load mismatch: " + text2);
					}
					ValidateTemper(val7);
					File.WriteAllText(Path.Combine(testDirectory, text2 + (flag ? "-empty" : "-filled") + ".json"), magicItemJson2);
				}
			}
			File.WriteAllText(Path.Combine(testDirectory, "SUCCESS.txt"), "All presets: effect legality, tempering limits, socket rules, inventory serialization round-trip passed. No live player or save was accessed.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"GAP_SELFTEST_SUCCESS");
		}
		catch (Exception ex)
		{
			File.WriteAllText(Path.Combine(testDirectory, "FAILED.txt"), ex.ToString());
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
		if (Environment.GetCommandLineArgs().Contains("-gaptestquit"))
		{
			Application.Quit();
		}
	}
}