using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BepInEx;
using BepInEx.Unity.IL2CPP;
using GameData;
using HarmonyLib;
using MTFO.API;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ExtendedSurvivalWavePopulation")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ExtendedSurvivalWavePopulation")]
[assembly: AssemblyTitle("ExtendedSurvivalWavePopulation")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace ExtendedSurvivalWavePopulation
{
[BepInPlugin("com.gtfo.extendedsurvivalwavepopulation", "ExtendedSurvivalWavePopulation", "1.0.0")]
public sealed class ExtendedSurvivalWavePopulationStart : BasePlugin
{
public override void Load()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
PopulationConfig.Load();
MTFOHotReloadAPI.OnHotReload += OnMTFOHotReload;
new Harmony("com.gtfo.extendedsurvivalwavepopulation").PatchAll();
((BasePlugin)this).Log.LogInfo((object)"ExtendedSurvivalWavePopulation loaded");
}
private void OnMTFOHotReload()
{
PopulationConfig.Load();
((BasePlugin)this).Log.LogInfo((object)"ExtendedSurvivalWavePopulation config reloaded");
}
}
public sealed class WeightedEnemy
{
public uint ID { get; set; }
public float Weight { get; set; } = 1f;
}
public sealed class PopulationEntry
{
public uint PersistentID { get; set; }
public List<WeightedEnemy> WaveRoleWeakling { get; set; } = new List<WeightedEnemy>();
public List<WeightedEnemy> WaveRoleStandard { get; set; } = new List<WeightedEnemy>();
public List<WeightedEnemy> WaveRoleSpecial { get; set; } = new List<WeightedEnemy>();
public List<WeightedEnemy> WaveRoleMiniBoss { get; set; } = new List<WeightedEnemy>();
public List<WeightedEnemy> WaveRoleBoss { get; set; } = new List<WeightedEnemy>();
}
public sealed class PopulationSettings
{
public List<PopulationEntry> Populations { get; set; } = new List<PopulationEntry>();
}
public static class PopulationConfig
{
private static readonly Dictionary<uint, PopulationEntry> Entries = new Dictionary<uint, PopulationEntry>();
private static readonly Random Rng = new Random();
public static void Load()
{
string text = Path.Combine(MTFOPathAPI.CustomPath, "ExtendedSurvivalWavePopulationConfig");
string text2 = Path.Combine(text, "ExtendedSurvivalWavePopulation.jsonc");
Directory.CreateDirectory(text);
Console.WriteLine("[ExtendedSurvivalWavePopulation] Config path: " + text2);
if (!File.Exists(text2))
{
string contents = "{\n \"Populations\": [\n {\n \"PersistentID\": 8000, // SurvivalWavePopulation PersistentID you want to extend\n \"WaveRoleWeakling\": [], // Empty entries will have no changes\n \"WaveRoleStandard\": [\n {\n \"ID\": 24, // Enemy ID\n \"Weight\": 1.0 // Weight to spawn this enemy ID\n },\n {\n \"ID\": 21,\n \"Weight\": 1.0\n },\n {\n \"ID\": 30,\n \"Weight\": 1.0\n }\n ],\n \"WaveRoleSpecial\": [],\n \"WaveRoleMiniBoss\": [],\n \"WaveRoleBoss\": []\n }\n ]\n}";
File.WriteAllText(text2, contents);
Console.WriteLine("[ExtendedSurvivalWavePopulation] Created default config " + text2);
}
try
{
JsonSerializerOptions options = new JsonSerializerOptions
{
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
PropertyNameCaseInsensitive = true
};
PopulationSettings? populationSettings = JsonSerializer.Deserialize<PopulationSettings>(File.ReadAllText(text2), options);
Entries.Clear();
foreach (PopulationEntry item in populationSettings?.Populations ?? new List<PopulationEntry>())
{
Entries[item.PersistentID] = item;
}
}
catch (Exception ex)
{
Entries.Clear();
Console.WriteLine("[ExtendedSurvivalWavePopulation] Invalid config " + ex);
}
}
public static bool TrySelect(uint populationID, eEnemyType role, out EnemyDataBlock selected)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected I4, but got Unknown
selected = null;
if (!Entries.TryGetValue(populationID, out PopulationEntry value))
{
return false;
}
List<WeightedEnemy> list = (int)role switch
{
0 => value.WaveRoleWeakling,
1 => value.WaveRoleStandard,
2 => value.WaveRoleSpecial,
3 => value.WaveRoleMiniBoss,
4 => value.WaveRoleBoss,
_ => null,
};
if (list == null || list.Count == 0)
{
return false;
}
List<(EnemyDataBlock, double)> list2 = new List<(EnemyDataBlock, double)>();
foreach (WeightedEnemy item in list)
{
if (item != null && item.ID != 0 && !(item.Weight <= 0f) && !float.IsNaN(item.Weight) && !float.IsInfinity(item.Weight))
{
EnemyDataBlock block = GameDataBlockBase<EnemyDataBlock>.GetBlock(item.ID);
if (block != null)
{
list2.Add((block, item.Weight));
}
}
}
if (list2.Count == 0)
{
return false;
}
double num = list2.Sum<(EnemyDataBlock, double)>(((EnemyDataBlock data, double weight) c) => c.weight);
double num2;
lock (Rng)
{
num2 = Rng.NextDouble() * num;
}
foreach (var item2 in list2)
{
num2 -= item2.Item2;
if (num2 < 0.0)
{
(selected, _) = item2;
return true;
}
}
selected = list2[list2.Count - 1].Item1;
return true;
}
}
[HarmonyPatch(typeof(SurvivalWavePopulationDataBlock), "TryGetEnemyData")]
internal static class SurvivalWavePopulationPatch
{
[HarmonyPostfix]
private static void Postfix(SurvivalWavePopulationDataBlock __instance, eEnemyType waveRole, ref EnemyDataBlock enemyData, ref bool __result)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
if (PopulationConfig.TrySelect(((GameDataBlockBase<SurvivalWavePopulationDataBlock>)(object)__instance).persistentID, waveRole, out EnemyDataBlock selected))
{
enemyData = selected;
__result = true;
}
}
}
}