using System;
using System.Collections;
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.9.2.0")]
[assembly: AssemblyInformationalVersion("0.9.2")]
[assembly: AssemblyProduct("quaternion.reggie.modded")]
[assembly: AssemblyTitle("quaternion.reggie.modded")]
[assembly: AssemblyVersion("0.9.2.0")]
[BepInPlugin("quaternion.reggie.modded", "Trench Rat Reggie Modded", "0.9.2")]
public sealed class ReggieModded : BaseUnityPlugin
{
public sealed class ReggieBox : MonoBehaviour
{
}
public sealed class ReggieSpawn : MonoBehaviour
{
private IEnumerator Start()
{
yield return null;
NormalizeSpawn(((Component)this).gameObject, afterStart: true);
}
}
private sealed class AmmoInfo
{
public string id;
public string error;
public FireArmRoundType roundType;
public FireArmRoundClass roundClass;
public FVRObject round;
public FVRFireArm prefab;
public bool external;
public List<FVRObject> supplies = new List<FVRObject>();
public object Report()
{
return new
{
id = id,
error = error,
roundType = ((object)Unsafe.As<FireArmRoundType, FireArmRoundType>(ref roundType)/*cast due to .constrained prefix*/).ToString(),
ordinaryClass = ((object)Unsafe.As<FireArmRoundClass, FireArmRoundClass>(ref roundClass)/*cast due to .constrained prefix*/).ToString(),
round = (((Object)(object)round == (Object)null) ? null : round.ItemID),
external = external,
supplies = supplies.Select((FVRObject s) => s.ItemID).ToArray()
};
}
}
[HarmonyPatch]
private static class RewardScope
{
private static IEnumerable<MethodBase> TargetMethods()
{
yield return AccessTools.Method(typeof(TNH_Manager), "SpawnSosigLoot", (Type[])null, (Type[])null);
yield return AccessTools.Method(typeof(TNH_Manager), "SpawnBoxLoot", (Type[])null, (Type[])null);
}
private static void Postfix(TNH_Manager __instance, ref IEnumerator __result)
{
if (IsReggie(__instance))
{
__result = Scoped(__result);
}
}
}
[HarmonyPatch(typeof(TNH_SupplyPoint), "SpawnLoadoutEntry")]
private static class StarterScope
{
private static void Postfix(TNH_CharacterDef __1, ref IEnumerator __result)
{
if ((Object)(object)__1 != (Object)null && __1.UgcId == "quaternion.reggiemodded:WW1_Looter")
{
__result = Scoped(__result);
}
}
}
[HarmonyPatch(typeof(LootBox), "ConfigureFromID")]
private static class MarkBox
{
private static void Postfix(LootBox __instance)
{
if (spawnDepth > 0 && (Object)(object)((Component)__instance).GetComponent<ReggieBox>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<ReggieBox>();
}
}
}
[HarmonyPatch(typeof(LootBox), "OpenBox")]
private static class OpenBoxScope
{
private static void Prefix(LootBox __instance, out bool __state)
{
__state = (Object)(object)((Component)__instance).GetComponent<ReggieBox>() != (Object)null;
if (__state)
{
spawnDepth++;
}
}
private static Exception Finalizer(Exception __exception, bool __state)
{
if (__state)
{
spawnDepth--;
}
return __exception;
}
}
[HarmonyPatch(typeof(TNH_Manager), "GetSeededRandomAmmoObject")]
private static class StarterAmmo
{
private static bool Prefix(TNH_Manager __instance, FVRObject __0, int __1, int __2, ref FVRObject __result)
{
if (!IsReggie(__instance))
{
return true;
}
__result = Supply(__0, __1, __2, (int n) => __instance.GetRandomAmmoObjectIndexNext(__0, n));
return false;
}
}
[HarmonyPatch(typeof(TNH_Manager), "CanGetSmartLoot")]
private static class CanSupply
{
private static bool Prefix(TNH_Manager __instance, ref bool __result)
{
if (!IsReggie(__instance))
{
return true;
}
__result = KnownGuns(__instance).Any((FVRObject o) => ResolveAmmo(o).error == null);
return false;
}
}
[HarmonyPatch(typeof(TNH_Manager), "GetSmartAmmoObject")]
private static class SmartSupply
{
private static bool Prefix(TNH_Manager __instance, SosigLootGroup __0, ref FVRObject __result)
{
if (!IsReggie(__instance))
{
return true;
}
List<FVRObject> list = (from o in KnownGuns(__instance)
where ResolveAmmo(o).error == null
select o).ToList();
__result = ((list.Count == 0) ? null : Supply(list[Random.Range(0, list.Count)], (int)__0.MinMaxCapacity.x, (int)__0.MinMaxCapacity.y, (int n) => Random.Range(0, n)));
return false;
}
}
[HarmonyPatch(typeof(TNH_Utilities), "GetValidRandomRoundClass")]
private static class OrdinaryLoot
{
private unsafe static bool Prefix(FireArmRoundType __0, ref FireArmRoundClass __result)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
if (!AmmoContext)
{
return true;
}
if (!OrdinaryRound(__0, out var _, out __result))
{
throw new InvalidOperationException("Reggie: no ordinary round for " + ((object)(*(FireArmRoundType*)(&__0))/*cast due to .constrained prefix*/).ToString());
}
return false;
}
}
[HarmonyPatch(typeof(TNH_Utilities), "GenerateProcessedLootObject")]
private static class ProcessWeapon
{
private static bool Prefix(string __0, Vector3 __1, Quaternion __2, Vector2 __3, ref GameObject __result)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Invalid comparison between Unknown and I4
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
if (spawnDepth == 0)
{
return true;
}
if (!IM.OD.TryGetValue(__0, out var value))
{
return true;
}
if (!ammoCache.TryGetValue(__0, out var value2))
{
if ((int)value.Category != 1)
{
return true;
}
value2 = ResolveAmmo(value);
}
if (value2.error != null)
{
throw new InvalidOperationException("Reggie cannot spawn " + __0 + ": " + value2.error);
}
GameObject val = Object.Instantiate<GameObject>(((Component)value2.prefab).gameObject, __1, __2);
try
{
FVRFireArm component = val.GetComponent<FVRFireArm>();
((FVRPhysicalObject)component).ObjectWrapper = value;
int num = Random.Range((int)__3.x, (int)__3.y + 1);
if (value2.external && (Object)(object)component.Magazine == (Object)null)
{
Object.Instantiate<GameObject>(((AnvilAsset)value2.supplies.OrderBy((FVRObject o) => o.MagazineCapacity).First()).GetGameObject(), component.MagazineMountPos.position, component.MagazineMountPos.rotation).GetComponent<FVRFireArmMagazine>().Load(component);
}
if ((Object)(object)component.Magazine != (Object)null)
{
component.Magazine.ReloadMagWithTypeUpToAmount(value2.roundClass, num);
}
else
{
foreach (FVRFireArmChamber item in component.GetChambers().Take(Math.Max(0, num)))
{
item.Autochamber(value2.roundClass);
}
}
NormalizeSpawn(val);
__result = val;
return false;
}
catch
{
Object.Destroy((Object)(object)val);
throw;
}
}
}
[HarmonyPatch(typeof(TNH_Manager), "AddObjectToTrackedList")]
private static class NormalizeNewObject
{
private static void Prefix(GameObject __0)
{
if (spawnDepth > 0)
{
NormalizeSpawn(__0);
}
}
}
[HarmonyPatch(typeof(SosigWeaponPlayerInterface), "TryToConvertIntoRelevantAmmoObject")]
private static class ConversionScope
{
private static void Prefix(out bool __state)
{
__state = IsReggie(GM.TNH_Manager);
if (__state)
{
conversionDepth++;
}
}
private static Exception Finalizer(Exception __exception, bool __state)
{
if (__state)
{
conversionDepth--;
}
return __exception;
}
}
[HarmonyPatch(typeof(AM), "GetDefaultRoundClass")]
private static class ConversionClass
{
private static bool Prefix(FireArmRoundType __0, ref FireArmRoundClass __result)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
FVRObject round;
if (conversionDepth != 0)
{
return !OrdinaryRound(__0, out round, out __result);
}
return true;
}
}
[HarmonyPatch(typeof(FVRObject), "GetFirstCompatibleRound")]
private static class OrdinaryCartridge
{
private static bool Prefix(FVRObject __0, ref FVRObject __result)
{
if (!AmmoContext)
{
return true;
}
AmmoInfo ammoInfo = ResolveAmmo(__0);
__result = ammoInfo.round;
return false;
}
}
[HarmonyPatch(typeof(FVRObject), "GetRandomAmmoObject")]
private static class ConversionSupply
{
private static bool Prefix(FVRObject __0, int __2, int __3, ref FVRObject __result)
{
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Invalid comparison between Unknown and I4
if (conversionDepth == 0)
{
return true;
}
AmmoInfo ammoInfo = ResolveAmmo(__0);
__result = ((ammoInfo.error == null) ? Supply(__0, __2, __3, (int n) => Random.Range(0, n)) : ammoInfo.round);
if ((Object)(object)__result != (Object)null && (int)__result.Category != 2)
{
__result = ammoInfo.round;
}
return false;
}
}
public sealed class Catalog
{
public string version;
public List<Candidate> items;
public List<Candidate> excluded;
}
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);
}
}
[HarmonyPatch(typeof(TNH_Manager), "SpawnWeaponCase")]
private static class MarkStarterCase
{
private static void Postfix(TNH_Manager __instance, GameObject __result)
{
if (IsReggie(__instance) && !((Object)(object)__result == (Object)null))
{
__result.AddComponent<ReggieBox>();
__result.GetComponent<TNH_WeaponCrate>().M = __instance;
}
}
}
[HarmonyPatch(typeof(TNH_WeaponCrate), "SpawnItemsInCrate")]
private static class OpenStarterCase
{
private static void Postfix(TNH_WeaponCrate __instance, ref IEnumerator __result)
{
if ((Object)(object)((Component)__instance).GetComponent<ReggieBox>() != (Object)null)
{
__result = Scoped(SpawnStarterContents(__instance));
}
}
}
[HarmonyPatch(typeof(TNH_Manager), "SpawnEnemy")]
private static class EnemyUniform
{
private static void Postfix(TNH_Manager __instance, SosigEnemyTemplate __0, Sosig __result)
{
if (IsReggie(__instance) && (Object)(object)__0 != (Object)null && __0.UgcId.StartsWith("quaternion.reggiemodded:") && (Object)(object)__result != (Object)null)
{
LightenUniform(((Component)__result).gameObject);
}
}
}
[HarmonyPatch(typeof(TNH_CharacterDisplay), "OnLoadComplete")]
private static class MenuUniform
{
private static void Postfix(TNH_CharacterDisplay __instance, List<FVRPhysicalObject> __0)
{
TNH_CharacterDef val = default(TNH_CharacterDef);
if (__0 == null || !UgcManager.TryGetItem<TNH_CharacterDef>("quaternion.reggiemodded:WW1_Looter", ref val) || (Object)(object)val.DisplayCharacter == (Object)null || AccessTools.Field(typeof(TNH_CharacterDisplay), "_displayedFile").GetValue(__instance) != val.DisplayCharacter.vf)
{
return;
}
foreach (FVRPhysicalObject item in __0)
{
if ((Object)(object)item != (Object)null)
{
LightenUniform(((Component)item).gameObject);
}
}
}
}
[ThreadStatic]
private static int spawnDepth;
[ThreadStatic]
private static int conversionDepth;
private static readonly Dictionary<string, AmmoInfo> ammoCache = new Dictionary<string, AmmoInfo>();
private static int indexedCount = -1;
private static int indexedRounds = -1;
private static List<FVRObject> loaders = new List<FVRObject>();
private static HashSet<string> excludedAmmo = new HashSet<string>();
private static readonly HashSet<string> ordinarySP = new HashSet<string>(new string[12]
{
"106x25mmRCartridgeSP", "45LongColtCartridgeSP", "577_450_MartiniHenry", "44Russian", "8mmOrdnance", "107558mmR", "115x60mmr", "8mmGasser", "9x20mm.Billiam", "a113x36mmR",
"primevr.11mm.delvigne", "potatoes11x58mmRSP"
});
private static readonly Dictionary<string, string[]> bayonetRecipes = new Dictionary<string, string[]>
{
{
"MosinM1891",
new string[1] { "BayonetMosin" }
},
{
"Springfield1903",
new string[1] { "Ult_M1905_Bayonet" }
},
{
"EnfieldP14.Muzz",
new string[1] { "EnfieldP14Bayonet.Muzz" }
},
{
"USM1917.Muzz",
new string[1] { "EnfieldP14Bayonet.Muzz" }
},
{
"Ult_Ross_Rifle_MK3",
new string[1] { "Ult_M1908_Bayonet" }
},
{
"Werndl.Billiam",
new string[1] { "WerndlBayo.Billiam" }
},
{
"RifBALeeEnfieldMkIII",
new string[2] { "P1907", "BayonetLeeEnfield" }
},
{
"Volks_CLLEEnfield_Rifle",
new string[2] { "P1907", "BayonetLeeEnfield" }
},
{
"Volks_MLE_Rifle",
new string[2] { "P1907", "BayonetLeeEnfield" }
},
{
"Volks_Win1895_3006",
new string[1] { "Volks_Win1895_Bayonet" }
},
{
"Volks_Win1895_762R",
new string[1] { "Volks_Win1895_Bayonet" }
},
{
"Ult_M1903",
new string[1] { "Ult_M1905_Bayonet" }
}
};
private static readonly Dictionary<string, string[]> scopeRecipes = new Dictionary<string, string[]>
{
{
"Volks_Carcano1981Rifle",
new string[1] { "Volks_Carcano1981Scope" }
},
{
"Ult_Gew98 Sniper",
new string[1] { "Ult_G98_Scope" }
}
};
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 static bool AmmoContext
{
get
{
if (spawnDepth <= 0)
{
return conversionDepth > 0;
}
return true;
}
}
private static bool IsReggie(TNH_Manager m)
{
if ((Object)(object)m != (Object)null && (Object)(object)m.C != (Object)null)
{
return m.C.UgcId == "quaternion.reggiemodded:WW1_Looter";
}
return false;
}
private static void IndexAmmo()
{
if (indexedCount != IM.OD.Count || indexedRounds != AM.SRoundDisplayDataDic.Count)
{
indexedCount = IM.OD.Count;
indexedRounds = AM.SRoundDisplayDataDic.Count;
ammoCache.Clear();
excludedAmmo = new HashSet<string>((catalog.excluded ?? new List<Candidate>()).Select((Candidate c) => c.id));
HashSet<string> declaredAmmo = new HashSet<string>(from c in catalog.items
where c.pool == "Ammo"
select c.id);
loaders = IM.OD.Values.Where((FVRObject o) => (Object)(object)o != (Object)null && !excludedAmmo.Contains(o.ItemID) && ((int)o.Category == 2 || (int)o.Category == 3 || (int)o.Category == 6 || declaredAmmo.Contains(o.ItemID))).OrderBy<FVRObject, string>((FVRObject o) => o.ItemID, StringComparer.Ordinal).ToList();
}
}
private static bool OrdinaryRound(FireArmRoundType type, out FVRObject round, out FireArmRoundClass cls)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Invalid comparison between Unknown and I4
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Expected I4, but got Unknown
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Expected I4, but got Unknown
round = null;
cls = (FireArmRoundClass)1;
if (!AM.SRoundDisplayDataDic.TryGetValue(type, out var value) || (Object)(object)value == (Object)null || value.Classes == null)
{
return false;
}
FireArmRoundClass[] array = (FireArmRoundClass[])(object)new FireArmRoundClass[8]
{
(FireArmRoundClass)1,
default(FireArmRoundClass),
(FireArmRoundClass)8,
(FireArmRoundClass)13,
(FireArmRoundClass)14,
(FireArmRoundClass)27,
(FireArmRoundClass)18,
(FireArmRoundClass)19
};
DisplayDataClass[] classes;
foreach (FireArmRoundClass val in array)
{
classes = value.Classes;
foreach (DisplayDataClass val2 in classes)
{
if (val2.Class == val && (Object)(object)val2.ObjectID != (Object)null && !excludedAmmo.Contains(val2.ObjectID.ItemID))
{
round = val2.ObjectID;
cls = (FireArmRoundClass)(int)val;
return true;
}
}
}
classes = value.Classes;
foreach (DisplayDataClass val3 in classes)
{
if ((int)val3.Class == 3 && (Object)(object)val3.ObjectID != (Object)null && ordinarySP.Contains(val3.ObjectID.ItemID))
{
round = val3.ObjectID;
cls = (FireArmRoundClass)(int)val3.Class;
return true;
}
}
return false;
}
private static AmmoInfo ResolveAmmo(FVRObject item)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_0300: Unknown result type (might be due to invalid IL or missing references)
//IL_0311: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
//IL_031a: Unknown result type (might be due to invalid IL or missing references)
//IL_032b: Unknown result type (might be due to invalid IL or missing references)
//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
IndexAmmo();
if (ammoCache.TryGetValue(item.ItemID, out var value))
{
return value;
}
value = new AmmoInfo
{
id = item.ItemID
};
try
{
value.prefab = ((AnvilAsset)item).GetGameObject().GetComponent<FVRFireArm>();
if ((Object)(object)value.prefab == (Object)null)
{
value.error = "Registered item is not a playable firearm prefab.";
return value;
}
FVRFireArm gun = value.prefab;
value.roundType = gun.RoundType;
if (!OrdinaryRound(gun.RoundType, out value.round, out value.roundClass))
{
value.error = "No registered ordinary round for actual prefab caliber " + ((object)Unsafe.As<FireArmRoundType, FireArmRoundType>(ref gun.RoundType)/*cast due to .constrained prefix*/).ToString();
return value;
}
value.external = (int)gun.MagazineType != 0 && (gun.UsesMagazines || gun.UsesBeltBoxes) && ((Object)(object)gun.Magazine == (Object)null || !gun.Magazine.IsIntegrated);
if (value.external)
{
List<FVRObject> explicitMags = item.CompatibleMagazines ?? new List<FVRObject>();
foreach (FVRObject item2 in loaders.Where((FVRObject o) => explicitMags.Contains(o) || ((int)gun.MagazineType != 0 && o.MagazineType == gun.MagazineType) || (item.ItemID == "RifBRRSC" && o.ItemID == "MagRSCClip")))
{
FVRFireArmMagazine component = ((AnvilAsset)item2).GetGameObject().GetComponent<FVRFireArmMagazine>();
if ((Object)(object)component != (Object)null && !component.IsIntegrated && component.RoundType == gun.RoundType && component.MagazineType == gun.MagazineType)
{
value.supplies.Add(item2);
}
}
if (value.supplies.Count == 0)
{
value.error = "No detachable magazine/en-bloc loader for actual prefab magazine type " + ((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref gun.MagazineType)/*cast due to .constrained prefix*/).ToString();
}
}
else if (gun.UsesClips)
{
List<FVRObject> explicitClips = item.CompatibleClips ?? new List<FVRObject>();
foreach (FVRObject item3 in loaders.Where((FVRObject o) => explicitClips.Contains(o) || ((int)gun.ClipType != 0 && o.ClipType == gun.ClipType)))
{
FVRFireArmClip component2 = ((AnvilAsset)item3).GetGameObject().GetComponent<FVRFireArmClip>();
if ((Object)(object)component2 != (Object)null && component2.RoundType == gun.RoundType && component2.ClipType == gun.ClipType)
{
value.supplies.Add(item3);
}
}
if (value.supplies.Count == 0)
{
value.error = "No compatible clip for actual prefab clip type " + ((object)Unsafe.As<FireArmClipType, FireArmClipType>(ref gun.ClipType)/*cast due to .constrained prefix*/).ToString();
}
}
else if (item.CompatibleSpeedLoaders != null)
{
foreach (FVRObject compatibleSpeedLoader in item.CompatibleSpeedLoaders)
{
if (!((Object)(object)compatibleSpeedLoader == (Object)null) && !excludedAmmo.Contains(compatibleSpeedLoader.ItemID))
{
Speedloader component3 = ((AnvilAsset)compatibleSpeedLoader).GetGameObject().GetComponent<Speedloader>();
if ((Object)(object)component3 != (Object)null && component3.Chambers.Count > 0 && component3.Chambers.All((SpeedloaderChamber c) => c.Type == gun.RoundType))
{
value.supplies.Add(compatibleSpeedLoader);
}
}
}
}
if (value.supplies.Count == 0 && value.error == null)
{
value.supplies.Add(value.round);
}
}
catch (Exception ex)
{
value.error = "Prefab/ammo inspection failed: " + ex.GetType().Name + ": " + ex.Message;
}
finally
{
ammoCache[item.ItemID] = value;
}
return value;
}
private static FVRObject Supply(FVRObject gun, int min, int max, Func<int, int> random)
{
AmmoInfo ammoInfo = ResolveAmmo(gun);
if (ammoInfo.error != null)
{
return null;
}
List<FVRObject> list = ammoInfo.supplies.Where((FVRObject o) => (int)o.Category != 2 || ((min < 0 || o.MagazineCapacity >= min) && (max < 0 || o.MagazineCapacity <= max))).ToList();
if (list.Count == 0)
{
list = ammoInfo.supplies;
}
return list[random(list.Count)];
}
private static IEnumerator Scoped(IEnumerator source)
{
try
{
while (true)
{
object obj = null;
spawnDepth++;
bool flag;
try
{
flag = source.MoveNext();
if (flag)
{
obj = source.Current;
}
}
finally
{
spawnDepth--;
}
if (flag)
{
yield return (!(obj is IEnumerator source2)) ? obj : Scoped(source2);
continue;
}
break;
}
}
finally
{
if (source is IDisposable disposable)
{
disposable.Dispose();
}
}
}
private static IEnumerable<FVRObject> KnownGuns(TNH_Manager m)
{
return from o in (List<FVRPhysicalObject>)AccessTools.Field(typeof(TNH_Manager), "m_knownObjs").GetValue(m)
where (Object)(object)o != (Object)null && o is FVRFireArm && (Object)(object)o.ObjectWrapper != (Object)null
select o.ObjectWrapper;
}
private static void NormalizeSpawn(GameObject g, bool afterStart = false)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)g == (Object)null || (!afterStart && (Object)(object)g.GetComponent<ReggieSpawn>() != (Object)null))
{
return;
}
if (!afterStart)
{
g.AddComponent<ReggieSpawn>();
}
FVRFireArmMagazine[] componentsInChildren = g.GetComponentsInChildren<FVRFireArmMagazine>(true);
foreach (FVRFireArmMagazine val in componentsInChildren)
{
if (val.m_numRounds > 0 && OrdinaryRound(val.RoundType, out var _, out var cls))
{
val.ReloadMagWithTypeUpToAmount(cls, val.m_numRounds);
}
}
FVRFireArmClip[] componentsInChildren2 = g.GetComponentsInChildren<FVRFireArmClip>(true);
foreach (FVRFireArmClip val2 in componentsInChildren2)
{
if (OrdinaryRound(val2.RoundType, out var _, out var cls2))
{
val2.ReloadClipWithTypeUpToAmount(cls2, val2.m_numRounds);
}
}
FVRFireArmChamber[] componentsInChildren3 = g.GetComponentsInChildren<FVRFireArmChamber>(true);
foreach (FVRFireArmChamber val3 in componentsInChildren3)
{
if (val3.IsFull && !val3.IsSpent && OrdinaryRound(val3.RoundType, out var _, out var cls3))
{
val3.Autochamber(cls3);
}
}
SpeedloaderChamber[] componentsInChildren4 = g.GetComponentsInChildren<SpeedloaderChamber>(true);
foreach (SpeedloaderChamber val4 in componentsInChildren4)
{
if (val4.IsLoaded && !val4.IsSpent && OrdinaryRound(val4.Type, out var _, out var cls4))
{
val4.Load(cls4, false);
}
}
FVRFireArm component = g.GetComponent<FVRFireArm>();
if ((Object)(object)component != (Object)null)
{
AttachBayonet(component);
AttachScope(component);
}
}
private static void AttachBayonet(FVRFireArm gun)
{
if (!((Object)(object)((FVRPhysicalObject)gun).ObjectWrapper == (Object)null) && !((Object)(object)gun.CurrentAttachableMeleeWeapon != (Object)null) && bayonetRecipes.TryGetValue(((FVRPhysicalObject)gun).ObjectWrapper.ItemID, out var value))
{
AttachMatchingAttachment(gun, value, "Bayonet");
}
}
private static void AttachScope(FVRFireArm gun)
{
if (!((Object)(object)((FVRPhysicalObject)gun).ObjectWrapper == (Object)null) && scopeRecipes.TryGetValue(((FVRPhysicalObject)gun).ObjectWrapper.ItemID, out var value))
{
AttachMatchingAttachment(gun, value, "Scope");
}
}
private static void AttachMatchingAttachment(FVRFireArm gun, string[] candidates, string kind)
{
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
if (((Component)gun).GetComponentsInChildren<FVRFireArmAttachment>(true).Any((FVRFireArmAttachment a) => (Object)(object)a.curMount != (Object)null && (Object)(object)((FVRPhysicalObject)a).ObjectWrapper != (Object)null && candidates.Contains(((FVRPhysicalObject)a).ObjectWrapper.ItemID)))
{
return;
}
string[] array = candidates;
foreach (string text in array)
{
if (!IM.OD.TryGetValue(text, out var value))
{
continue;
}
GameObject val = null;
try
{
FVRFireArmAttachment prefab = ((AnvilAsset)value).GetGameObject().GetComponent<FVRFireArmAttachment>();
if ((Object)(object)prefab == (Object)null)
{
continue;
}
FVRFireArmAttachmentMount val2 = ((IEnumerable<FVRFireArmAttachmentMount>)((Component)gun).GetComponentsInChildren<FVRFireArmAttachmentMount>(true)).FirstOrDefault((Func<FVRFireArmAttachmentMount, bool>)((FVRFireArmAttachmentMount m) => m.Type == prefab.Type && ((Component)m).gameObject.activeInHierarchy && m.isMountableOn(prefab)));
if ((Object)(object)val2 == (Object)null)
{
continue;
}
val = Object.Instantiate<GameObject>(((Component)prefab).gameObject, val2.Point_Front.position, ((Component)val2).transform.rotation);
FVRFireArmAttachment component = val.GetComponent<FVRFireArmAttachment>();
((FVRPhysicalObject)component).ObjectWrapper = value;
component.AttachToMount(val2, false);
if ((Object)(object)component.curMount != (Object)(object)val2)
{
throw new InvalidOperationException("Attachment did not remain on its mount.");
}
((BaseUnityPlugin)instance).Logger.LogInfo((object)(kind + " attached: " + ((FVRPhysicalObject)gun).ObjectWrapper.ItemID + " -> " + text));
break;
}
catch (Exception ex)
{
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
((BaseUnityPlugin)instance).Logger.LogWarning((object)(kind + " skipped for " + ((FVRPhysicalObject)gun).ObjectWrapper.ItemID + ": " + ex.Message));
}
}
}
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_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0452: Unknown result type (might be due to invalid IL or missing references)
//IL_0457: Unknown result type (might be due to invalid IL or missing references)
//IL_0462: Unknown result type (might be due to invalid IL or missing references)
//IL_0469: Unknown result type (might be due to invalid IL or missing references)
//IL_0471: Unknown result type (might be due to invalid IL or missing references)
//IL_0481: Expected O, but got Unknown
//IL_042f: 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, out var reason))
{
list2.Add(new { item.id, reason });
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>();
foreach (string item2 in value3)
{
if (!IsGunPool(text) || (IM.OD.TryGetValue(item2, out var value4) && HasAmmo(value4, out var _)))
{
list3.Add(item2);
}
else
{
list2.Add(new
{
id = item2,
reason = "Native fallback has no usable ordinary ammunition."
});
}
}
if (dictionary.TryGetValue(text, out var value5))
{
foreach (string item3 in value5)
{
if (!list3.Contains(item3))
{
list3.Add(item3);
}
}
}
val.IDOverride = list3;
}
TNH_LootPoolDef equipPool = character.SosigLootTable.LootGroup_Boxes.EquipPool;
if (!originalPools.TryGetValue(equipPool, out var value6))
{
originalPools.Add(equipPool, value6 = new List<PoolEntry>(equipPool.Entries));
}
equipPool.Entries = new List<PoolEntry>(value6);
if (dictionary.TryGetValue("Equipment", out var value7) && value7.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 = value7;
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,
ammo = ammoCache.Values.Select((AmmoInfo a) => a.Report()).ToArray(),
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, out string reason)
{
AmmoInfo ammoInfo = ResolveAmmo(gun);
reason = ammoInfo.error;
return reason == null;
}
private static bool IsGunPool(string pool)
{
switch (pool)
{
default:
return pool == "Support";
case "Sidearms":
case "Rifles":
case "Shotguns":
return true;
}
}
private static T CaseField<T>(TNH_WeaponCrate crate, string name)
{
return (T)AccessTools.Field(typeof(TNH_WeaponCrate), name).GetValue(crate);
}
private static GameObject StarterObject(TNH_WeaponCrate crate, FVRObject item, Transform point)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(((AnvilAsset)item).GetGameObject(), point.position, point.rotation);
FVRFireArm component = val.GetComponent<FVRFireArm>();
if ((Object)(object)component != (Object)null)
{
((FVRPhysicalObject)component).ObjectWrapper = item;
}
NormalizeSpawn(val);
if ((Object)(object)crate.M != (Object)null)
{
crate.M.AddObjectToTrackedList(val);
}
return val;
}
private static IEnumerator SpawnStarterContents(TNH_WeaponCrate crate)
{
FVRObject gun = CaseField<FVRObject>(crate, "m_storedObject_gun");
if ((Object)(object)gun != (Object)null)
{
yield return ((AnvilAsset)gun).GetGameObjectAsync();
if ((int)GM.TNHOptions.UseVaultGunsMode == 1 && VaultSystem.DoesVaultFileExistWithFVRObjectAsPrimaryObjectThatHasAttachments(gun))
{
VaultSystem.SpawnRandomVaultSavedVersionOfGunWithAtLeastOneAttachment(gun, ((Component)crate).transform);
}
else
{
StarterObject(crate, gun, crate.Point_Gun);
}
}
string[] array = new string[2] { "A", "B" };
foreach (string suffix in array)
{
FVRObject extra = CaseField<FVRObject>(crate, "m_storedObject_attach" + suffix);
if (!((Object)(object)extra == (Object)null) && !excludedAmmo.Contains(extra.ItemID))
{
yield return ((AnvilAsset)extra).GetGameObjectAsync();
StarterObject(crate, extra, crate.Points_Attachment[(!(suffix == "A")) ? 1 : 0]);
}
}
FVRObject ammo = CaseField<FVRObject>(crate, "m_magazineClipSpeedLoaderRound");
if ((Object)(object)ammo == (Object)null)
{
yield break;
}
yield return ((AnvilAsset)ammo).GetGameObjectAsync();
FVRFireArmRound component = ((AnvilAsset)ammo).GetGameObject().GetComponent<FVRFireArmRound>();
if ((Object)(object)component != (Object)null && CaseField<bool>(crate, "m_spawnAmmoAsBox"))
{
GameObject val = Object.Instantiate<GameObject>(AM.GetAmmoBox(component.RoundType), crate.Points_MagClipSpeedloader[0].position, Quaternion.identity);
val.GetComponent<CartridgeBox>().ConfigureShapeForRoundType(component.RoundType, component.RoundClass);
if ((Object)(object)crate.M != (Object)null)
{
crate.M.AddObjectToTrackedList(val);
}
}
else
{
List<Transform> list = (((Object)(object)component != (Object)null) ? crate.Points_Cartridge : crate.Points_MagClipSpeedloader);
int num = CaseField<int>(crate, "m_numClipSpeedLoaderRound");
for (int j = 0; j < num; j++)
{
StarterObject(crate, ammo, list[j % list.Count]);
}
}
}
private static void LightenUniform(GameObject root)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Expected O, but got Unknown
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)root == (Object)null)
{
return;
}
Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
foreach (Renderer val in componentsInChildren)
{
if (((Object)val).name.StartsWith("Sosigaccesory_ww2_") && ((Object)val).name.Contains("_grey"))
{
MaterialPropertyBlock val2 = new MaterialPropertyBlock();
val.GetPropertyBlock(val2);
val2.SetColor("_Color", Color.white);
val.SetPropertyBlock(val2);
}
}
}
}