Decompiled source of Trench Rat Reggie Modded v0.5.0

plugins/TrenchRatReggieModded/quaternion.reggie.modded.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using FistVR;
using FistVR.Ugc;
using HarmonyLib;
using UnityEngine;
using Valve.Newtonsoft.Json;
using Valve.Newtonsoft.Json.Linq;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("quaternion.reggie.modded")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.0.0")]
[assembly: AssemblyInformationalVersion("0.5.0")]
[assembly: AssemblyProduct("quaternion.reggie.modded")]
[assembly: AssemblyTitle("quaternion.reggie.modded")]
[assembly: AssemblyVersion("0.5.0.0")]
[BepInPlugin("quaternion.reggie.modded", "Trench Rat Reggie Modded", "0.5.0")]
public sealed class ReggieModded : BaseUnityPlugin
{
	public sealed class Catalog
	{
		public string version;

		public List<Candidate> items;
	}

	public sealed class Candidate
	{
		public string id;

		public string pool;

		public string package;

		public string name;

		public List<string> requiredPeerIds;
	}

	[HarmonyPatch(typeof(UgcManager), "DiscoverFromLocalStudio")]
	private static class Discover
	{
		private static void Postfix(List<IUgcItem> __0)
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			Dictionary<string, UgcModule> dictionary = (Dictionary<string, UgcModule>)AccessTools.Field(typeof(UgcManager), "_contentModulesById").GetValue(null);
			if (dictionary.ContainsKey("quaternion.reggiemodded"))
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)"Another copy of the modded module was found; using that copy without registering a duplicate.");
				return;
			}
			string text = Path.Combine(Path.Combine(directory, "studio"), "quaternion.reggiemodded");
			JObject val = JObject.Parse(File.ReadAllText(Path.Combine(text, "module.json")));
			if ((string)val["Id"] != "quaternion.reggiemodded")
			{
				throw new InvalidOperationException("Incorrect bundled module ID.");
			}
			MethodInfo obj = AccessTools.Method(typeof(UgcManager), "DiscoverFromDirectoryRecurse", new Type[5]
			{
				typeof(List<IUgcItem>),
				typeof(UgcModule),
				typeof(string),
				typeof(string),
				typeof(bool)
			}, (Type[])null) ?? throw new MissingMethodException("Unsupported H3VR native discovery API.");
			UgcModule val2 = new UgcModule("quaternion.reggiemodded", (string)val["Name"]);
			dictionary.Add("quaternion.reggiemodded", val2);
			obj.Invoke(null, new object[5] { __0, val2, text, text, false });
			((BaseUnityPlugin)instance).Logger.LogInfo((object)"Registered standalone native modded character from this profile.");
		}
	}

	[HarmonyPatch(typeof(TNH_LevelLoader), "ValidateCharacter")]
	private static class Validate
	{
		private static void Prefix(TNH_CharacterDef __0)
		{
			Prepare(__0);
		}
	}

	[HarmonyPatch(typeof(TNH_Manager), "InitTables")]
	private static class Initialize
	{
		private static void Prefix(TNH_Manager __instance)
		{
			Prepare(__instance.C);
		}
	}

	public const string Module = "quaternion.reggiemodded";

	public const string Character = "quaternion.reggiemodded:WW1_Looter";

	private static ReggieModded instance;

	private static string directory;

	private static Catalog catalog;

	private static readonly Dictionary<ObjectTableDef, List<string>> originals = new Dictionary<ObjectTableDef, List<string>>();

	private static readonly Dictionary<TNH_LootPoolDef, List<PoolEntry>> originalPools = new Dictionary<TNH_LootPoolDef, List<PoolEntry>>();

	private static ObjectTableDef equipment;

	private static readonly Dictionary<TNH_CharacterDef, List<OTagEra>> originalEras = new Dictionary<TNH_CharacterDef, List<OTagEra>>();

	private static readonly Dictionary<TNH_CharacterDef, List<OTagSet>> originalSets = new Dictionary<TNH_CharacterDef, List<OTagSet>>();

	private static string lastReport;

	private void Awake()
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		instance = this;
		directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		catalog = JsonConvert.DeserializeObject<Catalog>(File.ReadAllText(Path.Combine(directory, "optional-items.json")));
		if (catalog == null || catalog.items == null)
		{
			throw new InvalidOperationException("Optional item catalog is missing.");
		}
		new Harmony("quaternion.reggie.modded").PatchAll(typeof(ReggieModded).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Optional catalog loaded: " + catalog.items.Count + " exact IDs. Missing item packs are optional."));
	}

	public static void Prepare(TNH_CharacterDef character)
	{
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0406: Unknown result type (might be due to invalid IL or missing references)
		//IL_0416: Expected O, but got Unknown
		//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)character == (Object)null || character.UgcId != "quaternion.reggiemodded:WW1_Looter")
		{
			return;
		}
		Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.Ordinal);
		List<object> list = new List<object>();
		List<object> list2 = new List<object>();
		if (!originalEras.ContainsKey(character))
		{
			originalEras.Add(character, new List<OTagEra>(character.ValidAmmoEras));
		}
		if (!originalSets.ContainsKey(character))
		{
			originalSets.Add(character, new List<OTagSet>(character.ValidAmmoSets));
		}
		HashSet<OTagEra> hashSet = new HashSet<OTagEra>(originalEras[character]);
		HashSet<OTagSet> hashSet2 = new HashSet<OTagSet>(originalSets[character]);
		foreach (Candidate item in catalog.items)
		{
			if (!IM.OD.TryGetValue(item.id, out var value) || (Object)(object)value == (Object)null || (item.requiredPeerIds != null && !item.requiredPeerIds.Any((string id) => IM.OD.ContainsKey(id))))
			{
				continue;
			}
			if (IsGunPool(item.pool) && !HasAmmo(value))
			{
				list2.Add(new
				{
					id = item.id,
					reason = "No registered compatible ammunition; install this weapon's dependencies."
				});
				continue;
			}
			hashSet.Add(value.TagEra);
			hashSet2.Add(value.TagSet);
			if (item.pool != "Ammo")
			{
				if (!dictionary.TryGetValue(item.pool, out var value2))
				{
					dictionary.Add(item.pool, value2 = new List<string>());
				}
				if (!value2.Contains(item.id))
				{
					value2.Add(item.id);
				}
			}
			list.Add(new { item.id, item.pool, item.package });
		}
		character.ValidAmmoEras = hashSet.ToList();
		character.ValidAmmoSets = hashSet2.ToList();
		string[] array = new string[6] { "Sidearms", "Rifles", "Shotguns", "Support", "Melee", "Grenades" };
		ObjectTableDef val = default(ObjectTableDef);
		foreach (string text in array)
		{
			if (!UgcManager.TryGetItem<ObjectTableDef>("quaternion.reggiemodded:WW1_" + text, ref val))
			{
				throw new InvalidOperationException("Bundled pool missing: " + text);
			}
			if (!originals.TryGetValue(val, out var value3))
			{
				originals.Add(val, value3 = new List<string>(val.IDOverride));
			}
			List<string> list3 = new List<string>(value3);
			if (dictionary.TryGetValue(text, out var value4))
			{
				foreach (string item2 in value4)
				{
					if (!list3.Contains(item2))
					{
						list3.Add(item2);
					}
				}
			}
			val.IDOverride = list3;
		}
		TNH_LootPoolDef equipPool = character.SosigLootTable.LootGroup_Boxes.EquipPool;
		if (!originalPools.TryGetValue(equipPool, out var value5))
		{
			originalPools.Add(equipPool, value5 = new List<PoolEntry>(equipPool.Entries));
		}
		equipPool.Entries = new List<PoolEntry>(value5);
		if (dictionary.TryGetValue("Equipment", out var value6) && value6.Count > 0)
		{
			if ((Object)(object)equipment == (Object)null)
			{
				equipment = ScriptableObject.CreateInstance<ObjectTableDef>();
				((Object)equipment).name = "Reggie optional equipment";
				equipment.UgcId = "quaternion.reggiemodded:OptionalEquipment";
				equipment.Category = (ObjectCategory)9;
				equipment.UseIDListOverride = true;
			}
			equipment.IDOverride = value6;
			equipPool.Entries.Add(new PoolEntry
			{
				TableDef = equipment,
				MinLevelAppears = 0,
				MaxLevelAppears = 99,
				Rarity = 1f
			});
		}
		string text2 = JsonConvert.SerializeObject((object)new
		{
			character = "quaternion.reggiemodded:WW1_Looter",
			catalog = catalog.version,
			supportedIds = catalog.items.Count,
			registered = list,
			rejected = list2,
			pools = dictionary.ToDictionary((KeyValuePair<string, List<string>> p) => p.Key, (KeyValuePair<string, List<string>> p) => p.Value.Count)
		}, (Formatting)1);
		if (text2 != lastReport)
		{
			((BaseUnityPlugin)instance).Logger.LogInfo((object)("Reggie optional items: " + list.Count + " registered; " + list2.Count + " missing ammo. Vanilla fallbacks retained."));
			try
			{
				File.WriteAllText(Path.Combine(Paths.ConfigPath, "quaternion.reggie.modded.audit.json"), text2);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)("Could not write item report: " + ex.Message));
			}
			lastReport = text2;
		}
	}

	private static bool HasAmmo(FVRObject gun)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		if ((int)gun.MagazineType != 0 && (!IM.CompatMags.TryGetValue(gun.MagazineType, out var value) || value == null || value.Count == 0))
		{
			return false;
		}
		if (AM.SRoundDisplayDataDic.TryGetValue(gun.RoundType, out var value2) && (Object)(object)value2 != (Object)null && value2.Classes != null && value2.Classes.Length != 0)
		{
			return value2.Classes.Any((DisplayDataClass c) => (Object)(object)c.ObjectID != (Object)null);
		}
		return false;
	}

	private static bool IsGunPool(string pool)
	{
		switch (pool)
		{
		default:
			return pool == "Support";
		case "Sidearms":
		case "Rifles":
		case "Shotguns":
			return true;
		}
	}
}