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 System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using FistVR;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("GunGameProgressionsMetadataExporter")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.6.0")]
[assembly: AssemblyInformationalVersion("1.3.6")]
[assembly: AssemblyProduct("GunGameProgressionsMetadataExporter")]
[assembly: AssemblyTitle("GunGameProgressionsMetadataExporter")]
[assembly: AssemblyVersion("1.3.6.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 HLin.GunGameProgressions
{
public sealed class EnemySpawnWeight
{
public int Value { get; private set; }
public int Multiplicity { get; private set; }
public EnemySpawnWeight(int value, int multiplicity)
{
Value = value;
Multiplicity = multiplicity;
}
}
public static class EnemyWeightPolicy
{
private enum OperatorTier
{
None,
Standard,
Advanced,
Apex
}
public static EnemySpawnWeight Resolve(RuntimeEnemyEntry enemy)
{
if (enemy == null)
{
throw new ArgumentNullException("enemy");
}
int value = EnemyValue(enemy);
return new EnemySpawnWeight(value, SpawnMultiplicity(enemy, value));
}
private static int EnemyValue(RuntimeEnemyEntry enemy)
{
switch (GetOperatorTier(enemy.EnemyNameString))
{
case OperatorTier.Standard:
return 2;
case OperatorTier.Advanced:
case OperatorTier.Apex:
return 1;
default:
switch (enemy.EnemyNameString)
{
case "RW_Rot":
return 8;
case "M_Swat_Scout":
return 5;
case "M_MercWiener_Riflewiener":
return 3;
case "M_Swat_SpecOps":
return 2;
case "M_Swat_Heavy":
return 1;
default:
if (!IsCoreEnemyFamily(enemy.EnemyNameString))
{
return OtherSpawnWeight(enemy.DifficultyScore);
}
return CoreSpawnWeight(enemy.DifficultyScore);
}
}
}
private static int CoreSpawnWeight(int score)
{
if (score <= 15)
{
return 8;
}
if (score <= 40)
{
return 5;
}
if (score <= 65)
{
return 3;
}
if (score <= 100)
{
return 2;
}
return 1;
}
private static int OtherSpawnWeight(int score)
{
if (score > 40)
{
return 1;
}
return 2;
}
private static int SpawnMultiplicity(RuntimeEnemyEntry enemy, int value)
{
switch (GetOperatorTier(enemy.EnemyNameString))
{
case OperatorTier.Apex:
return 1;
case OperatorTier.Standard:
case OperatorTier.Advanced:
return 2;
default:
if (!IsCoreEnemyFamily(enemy.EnemyNameString))
{
return 1;
}
return value switch
{
8 => 13,
5 => 8,
3 => 6,
2 => 4,
_ => 2,
};
}
}
private static bool IsCoreEnemyFamily(string enemyNameString)
{
if (!enemyNameString.StartsWith("RW_", StringComparison.Ordinal) && !enemyNameString.StartsWith("M_Swat_", StringComparison.Ordinal) && !enemyNameString.StartsWith("M_MercWiener_", StringComparison.Ordinal))
{
return enemyNameString.StartsWith("Comperator_", StringComparison.Ordinal);
}
return true;
}
private static OperatorTier GetOperatorTier(string enemyNameString)
{
if (string.IsNullOrEmpty(enemyNameString) || !enemyNameString.StartsWith("Comperator_", StringComparison.OrdinalIgnoreCase))
{
return OperatorTier.None;
}
if (ContainsToken(enemyNameString, "Heavy_") || ContainsToken(enemyNameString, "Tier5") || ContainsToken(enemyNameString, "MixedHighTier"))
{
return OperatorTier.Apex;
}
if (ContainsToken(enemyNameString, "Tier4") || ContainsToken(enemyNameString, "MixedMedTier") || ContainsToken(enemyNameString, "Medium_Tier3"))
{
return OperatorTier.Advanced;
}
return OperatorTier.Standard;
}
private static bool ContainsToken(string value, string token)
{
return value.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0;
}
}
public sealed class MountResolution
{
public string RawMount { get; private set; }
public string CanonicalMount { get; private set; }
public bool IsResolved { get; private set; }
private MountResolution(string rawMount, string canonicalMount, bool isResolved)
{
RawMount = rawMount;
CanonicalMount = canonicalMount;
IsResolved = isResolved;
}
public static MountResolution Resolve(string rawMount)
{
if (string.IsNullOrEmpty(rawMount) || rawMount.Trim().Length == 0)
{
return new MountResolution(string.Empty, string.Empty, isResolved: false);
}
string text = rawMount.Trim();
if (string.Equals(text, "99", StringComparison.Ordinal))
{
return new MountResolution(text, "RMR", isResolved: true);
}
if (int.TryParse(text, out var _))
{
return new MountResolution(text, string.Empty, isResolved: false);
}
return new MountResolution(text, text, isResolved: true);
}
}
public static class PipScopeOpticClassifier
{
public static string Classify(string objectId, bool hasPipScope, bool hasReflexSight)
{
if (!string.IsNullOrEmpty(objectId) && objectId.IndexOf("magnifier", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "Magnifier";
}
if (hasPipScope)
{
return "Scope";
}
if (!hasReflexSight)
{
return string.Empty;
}
return "Reflex";
}
}
[BepInPlugin("HLin.GunGameProgressionsMetadataExporter", "GunGame Progressions Metadata Exporter", "1.3.6")]
[BepInProcess("h3vr.exe")]
public sealed class Plugin : BaseUnityPlugin
{
private sealed class RuntimeFirearmInspection
{
public string Category { get; private set; }
public int? MagazineType { get; private set; }
public List<string> PhysicalMountTypes { get; private set; }
public RuntimeFirearmInspection(string category, int? magazineType, List<string> physicalMountTypes)
{
Category = category;
MagazineType = magazineType;
PhysicalMountTypes = physicalMountTypes;
}
}
private const int StableSamplesRequired = 3;
private const int MaximumSamples = 120;
private const int MetadataEntriesPerFrame = 64;
private void Start()
{
((MonoBehaviour)this).StartCoroutine(ExportWhenObjectDataIsStable());
}
private IEnumerator ExportWhenObjectDataIsStable()
{
RuntimeMetadataStabilityGate stabilityGate = new RuntimeMetadataStabilityGate(3);
for (int sample = 0; sample < 120; sample++)
{
if (!TryGetObjectData(out var objects) || objects.Count == 0)
{
yield return (object)new WaitForSeconds(1f);
continue;
}
if (stabilityGate.Observe(objects.Count))
{
yield return ((MonoBehaviour)this).StartCoroutine(WriteRuntimeMetadata(objects, "final-refresh"));
yield break;
}
yield return (object)new WaitForSeconds(1f);
}
((BaseUnityPlugin)this).Logger.LogWarning((object)"Timed out waiting for late H3VR object metadata growth; packaged vanilla fallback profiles remain available for this launch.");
}
private bool TryGetObjectData(out Dictionary<string, FVRObject> objects)
{
objects = null;
try
{
objects = IM.OD;
return objects != null;
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("H3VR object data is not ready: " + ex.Message));
return false;
}
}
private unsafe IEnumerator WriteRuntimeMetadata(Dictionary<string, FVRObject> objects, string phase)
{
List<RuntimeMetadataEntry> entries = new List<RuntimeMetadataEntry>();
int skipped = 0;
List<FVRObject> snapshot = objects.Values.Where((FVRObject item) => (Object)(object)item != (Object)null).ToList();
for (int index = 0; index < snapshot.Count; index++)
{
FVRObject val = snapshot[index];
if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.ItemID))
{
skipped++;
continue;
}
string declaredCategory = ((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref val.Category)/*cast due to .constrained prefix*/).ToString();
string opticKind = GetOpticKind(val);
RuntimeFirearmInspection runtimeFirearmInspection = InspectFirearmPrefab(val, declaredCategory);
string category = runtimeFirearmInspection.Category;
entries.Add(new RuntimeMetadataEntry
{
ObjectID = val.ItemID,
Category = category,
IsModContent = val.IsModContent,
MagazineType = (runtimeFirearmInspection.MagazineType ?? ((int)val.MagazineType)),
ClipType = (int)val.ClipType,
RoundType = (int)val.RoundType,
CompatibleMagazines = ObjectIds(val.CompatibleMagazines),
CompatibleClips = ObjectIds(val.CompatibleClips),
CompatibleSpeedLoaders = ObjectIds(val.CompatibleSpeedLoaders),
CompatibleSingleRounds = ObjectIds(val.CompatibleSingleRounds),
BespokeAttachments = ObjectIds(val.BespokeAttachments),
FirearmSize = ((object)Unsafe.As<OTagFirearmSize, OTagFirearmSize>(ref val.TagFirearmSize)/*cast due to .constrained prefix*/).ToString(),
FirearmRoundPower = ((object)Unsafe.As<OTagFirearmRoundPower, OTagFirearmRoundPower>(ref val.TagFirearmRoundPower)/*cast due to .constrained prefix*/).ToString(),
FirearmMounts = ((val.TagFirearmMounts == null) ? new List<string>() : val.TagFirearmMounts.Select((OTagFirearmMount mount) => ((object)(*(OTagFirearmMount*)(&mount))/*cast due to .constrained prefix*/).ToString()).ToList()),
AttachmentMount = ((object)Unsafe.As<OTagFirearmMount, OTagFirearmMount>(ref val.TagAttachmentMount)/*cast due to .constrained prefix*/).ToString(),
AttachmentFeature = ((object)Unsafe.As<OTagAttachmentFeature, OTagAttachmentFeature>(ref val.TagAttachmentFeature)/*cast due to .constrained prefix*/).ToString(),
OpticKind = opticKind,
PhysicalMountTypes = (runtimeFirearmInspection.PhysicalMountTypes ?? GetPhysicalMountTypes(val, category, opticKind))
});
if (index > 0 && index % 64 == 0)
{
yield return null;
}
}
entries.Sort((RuntimeMetadataEntry left, RuntimeMetadataEntry right) => string.CompareOrdinal(left.ObjectID, right.ObjectID));
string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string text = Path.Combine(directoryName, "ObjectData.json");
WriteTextAtomically(text, SerializeMetadata(entries));
ProfileRules rules;
try
{
rules = ProfileRules.Load(directoryName);
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Unable to load GunGame profile rules: " + ex.Message));
yield break;
}
List<RuntimeMetadataEntry> sourceEntries = entries.Where((RuntimeMetadataEntry entry) => !rules.IsBlacklisted(entry)).ToList();
int hashCode = Guid.NewGuid().GetHashCode();
List<RuntimeEnemyEntry> list = BuildEnemyEntries();
RuntimeGenerationResult runtimeGenerationResult = RuntimeProfileBuilder.BuildWithDiagnostics(sourceEntries, list, new Random(hashCode));
string text2 = Path.Combine(directoryName, "RuntimePools");
Directory.CreateDirectory(text2);
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
foreach (RuntimeWeaponPool pool in runtimeGenerationResult.Pools)
{
string text3 = RuntimePoolFileName(pool);
hashSet.Add(text3);
WriteTextAtomically(Path.Combine(directoryName, text3), SerializePool(pool));
}
RemoveStaleRuntimePools(directoryName, hashSet);
RemoveStaleRuntimePools(text2, new HashSet<string>(StringComparer.Ordinal));
WriteTextAtomically(Path.Combine(text2, "runtime-generation-receipt.json"), SerializeReceipt(entries, list, runtimeGenerationResult, hashCode, phase));
WriteTextAtomically(Path.Combine(text2, "enemy-catalog.json"), SerializeEnemyCatalog(list));
int num = entries.Count((RuntimeMetadataEntry entry) => entry.IsModContent);
int num2 = ((runtimeGenerationResult.Pools.Count != 0) ? runtimeGenerationResult.Pools[0].Guns.Count : 0);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Exported " + entries.Count + " active metadata entries (" + num + " modded) to " + text + "; generated " + runtimeGenerationResult.Pools.Count + " advanced runtime GunGame pools with " + num2 + " firearms and " + list.Count + " active Sosig types during " + phase + "; skipped " + runtimeGenerationResult.SkippedFirearms.Count + " without a compatible feed."));
}
private static List<string> ObjectIds(IEnumerable<FVRObject> objects)
{
if (objects == null)
{
return new List<string>();
}
return (from item in objects
where (Object)(object)item != (Object)null && !string.IsNullOrEmpty(item.ItemID)
select item.ItemID).Distinct().OrderBy<string, string>((string item) => item, StringComparer.Ordinal).ToList();
}
private static RuntimeFirearmInspection InspectFirearmPrefab(FVRObject item, string declaredCategory)
{
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Expected I4, but got Unknown
if (declaredCategory != "Firearm")
{
return new RuntimeFirearmInspection(declaredCategory, null, null);
}
try
{
GameObject gameObject = ((AnvilAsset)item).GetGameObject();
if ((Object)(object)gameObject == (Object)null)
{
return new RuntimeFirearmInspection(declaredCategory, null, null);
}
FVRPhysicalObject[] componentsInChildren = gameObject.GetComponentsInChildren<FVRPhysicalObject>(true);
FVRFireArm val = null;
bool hasMagazine = false;
bool hasClip = false;
bool hasSpeedloader = false;
bool hasRound = false;
FVRPhysicalObject[] array = componentsInChildren;
foreach (FVRPhysicalObject val2 in array)
{
if (val2 is FVRFireArm)
{
val = (FVRFireArm)(object)((val2 is FVRFireArm) ? val2 : null);
}
else if (val2 is FVRFireArmMagazine)
{
hasMagazine = true;
}
else if (val2 is FVRFireArmClip)
{
hasClip = true;
}
else if (val2 is Speedloader)
{
hasSpeedloader = true;
}
else if (val2 is FVRFireArmRound)
{
hasRound = true;
}
}
string category = RuntimeItemRole.Resolve(declaredCategory, (Object)(object)val != (Object)null, hasMagazine, hasClip, hasSpeedloader, hasRound);
int? magazineType = (((Object)(object)val == (Object)null) ? ((int?)null) : new int?((int)val.MagazineType));
List<string> physicalMountTypes = (((Object)(object)val == (Object)null) ? null : GetPhysicalMountTypes(gameObject));
return new RuntimeFirearmInspection(category, magazineType, physicalMountTypes);
}
catch (Exception)
{
return new RuntimeFirearmInspection(declaredCategory, null, null);
}
}
private static List<string> GetPhysicalMountTypes(FVRObject item, string category, string opticKind)
{
string text = string.Empty;
if (category == "Firearm")
{
text = "FistVR.FVRFireArmAttachmentMount";
}
else if (category == "Attachment" && !string.IsNullOrEmpty(opticKind))
{
text = "FistVR.FVRFireArmAttachment";
}
if (string.IsNullOrEmpty(text))
{
return new List<string>();
}
try
{
GameObject gameObject = ((AnvilAsset)item).GetGameObject();
if ((Object)(object)gameObject == (Object)null)
{
return new List<string>();
}
return GetPhysicalMountTypes(gameObject, text);
}
catch (Exception)
{
return new List<string>();
}
}
private static List<string> GetPhysicalMountTypes(GameObject prefab)
{
return GetPhysicalMountTypes(prefab, "FistVR.FVRFireArmAttachmentMount");
}
private static List<string> GetPhysicalMountTypes(GameObject prefab, string componentTypeName)
{
Type type = typeof(FVRObject).Assembly.GetType(componentTypeName, throwOnError: false);
if ((object)type == null)
{
return new List<string>();
}
FieldInfo typeField = type.GetField("Type", BindingFlags.Instance | BindingFlags.Public);
if ((object)typeField == null)
{
return new List<string>();
}
return (from value in (from component in prefab.GetComponentsInChildren(type, true)
select typeField.GetValue(component) into value
where value != null
select value).Select(ResolveRuntimeMountName)
where !string.IsNullOrEmpty(value)
select value).Distinct<string>(StringComparer.Ordinal).OrderBy<string, string>((string value) => value, StringComparer.Ordinal).ToList();
}
private static string ResolveRuntimeMountName(object value)
{
Type type = value.GetType();
if (!type.IsEnum || !Enum.IsDefined(type, value))
{
return value.ToString();
}
return Enum.GetName(type, value) ?? value.ToString();
}
private static List<RuntimeEnemyEntry> BuildEnemyEntries()
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
List<RuntimeEnemyEntry> list = new List<RuntimeEnemyEntry>();
IM instance = ManagerSingleton<IM>.Instance;
if ((Object)(object)instance == (Object)null || instance.odicSosigObjsByID == null)
{
return list;
}
foreach (KeyValuePair<SosigEnemyID, SosigEnemyTemplate> item in instance.odicSosigObjsByID)
{
SosigEnemyTemplate value = item.Value;
if (!((Object)(object)value == (Object)null) && (int)item.Key != 0)
{
bool flag = Enum.IsDefined(typeof(SosigEnemyID), item.Key);
string text = (flag ? ((object)item.Key/*cast due to .constrained prefix*/).ToString() : Convert.ToInt32(item.Key).ToString());
int num = EnemyHealthScore(value);
int num2 = EnemyArmorScore(value);
int num3 = EnemyWeaponThreatScore(value);
int num4 = EnemySpecialThreatScore(value);
list.Add(new RuntimeEnemyEntry
{
EnemyNameString = text,
DisplayName = (string.IsNullOrEmpty(value.DisplayName) ? text : value.DisplayName),
IsModContent = !flag,
IsSpawnable = true,
HealthScore = num,
ArmorScore = num2,
WeaponThreatScore = num3,
SpecialThreatScore = num4,
DifficultyScore = Math.Max(1, num + num2 + num3 + num4)
});
}
}
return list.OrderBy((RuntimeEnemyEntry entry) => entry.DifficultyScore).ThenBy<RuntimeEnemyEntry, string>((RuntimeEnemyEntry entry) => entry.EnemyNameString, StringComparer.Ordinal).ToList();
}
private static int EnemyHealthScore(SosigEnemyTemplate template)
{
List<SosigConfigTemplate> list = EnemyConfigs(template).ToList();
if (list.Count == 0)
{
return 1;
}
return Math.Max(1, (int)Math.Round(list.Average((SosigConfigTemplate config) => config.TotalMustard) / 25f));
}
private static int EnemyArmorScore(SosigEnemyTemplate template)
{
float num = 0f;
foreach (SosigOutfitConfig item in template.OutfitConfig ?? new List<SosigOutfitConfig>())
{
num += OutfitSlotScore(item.Headwear, item.Chance_Headwear);
num += OutfitSlotScore(item.Eyewear, item.Chance_Eyewear) * 0.5f;
num += OutfitSlotScore(item.Facewear, item.Chance_Facewear) * 0.75f;
num += OutfitSlotScore(item.Torsowear, item.Chance_Torsowear) * 1.5f;
num += OutfitSlotScore(item.Pantswear, item.Chance_Pantswear) * 0.5f;
}
return (int)Math.Round(num * 3f);
}
private static float OutfitSlotScore(List<FVRObject> items, float chance)
{
if (items == null || items.Count == 0)
{
return 0f;
}
if (!(chance > 0f))
{
return 1f;
}
return chance;
}
private static int EnemyWeaponThreatScore(SosigEnemyTemplate template)
{
List<FVRObject> list = new List<FVRObject>();
list.AddRange(template.WeaponOptions ?? new List<FVRObject>());
list.AddRange(template.WeaponOptions_Secondary ?? new List<FVRObject>());
list.AddRange(template.WeaponOptions_Tertiary ?? new List<FVRObject>());
int num = list.Where((FVRObject weapon) => (Object)(object)weapon != (Object)null).Select(WeaponThreatScore).DefaultIfEmpty(0)
.Max();
int num2 = Math.Min(10, list.Count((FVRObject weapon) => (Object)(object)weapon != (Object)null));
return num + num2 + (int)Math.Round((template.SecondaryChance + template.TertiaryChance) * 4f);
}
private static int WeaponThreatScore(FVRObject weapon)
{
if (((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref weapon.Category)/*cast due to .constrained prefix*/).ToString() != "Firearm")
{
return 1;
}
return ((object)Unsafe.As<OTagFirearmRoundPower, OTagFirearmRoundPower>(ref weapon.TagFirearmRoundPower)/*cast due to .constrained prefix*/).ToString() switch
{
"Tiny" => 2,
"Pistol" => 4,
"Shotgun" => 6,
"Intermediate" => 7,
"FullPower" => 9,
"AntiMaterial" => 12,
"Ordnance" => 14,
"Exotic" => 12,
_ => 5,
};
}
private static int EnemySpecialThreatScore(SosigEnemyTemplate template)
{
float num = 0f;
foreach (SosigConfigTemplate item in EnemyConfigs(template))
{
num = Math.Max(num, Math.Max(0f, item.RunSpeed - 3f) * 2f);
num = Math.Max(num, Math.Max(0f, item.ViewDistance - 150f) / 100f);
num = Math.Max(num, HasBooleanProperty(item, "HasNightVision") ? 4f : 0f);
num = Math.Max(num, item.AppliesDamageResistToIntegrityLoss ? 3f : 0f);
num = Math.Max(num, (!item.CanBeGrabbed || !item.CanBeSevered || !item.CanBeStabbed) ? 3f : 0f);
}
return (int)Math.Ceiling(num);
}
private static IEnumerable<SosigConfigTemplate> EnemyConfigs(SosigEnemyTemplate template)
{
return from config in (template.ConfigTemplates ?? new List<SosigConfigTemplate>()).Concat(template.ConfigTemplates_Easy ?? new List<SosigConfigTemplate>())
where (Object)(object)config != (Object)null
select config;
}
private static bool HasBooleanProperty(object value, string propertyName)
{
PropertyInfo property = value.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if ((object)property != null && (object)property.PropertyType == typeof(bool))
{
return (bool)property.GetValue(value, null);
}
return false;
}
private static string GetOpticKind(FVRObject item)
{
if (((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref item.Category)/*cast due to .constrained prefix*/).ToString() != "Attachment")
{
return string.Empty;
}
string text = ((object)Unsafe.As<OTagAttachmentFeature, OTagAttachmentFeature>(ref item.TagAttachmentFeature)/*cast due to .constrained prefix*/).ToString();
if (text != "Reflex" && text != "Magnification")
{
return string.Empty;
}
try
{
GameObject gameObject = ((AnvilAsset)item).GetGameObject();
if ((Object)(object)gameObject == (Object)null)
{
return string.Empty;
}
Component component = GetComponent(gameObject, "FistVR.PIPScopeController");
Component component2 = GetComponent(gameObject, "FistVR.ReflexSightController");
return PipScopeOpticClassifier.Classify(item.ItemID, (Object)(object)component != (Object)null, (Object)(object)component2 != (Object)null);
}
catch (Exception)
{
}
return string.Empty;
}
private static Component GetComponent(GameObject prefab, string typeName)
{
Type type = typeof(FVRObject).Assembly.GetType(typeName, throwOnError: false);
if ((object)type != null)
{
return prefab.GetComponentInChildren(type, true);
}
return null;
}
private static string RuntimePoolFileName(RuntimeWeaponPool pool)
{
return "GunGameWeaponPool_Runtime_" + pool.Family + "_" + pool.EnemyType + ".json";
}
private static void RemoveStaleRuntimePools(string runtimePoolsPath, HashSet<string> expectedPoolFiles)
{
string[] files = Directory.GetFiles(runtimePoolsPath, "GunGameWeaponPool_Runtime_*.json");
foreach (string path in files)
{
if (!expectedPoolFiles.Contains(Path.GetFileName(path)))
{
File.Delete(path);
}
}
}
private static void WriteTextAtomically(string outputPath, string contents)
{
string text = outputPath + "." + Guid.NewGuid().ToString("N") + ".tmp";
File.WriteAllText(text, contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
try
{
if (File.Exists(outputPath))
{
File.Replace(text, outputPath, null);
}
else
{
File.Move(text, outputPath);
}
}
catch (PlatformNotSupportedException)
{
File.Copy(text, outputPath, overwrite: true);
File.Delete(text);
}
}
private static string SerializeMetadata(List<RuntimeMetadataEntry> entries)
{
StringBuilder stringBuilder = new StringBuilder(entries.Count * 256);
stringBuilder.Append("[\n");
for (int i = 0; i < entries.Count; i++)
{
RuntimeMetadataEntry runtimeMetadataEntry = entries[i];
stringBuilder.Append(" {\"ObjectID\":\"");
AppendJsonString(stringBuilder, runtimeMetadataEntry.ObjectID);
stringBuilder.Append("\",\"Category\":\"");
AppendJsonString(stringBuilder, runtimeMetadataEntry.Category);
stringBuilder.Append("\",\"IsModContent\":");
stringBuilder.Append(runtimeMetadataEntry.IsModContent ? "true" : "false");
stringBuilder.Append(",\"MagazineType\":");
stringBuilder.Append(runtimeMetadataEntry.MagazineType);
stringBuilder.Append(",\"ClipType\":");
stringBuilder.Append(runtimeMetadataEntry.ClipType);
stringBuilder.Append(",\"RoundType\":");
stringBuilder.Append(runtimeMetadataEntry.RoundType);
AppendJsonNamedStringArray(stringBuilder, "CompatibleMagazines", runtimeMetadataEntry.CompatibleMagazines);
AppendJsonNamedStringArray(stringBuilder, "CompatibleClips", runtimeMetadataEntry.CompatibleClips);
AppendJsonNamedStringArray(stringBuilder, "CompatibleSpeedLoaders", runtimeMetadataEntry.CompatibleSpeedLoaders);
AppendJsonNamedStringArray(stringBuilder, "CompatibleSingleRounds", runtimeMetadataEntry.CompatibleSingleRounds);
AppendJsonNamedStringArray(stringBuilder, "BespokeAttachments", runtimeMetadataEntry.BespokeAttachments);
AppendJsonNamedString(stringBuilder, "FirearmSize", runtimeMetadataEntry.FirearmSize);
AppendJsonNamedString(stringBuilder, "FirearmRoundPower", runtimeMetadataEntry.FirearmRoundPower);
AppendJsonNamedStringArray(stringBuilder, "FirearmMounts", runtimeMetadataEntry.FirearmMounts);
AppendJsonNamedString(stringBuilder, "AttachmentMount", runtimeMetadataEntry.AttachmentMount);
AppendJsonNamedString(stringBuilder, "AttachmentFeature", runtimeMetadataEntry.AttachmentFeature);
AppendJsonNamedString(stringBuilder, "OpticKind", runtimeMetadataEntry.OpticKind);
AppendJsonNamedStringArray(stringBuilder, "PhysicalMountTypes", runtimeMetadataEntry.PhysicalMountTypes);
stringBuilder.Append('}');
if (i < entries.Count - 1)
{
stringBuilder.Append(',');
}
stringBuilder.Append('\n');
}
stringBuilder.Append(']');
return stringBuilder.ToString();
}
private static string SerializePool(RuntimeWeaponPool pool)
{
StringBuilder stringBuilder = new StringBuilder(pool.Guns.Count * 128);
stringBuilder.Append("{\n \"WeaponPoolType\": \"Advanced\",\n \"Description\": \"");
AppendJsonString(stringBuilder, pool.Description);
stringBuilder.Append("\",\n \"EnemyProgressionType\": ");
stringBuilder.Append(pool.EnemyProgressionType);
stringBuilder.Append(",\n \"Enemies\": [");
for (int i = 0; i < pool.Enemies.Count; i++)
{
if (i > 0)
{
stringBuilder.Append(',');
}
stringBuilder.Append("{\"EnemyName\":0,\"EnemyNameString\":\"");
AppendJsonString(stringBuilder, pool.Enemies[i].EnemyNameString);
stringBuilder.Append("\",\"Value\":");
stringBuilder.Append(pool.Enemies[i].Value);
stringBuilder.Append('}');
}
stringBuilder.Append("],\n \"Guns\": [");
for (int j = 0; j < pool.Guns.Count; j++)
{
if (j > 0)
{
stringBuilder.Append(',');
}
RuntimeGun runtimeGun = pool.Guns[j];
stringBuilder.Append("{\"GunName\":\"");
AppendJsonString(stringBuilder, runtimeGun.GunName);
stringBuilder.Append("\",\"MagName\":\"");
AppendJsonString(stringBuilder, runtimeGun.MagName);
stringBuilder.Append("\",\"MagNames\":");
AppendJsonStringArray(stringBuilder, runtimeGun.MagNames);
stringBuilder.Append(",\"CategoryID\":");
stringBuilder.Append(runtimeGun.CategoryID);
stringBuilder.Append(",\"Extra\":\"");
AppendJsonString(stringBuilder, runtimeGun.Extra);
stringBuilder.Append("\"}");
}
stringBuilder.Append("],\n \"Name\": \"");
AppendJsonString(stringBuilder, pool.Name);
stringBuilder.Append("\",\n \"OrderType\": ");
stringBuilder.Append(pool.OrderType);
stringBuilder.Append("\n}");
return stringBuilder.ToString();
}
private static string SerializeReceipt(List<RuntimeMetadataEntry> entries, List<RuntimeEnemyEntry> enemies, RuntimeGenerationResult result, int randomSeed, string phase)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("{\n \"generatedAtUtc\": \"");
AppendJsonString(stringBuilder, DateTime.UtcNow.ToString("o"));
stringBuilder.Append("\",\n \"randomSeed\": ");
stringBuilder.Append(randomSeed);
stringBuilder.Append(",\n \"phase\": \"");
AppendJsonString(stringBuilder, phase);
stringBuilder.Append('"');
stringBuilder.Append(",\n \"activeItems\": ");
stringBuilder.Append(entries.Count);
stringBuilder.Append(",\n \"activeModdedItems\": ");
stringBuilder.Append(entries.Count((RuntimeMetadataEntry entry) => entry.IsModContent));
stringBuilder.Append(",\n \"activeSosigTypes\": ");
stringBuilder.Append(enemies.Count);
stringBuilder.Append(",\n \"activeModdedSosigTypes\": ");
stringBuilder.Append(enemies.Count((RuntimeEnemyEntry enemy) => enemy.IsModContent));
stringBuilder.Append(",\n \"eligibleWeaponsPerPool\": ");
stringBuilder.Append((result.Pools.Count != 0) ? result.Pools[0].Guns.Count : 0);
stringBuilder.Append(",\n \"skippedFirearms\": ");
AppendJsonStringArray(stringBuilder, result.SkippedFirearms);
stringBuilder.Append(",\n \"firearmsWithoutOptics\": ");
AppendJsonStringArray(stringBuilder, result.FirearmsWithoutOptics);
stringBuilder.Append("\n}");
return stringBuilder.ToString();
}
private static string SerializeEnemyCatalog(List<RuntimeEnemyEntry> enemies)
{
StringBuilder stringBuilder = new StringBuilder(enemies.Count * 192);
stringBuilder.Append("[\n");
for (int i = 0; i < enemies.Count; i++)
{
RuntimeEnemyEntry runtimeEnemyEntry = enemies[i];
stringBuilder.Append(" {\"EnemyNameString\":\"");
AppendJsonString(stringBuilder, runtimeEnemyEntry.EnemyNameString);
stringBuilder.Append("\",\"DisplayName\":\"");
AppendJsonString(stringBuilder, runtimeEnemyEntry.DisplayName);
stringBuilder.Append("\",\"IsModContent\":");
stringBuilder.Append(runtimeEnemyEntry.IsModContent ? "true" : "false");
stringBuilder.Append(",\"IsSpawnable\":");
stringBuilder.Append(runtimeEnemyEntry.IsSpawnable ? "true" : "false");
stringBuilder.Append(",\"DifficultyScore\":");
stringBuilder.Append(runtimeEnemyEntry.DifficultyScore);
stringBuilder.Append(",\"HealthScore\":");
stringBuilder.Append(runtimeEnemyEntry.HealthScore);
stringBuilder.Append(",\"ArmorScore\":");
stringBuilder.Append(runtimeEnemyEntry.ArmorScore);
stringBuilder.Append(",\"WeaponThreatScore\":");
stringBuilder.Append(runtimeEnemyEntry.WeaponThreatScore);
stringBuilder.Append(",\"SpecialThreatScore\":");
stringBuilder.Append(runtimeEnemyEntry.SpecialThreatScore);
stringBuilder.Append('}');
if (i < enemies.Count - 1)
{
stringBuilder.Append(',');
}
stringBuilder.Append('\n');
}
stringBuilder.Append(']');
return stringBuilder.ToString();
}
private static void AppendJsonNamedString(StringBuilder json, string name, string value)
{
json.Append(",\"");
AppendJsonString(json, name);
json.Append("\":\"");
AppendJsonString(json, value ?? string.Empty);
json.Append('"');
}
private static void AppendJsonNamedStringArray(StringBuilder json, string name, List<string> values)
{
json.Append(",\"");
AppendJsonString(json, name);
json.Append("\":");
AppendJsonStringArray(json, values);
}
private static void AppendJsonStringArray(StringBuilder json, List<string> values)
{
values = values ?? new List<string>();
json.Append('[');
for (int i = 0; i < values.Count; i++)
{
if (i > 0)
{
json.Append(',');
}
json.Append('"');
AppendJsonString(json, values[i]);
json.Append('"');
}
json.Append(']');
}
private static void AppendJsonString(StringBuilder json, string value)
{
string text = value ?? string.Empty;
foreach (char c in text)
{
switch (c)
{
case '\\':
json.Append("\\\\");
continue;
case '"':
json.Append("\\\"");
continue;
case '\n':
json.Append("\\n");
continue;
case '\r':
json.Append("\\r");
continue;
case '\t':
json.Append("\\t");
continue;
}
if (c < ' ')
{
json.Append("\\u");
int num = c;
json.Append(num.ToString("x4"));
}
else
{
json.Append(c);
}
}
}
}
public sealed class ProfileRules
{
public string[] FirearmBlacklist { get; set; }
public string[] FeedBlacklist { get; set; }
public static ProfileRules Load(string packageDirectory)
{
string text = Path.Combine(packageDirectory, "profile-rules.json");
if (!File.Exists(text))
{
throw new FileNotFoundException("GunGame profile rules are missing.", text);
}
string json = File.ReadAllText(text);
return new ProfileRules
{
FirearmBlacklist = ReadStringArray(json, "firearmBlacklist"),
FeedBlacklist = ReadStringArray(json, "feedBlacklist")
};
}
public bool IsBlacklisted(RuntimeMetadataEntry entry)
{
if (!(entry.Category == "Firearm"))
{
return Contains(FeedBlacklist, entry.ObjectID);
}
return Contains(FirearmBlacklist, entry.ObjectID);
}
private static bool Contains(IEnumerable<string> values, string value)
{
foreach (string value2 in values)
{
if (string.Equals(value2, value, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
private static string[] ReadStringArray(string json, string propertyName)
{
string pattern = "\\\"" + Regex.Escape(propertyName) + "\\\"\\s*:\\s*\\[(?<items>.*?)\\]";
Match match = Regex.Match(json, pattern, RegexOptions.Singleline);
if (!match.Success)
{
return new string[0];
}
List<string> list = new List<string>();
foreach (Match item in Regex.Matches(match.Groups["items"].Value, "\\\"(?<value>(?:\\\\.|[^\\\"\\\\])*)\\\""))
{
list.Add(item.Groups["value"].Value.Replace("\\\\\"", "\"").Replace("\\\\\\\\", "\\"));
}
return list.ToArray();
}
}
public static class RuntimeItemRole
{
public static string Resolve(string declaredCategory, bool hasFirearm, bool hasMagazine, bool hasClip, bool hasSpeedloader, bool hasRound)
{
if (declaredCategory != "Firearm")
{
return declaredCategory;
}
if (hasFirearm)
{
return "Firearm";
}
if (hasMagazine)
{
return "Magazine";
}
if (hasClip)
{
return "Clip";
}
if (hasSpeedloader)
{
return "SpeedLoader";
}
if (hasRound)
{
return "Cartridge";
}
return "Unknown";
}
}
public sealed class RuntimeMetadataStabilityGate
{
private readonly int requiredStableSamples;
private int initialCount = -1;
private int previousCount = -1;
private int stableSamples;
private bool observedLateGrowth;
public RuntimeMetadataStabilityGate(int requiredStableSamples)
{
if (requiredStableSamples < 1)
{
throw new ArgumentOutOfRangeException("requiredStableSamples");
}
this.requiredStableSamples = requiredStableSamples;
}
public bool Observe(int itemCount)
{
if (itemCount <= 0)
{
return false;
}
if (initialCount < 0)
{
initialCount = itemCount;
}
if (itemCount != previousCount)
{
observedLateGrowth = observedLateGrowth || itemCount > initialCount;
previousCount = itemCount;
stableSamples = 0;
return false;
}
stableSamples++;
if (observedLateGrowth)
{
return stableSamples >= requiredStableSamples;
}
return false;
}
}
public sealed class RuntimeMetadataEntry
{
public string ObjectID { get; set; }
public string Category { get; set; }
public bool IsModContent { get; set; }
public int MagazineType { get; set; }
public int ClipType { get; set; }
public int RoundType { get; set; }
public List<string> CompatibleMagazines { get; set; }
public List<string> CompatibleClips { get; set; }
public List<string> CompatibleSpeedLoaders { get; set; }
public List<string> CompatibleSingleRounds { get; set; }
public List<string> BespokeAttachments { get; set; }
public string FirearmSize { get; set; }
public string FirearmRoundPower { get; set; }
public List<string> FirearmMounts { get; set; }
public string AttachmentMount { get; set; }
public string AttachmentFeature { get; set; }
public string OpticKind { get; set; }
public List<string> PhysicalMountTypes { get; set; }
}
public sealed class RuntimeEnemyEntry
{
public string EnemyNameString { get; set; }
public string DisplayName { get; set; }
public bool IsModContent { get; set; }
public bool IsSpawnable { get; set; }
public int DifficultyScore { get; set; }
public int HealthScore { get; set; }
public int ArmorScore { get; set; }
public int WeaponThreatScore { get; set; }
public int SpecialThreatScore { get; set; }
}
public sealed class RuntimeGun
{
public string GunName { get; set; }
public string MagName { get; set; }
public List<string> MagNames { get; set; }
public string Extra { get; set; }
public int CategoryID { get; set; }
}
public sealed class RuntimeEnemy
{
public string EnemyNameString { get; set; }
public int Value { get; set; }
}
public sealed class RuntimeWeaponPool
{
public string Name { get; set; }
public string Description { get; set; }
public int OrderType { get; set; }
public string WeaponPoolType { get; set; }
public int EnemyProgressionType { get; set; }
public string Family { get; set; }
public string EnemyType { get; set; }
public List<RuntimeEnemy> Enemies { get; set; }
public List<RuntimeGun> Guns { get; set; }
}
public sealed class RuntimeGenerationResult
{
public List<RuntimeWeaponPool> Pools { get; set; }
public List<string> SkippedFirearms { get; set; }
public List<string> FirearmsWithoutOptics { get; set; }
}
public static class RuntimeProfileBuilder
{
private sealed class FeedCandidate
{
public string ObjectID { get; private set; }
public int CategoryID { get; private set; }
public FeedCandidate(string objectId, int categoryId)
{
ObjectID = objectId;
CategoryID = categoryId;
}
}
public static List<RuntimeWeaponPool> Build(IEnumerable<RuntimeMetadataEntry> sourceEntries, Random random)
{
return BuildWithDiagnostics(sourceEntries, DefaultEnemies(), random).Pools;
}
public static List<RuntimeWeaponPool> Build(IEnumerable<RuntimeMetadataEntry> sourceEntries, IEnumerable<RuntimeEnemyEntry> sourceEnemies, Random random)
{
return BuildWithDiagnostics(sourceEntries, sourceEnemies, random).Pools;
}
public static RuntimeGenerationResult BuildWithDiagnostics(IEnumerable<RuntimeMetadataEntry> sourceEntries, Random random)
{
return BuildWithDiagnostics(sourceEntries, DefaultEnemies(), random);
}
public static RuntimeGenerationResult BuildWithDiagnostics(IEnumerable<RuntimeMetadataEntry> sourceEntries, IEnumerable<RuntimeEnemyEntry> sourceEnemies, Random random)
{
if (sourceEntries == null)
{
throw new ArgumentNullException("sourceEntries");
}
if (random == null)
{
throw new ArgumentNullException("random");
}
if (sourceEnemies == null)
{
throw new ArgumentNullException("sourceEnemies");
}
List<RuntimeMetadataEntry> list = sourceEntries.Where((RuntimeMetadataEntry entry) => entry != null && !string.IsNullOrEmpty(entry.ObjectID)).OrderBy<RuntimeMetadataEntry, string>((RuntimeMetadataEntry entry) => entry.ObjectID, StringComparer.Ordinal).ToList();
Dictionary<string, RuntimeMetadataEntry> entriesById = list.GroupBy<RuntimeMetadataEntry, string>((RuntimeMetadataEntry entry) => entry.ObjectID, StringComparer.Ordinal).ToDictionary<IGrouping<string, RuntimeMetadataEntry>, string, RuntimeMetadataEntry>((IGrouping<string, RuntimeMetadataEntry> group) => group.Key, (IGrouping<string, RuntimeMetadataEntry> group) => group.First(), StringComparer.Ordinal);
List<RuntimeMetadataEntry> source = (from @group in list.Where((RuntimeMetadataEntry entry) => entry.Category == "Firearm").GroupBy<RuntimeMetadataEntry, string>((RuntimeMetadataEntry entry) => entry.ObjectID, StringComparer.Ordinal)
select @group.First()).ToList();
List<RuntimeMetadataEntry> list2 = list.Where((RuntimeMetadataEntry entry) => !entry.IsModContent).ToList();
Dictionary<string, RuntimeMetadataEntry> entriesById2 = list2.GroupBy<RuntimeMetadataEntry, string>((RuntimeMetadataEntry entry) => entry.ObjectID, StringComparer.Ordinal).ToDictionary<IGrouping<string, RuntimeMetadataEntry>, string, RuntimeMetadataEntry>((IGrouping<string, RuntimeMetadataEntry> group) => group.Key, (IGrouping<string, RuntimeMetadataEntry> group) => group.First(), StringComparer.Ordinal);
List<RuntimeMetadataEntry> firearms = source.Where((RuntimeMetadataEntry entry) => !entry.IsModContent).ToList();
List<RuntimeMetadataEntry> firearms2 = source.Where((RuntimeMetadataEntry entry) => entry.IsModContent).ToList();
List<RuntimeEnemyEntry> list3 = (from @group in sourceEnemies.Where((RuntimeEnemyEntry enemy) => enemy != null && enemy.IsSpawnable && !string.IsNullOrEmpty(enemy.EnemyNameString)).GroupBy<RuntimeEnemyEntry, string>((RuntimeEnemyEntry enemy) => enemy.EnemyNameString, StringComparer.OrdinalIgnoreCase)
select @group.OrderByDescending((RuntimeEnemyEntry enemy) => enemy.DifficultyScore).First()).ToList();
List<string> list4 = new List<string>();
List<string> list5 = new List<string>();
List<RuntimeGun> weapons = BuildWeapons(firearms, list2, entriesById2, random, list4, list5);
List<RuntimeGun> list6 = BuildWeapons(firearms2, list, entriesById, random, list4, list5);
RuntimeEnemy runtimeEnemy = FindRot(list3);
List<RuntimeEnemy> list7 = BuildMixedEnemies(list3.Where((RuntimeEnemyEntry enemy) => !enemy.IsModContent));
List<RuntimeEnemy> list8 = BuildMixedEnemies(list3);
List<RuntimeWeaponPool> list9 = new List<RuntimeWeaponPool>();
list9.Add(CreateScenarioPool("01_Vanilla_Rot", "Runtime 01 - Vanilla Rot", "A Rot-only random progression using active vanilla firearms.", 1, 0, weapons, runtimeEnemy));
list9.Add(CreateScenarioPool("03_Vanilla_Mixed_Enemy", "Runtime 03 - Vanilla Mixed Enemy", "A weighted mixed-enemy progression using active vanilla firearms.", 1, 0, weapons, list7.ToArray()));
List<RuntimeWeaponPool> list10 = list9;
if (list6.Count > 0)
{
list10.Insert(1, CreateScenarioPool("02_Modded_Rot", "Runtime 02 - Modded Rot", "A Rot-only random progression using active modded firearms and compatible active feeds.", 1, 0, list6, runtimeEnemy));
list10.Add(CreateScenarioPool("04_Modded_Mixed_Enemy", "Runtime 04 - Modded Mixed Enemy", "A weighted mixed-enemy progression using active modded firearms and active Sosigs.", 1, 0, list6, list8.ToArray()));
}
return new RuntimeGenerationResult
{
Pools = list10,
SkippedFirearms = list4,
FirearmsWithoutOptics = list5
};
}
private static List<RuntimeGun> BuildWeapons(IEnumerable<RuntimeMetadataEntry> firearms, List<RuntimeMetadataEntry> entries, IDictionary<string, RuntimeMetadataEntry> entriesById, Random random, List<string> skipped, List<string> noOptic)
{
List<RuntimeGun> list = new List<RuntimeGun>();
foreach (RuntimeMetadataEntry firearm in firearms)
{
List<FeedCandidate> compatibleFeeds = GetCompatibleFeeds(entries, entriesById, firearm);
if (compatibleFeeds.Count == 0)
{
skipped.Add(firearm.ObjectID);
continue;
}
string text = SelectOptic(entries, entriesById, firearm, random);
if (string.IsNullOrEmpty(text))
{
noOptic.Add(firearm.ObjectID);
}
list.Add(new RuntimeGun
{
GunName = firearm.ObjectID,
MagName = compatibleFeeds[0].ObjectID,
MagNames = compatibleFeeds.Select((FeedCandidate feed) => feed.ObjectID).ToList(),
Extra = (text ?? string.Empty),
CategoryID = compatibleFeeds[0].CategoryID
});
}
return list;
}
private static RuntimeEnemy FindRot(IEnumerable<RuntimeEnemyEntry> enemies)
{
RuntimeEnemyEntry runtimeEnemyEntry = enemies.FirstOrDefault((RuntimeEnemyEntry enemy) => string.Equals(enemy.EnemyNameString, "RW_Rot", StringComparison.OrdinalIgnoreCase));
return new RuntimeEnemy
{
EnemyNameString = ((runtimeEnemyEntry == null) ? "RW_Rot" : runtimeEnemyEntry.EnemyNameString),
Value = 1
};
}
private static List<RuntimeEnemy> BuildMixedEnemies(IEnumerable<RuntimeEnemyEntry> enemies)
{
List<RuntimeEnemyEntry> list = enemies.OrderBy((RuntimeEnemyEntry enemy) => Math.Max(0, enemy.DifficultyScore)).ThenBy<RuntimeEnemyEntry, string>((RuntimeEnemyEntry enemy) => enemy.EnemyNameString, StringComparer.Ordinal).ToList();
if (list.Count == 0)
{
return new List<RuntimeEnemy> { FindRot(list) };
}
List<RuntimeEnemy> list2 = new List<RuntimeEnemy>();
foreach (RuntimeEnemyEntry item in list)
{
EnemySpawnWeight enemySpawnWeight = EnemyWeightPolicy.Resolve(item);
for (int num = 0; num < enemySpawnWeight.Multiplicity; num++)
{
list2.Add(new RuntimeEnemy
{
EnemyNameString = item.EnemyNameString,
Value = enemySpawnWeight.Value
});
}
}
return list2;
}
private static RuntimeWeaponPool CreateScenarioPool(string family, string name, string description, int orderType, int enemyProgressionType, IEnumerable<RuntimeGun> weapons, params RuntimeEnemy[] enemies)
{
return new RuntimeWeaponPool
{
Name = name,
Description = description,
OrderType = orderType,
WeaponPoolType = "Advanced",
EnemyProgressionType = enemyProgressionType,
Family = family,
EnemyType = enemies[0].EnemyNameString,
Enemies = enemies.Select(CloneEnemy).ToList(),
Guns = weapons.Select(CloneGun).ToList()
};
}
private static RuntimeEnemy CloneEnemy(RuntimeEnemy enemy)
{
return new RuntimeEnemy
{
EnemyNameString = enemy.EnemyNameString,
Value = enemy.Value
};
}
private static RuntimeGun CloneGun(RuntimeGun gun)
{
return new RuntimeGun
{
GunName = gun.GunName,
MagName = gun.MagName,
MagNames = new List<string>(gun.MagNames),
Extra = gun.Extra,
CategoryID = gun.CategoryID
};
}
private static List<FeedCandidate> GetCompatibleFeeds(List<RuntimeMetadataEntry> entries, IDictionary<string, RuntimeMetadataEntry> entriesById, RuntimeMetadataEntry firearm)
{
if (HasIds(firearm.CompatibleMagazines))
{
return GetDirectFeeds(firearm.CompatibleMagazines, entriesById, "Magazine");
}
if (HasIds(firearm.CompatibleClips))
{
return GetDirectFeeds(firearm.CompatibleClips, entriesById, "Clip");
}
if (HasIds(firearm.CompatibleSpeedLoaders))
{
return GetDirectFeeds(firearm.CompatibleSpeedLoaders, entriesById, "SpeedLoader");
}
if (HasIds(firearm.CompatibleSingleRounds))
{
return GetDirectFeeds(firearm.CompatibleSingleRounds, entriesById, "Cartridge");
}
if (firearm.MagazineType != 0)
{
return GetMatchingFeeds(entries, "Magazine", firearm.MagazineType, (RuntimeMetadataEntry entry) => entry.MagazineType, 0);
}
if (firearm.ClipType != 0)
{
List<FeedCandidate> matchingFeeds = GetMatchingFeeds(entries, "Clip", firearm.ClipType, (RuntimeMetadataEntry entry) => entry.ClipType, 1);
if (matchingFeeds.Count > 0)
{
return matchingFeeds;
}
}
if (firearm.RoundType != 0)
{
List<FeedCandidate> matchingFeeds2 = GetMatchingFeeds(entries, "SpeedLoader", firearm.RoundType, (RuntimeMetadataEntry entry) => entry.RoundType, 2);
if (matchingFeeds2.Count <= 0)
{
return GetMatchingFeeds(entries, "Cartridge", firearm.RoundType, (RuntimeMetadataEntry entry) => entry.RoundType, 2);
}
return matchingFeeds2;
}
return new List<FeedCandidate>();
}
private static List<FeedCandidate> GetDirectFeeds(List<string> objectIds, IDictionary<string, RuntimeMetadataEntry> entriesById, string category)
{
List<FeedCandidate> list = new List<FeedCandidate>();
foreach (string item in DistinctIds(objectIds))
{
if (entriesById.TryGetValue(item, out var value) && value.Category == category)
{
AddFeedCandidate(list, value);
}
}
return list;
}
private static List<FeedCandidate> GetMatchingFeeds(IEnumerable<RuntimeMetadataEntry> entries, string category, int expectedType, Func<RuntimeMetadataEntry, int> typeSelector, int categoryId)
{
List<FeedCandidate> list = new List<FeedCandidate>();
AddMatchingFeeds(list, entries, category, expectedType, typeSelector, categoryId);
return list;
}
private static void AddFeedCandidate(List<FeedCandidate> candidates, RuntimeMetadataEntry feed)
{
int num = FeedCategoryId(feed.Category);
if (num >= 0 && !candidates.Any((FeedCandidate candidate) => candidate.ObjectID == feed.ObjectID))
{
candidates.Add(new FeedCandidate(feed.ObjectID, num));
}
}
private static void AddMatchingFeeds(List<FeedCandidate> candidates, IEnumerable<RuntimeMetadataEntry> entries, string category, int expectedType, Func<RuntimeMetadataEntry, int> typeSelector, int categoryId)
{
if (expectedType == 0)
{
return;
}
foreach (RuntimeMetadataEntry entry in entries)
{
if (entry.Category == category && typeSelector(entry) == expectedType)
{
AddFeedCandidate(candidates, entry);
}
}
}
private static string SelectOptic(List<RuntimeMetadataEntry> entries, IDictionary<string, RuntimeMetadataEntry> entriesById, RuntimeMetadataEntry firearm, Random random)
{
string desiredKind = DesiredOpticKind(firearm);
List<RuntimeMetadataEntry> list = new List<RuntimeMetadataEntry>();
foreach (string item in firearm.BespokeAttachments ?? new List<string>())
{
if (entriesById.TryGetValue(item, out var value) && IsCompatibleOptic(value, firearm, desiredKind))
{
list.Add(value);
}
}
List<RuntimeMetadataEntry> list2 = PreferDedicatedCompactOptics(list, firearm);
if (list2.Count == 0)
{
list2 = PreferDedicatedCompactOptics(entries.Where((RuntimeMetadataEntry attachment) => IsCompatibleOptic(attachment, firearm, desiredKind)).ToList(), firearm);
}
List<RuntimeMetadataEntry> list3 = (from @group in list2.GroupBy<RuntimeMetadataEntry, string>((RuntimeMetadataEntry attachment) => attachment.ObjectID, StringComparer.Ordinal)
select @group.First()).OrderBy<RuntimeMetadataEntry, string>((RuntimeMetadataEntry attachment) => attachment.ObjectID, StringComparer.Ordinal).ToList();
if (list3.Count == 0)
{
return null;
}
return list3[random.Next(list3.Count)].ObjectID;
}
private static bool IsCompatibleOptic(RuntimeMetadataEntry attachment, RuntimeMetadataEntry firearm, string desiredKind)
{
if (attachment.Category == "Attachment" && attachment.OpticKind == desiredKind)
{
return HasSharedPhysicalMount(firearm.PhysicalMountTypes, attachment.PhysicalMountTypes);
}
return false;
}
private static bool HasSharedPhysicalMount(IEnumerable<string> firearmMounts, IEnumerable<string> attachmentMounts)
{
if (firearmMounts == null || attachmentMounts == null)
{
return false;
}
HashSet<string> firearmMountSet = new HashSet<string>(ResolvedMountTypes(firearmMounts), StringComparer.OrdinalIgnoreCase);
return ResolvedMountTypes(attachmentMounts).Any((string mount) => firearmMountSet.Contains(mount));
}
private static List<RuntimeMetadataEntry> PreferDedicatedCompactOptics(List<RuntimeMetadataEntry> candidates, RuntimeMetadataEntry firearm)
{
if (!IsCompact(firearm.FirearmSize))
{
return candidates;
}
List<string> dedicatedMounts = ResolvedMountTypes(firearm.PhysicalMountTypes).Where(IsDedicatedCompactOpticMount).ToList();
if (dedicatedMounts.Count == 0)
{
return candidates;
}
return candidates.Where((RuntimeMetadataEntry attachment) => HasSharedPhysicalMount(dedicatedMounts, attachment.PhysicalMountTypes)).ToList();
}
private static IEnumerable<string> ResolvedMountTypes(IEnumerable<string> mounts)
{
return (from resolution in (mounts ?? Enumerable.Empty<string>()).Select(MountResolution.Resolve)
where resolution.IsResolved
select resolution.CanonicalMount).Distinct<string>(StringComparer.OrdinalIgnoreCase);
}
private static bool IsDedicatedCompactOpticMount(string mount)
{
if (!string.Equals(mount, "Picatinny", StringComparison.OrdinalIgnoreCase) && !string.Equals(mount, "Suppressor", StringComparison.OrdinalIgnoreCase) && !string.Equals(mount, "Stock", StringComparison.OrdinalIgnoreCase) && !string.Equals(mount, "M203", StringComparison.OrdinalIgnoreCase) && !string.Equals(mount, "GP25", StringComparison.OrdinalIgnoreCase) && !string.Equals(mount, "AKFore", StringComparison.OrdinalIgnoreCase) && !string.Equals(mount, "MLokRail", StringComparison.OrdinalIgnoreCase) && mount.IndexOf("Bayonet", StringComparison.OrdinalIgnoreCase) < 0)
{
return mount.IndexOf("Foregrip", StringComparison.OrdinalIgnoreCase) < 0;
}
return false;
}
private static RuntimeEnemyEntry[] DefaultEnemies()
{
return new RuntimeEnemyEntry[1]
{
new RuntimeEnemyEntry
{
EnemyNameString = "RW_Rot",
DisplayName = "Rot",
IsSpawnable = true,
DifficultyScore = 1
}
};
}
private static bool IsCompact(string firearmSize)
{
if (!(firearmSize == "Pocket") && !(firearmSize == "Pistol"))
{
return firearmSize == "Compact";
}
return true;
}
private static string DesiredOpticKind(RuntimeMetadataEntry firearm)
{
if (!IsCompact(firearm.FirearmSize) || !ResolvedMountTypes(firearm.PhysicalMountTypes).Any(IsDedicatedCompactOpticMount))
{
return "Scope";
}
return "Reflex";
}
private static List<string> DistinctIds(params List<string>[] lists)
{
return (from id in lists.Where((List<string> list) => list != null).SelectMany((List<string> list) => list)
where !string.IsNullOrEmpty(id)
select id).Distinct<string>(StringComparer.Ordinal).ToList();
}
private static bool HasIds(List<string> values)
{
return values?.Any((string value) => !string.IsNullOrEmpty(value)) ?? false;
}
private static int FeedCategoryId(string category)
{
switch (category)
{
case "Magazine":
return 0;
case "Clip":
return 1;
case "SpeedLoader":
case "Cartridge":
return 2;
default:
return -1;
}
}
private static int RoundPowerRank(string roundPower)
{
return roundPower switch
{
"Tiny" => 1,
"Pistol" => 2,
"Shotgun" => 3,
"Intermediate" => 4,
"FullPower" => 5,
"AntiMaterial" => 6,
"Ordnance" => 7,
"Exotic" => 8,
"Fire" => 9,
_ => 10,
};
}
private static int SizeRank(string firearmSize)
{
return firearmSize switch
{
"Pocket" => 1,
"Pistol" => 2,
"Compact" => 3,
"Carbine" => 4,
"FullSize" => 5,
"Bulky" => 6,
"Oversize" => 7,
_ => 8,
};
}
}
}