Decompiled source of ExtendedSurvivalWavePopulation v1.0.1

plugins/ExtendedSurvivalWavePopulation/ExtendedSurvivalWavePopulation.dll

Decompiled an hour ago
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;
			}
		}
	}
}