Decompiled source of MorePlayers v0.2.0

plugins/MorePlayers.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MorePlayers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+f08f763ef75225fd68131819444998f59746f4bd")]
[assembly: AssemblyProduct("MorePlayers")]
[assembly: AssemblyTitle("MorePlayers")]
[assembly: AssemblyVersion("0.2.0.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 MorePlayers
{
	internal sealed class ConfigurationManagerAttributes
	{
		public string DispName;

		public int? Order;
	}
	[BepInPlugin("com.darkharasho.stonewards.moreplayers", "MorePlayers", "0.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.darkharasho.stonewards.moreplayers";

		public const string PluginName = "MorePlayers";

		public const string PluginVersion = "0.2.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> MaxPlayers;

		internal static ConfigEntry<float> EnemyCountPerExtraPlayer;

		internal static ConfigEntry<float> ResourceYieldPerExtraPlayer;

		internal static ConfigEntry<float> CombatDifficultyMultiplier;

		internal static ConfigEntry<float> ForgeCostMultiplier;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			MaxPlayers = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPlayers", 8, new ConfigDescription("Most players allowed in a hosted session, including the host. The game's default is 4. Only the host needs this mod; takes effect the next time you host.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 64), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Max players"
				}
			}));
			EnemyCountPerExtraPlayer = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "EnemyCountPerExtraPlayer", 0.25f, new ConfigDescription("Extra enemies per wave for each player beyond 4, as a fraction of the wave. 0.25 means 8 players fight twice as many enemies. 0 turns it off. Bosses and other single spawns are never multiplied.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Enemy count per extra player"
				}
			}));
			ResourceYieldPerExtraPlayer = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "ResourceYieldPerExtraPlayer", 0.15f, new ConfigDescription("Extra mining, enemy drop and barrel yield for each player beyond 4. 0.15 means 8 players get 1.6x. 0 turns it off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Resource yield per extra player"
				}
			}));
			CombatDifficultyMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "CombatDifficultyMultiplier", 1f, new ConfigDescription("Multiplies the game's own enemy strength scaling once there are more than 4 players. 1 leaves it as vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Combat difficulty multiplier"
				}
			}));
			ForgeCostMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "ForgeCostMultiplier", 1f, new ConfigDescription("Multiplies the game's own forge cost scaling once there are more than 4 players. 1 leaves it as vanilla. Applied in steps of about one player's worth of cost.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					DispName = "Forge cost multiplier"
				}
			}));
			_harmony = new Harmony("com.darkharasho.stonewards.moreplayers");
			_harmony.PatchAll();
			Log.LogInfo((object)string.Format("{0} {1} loaded (max players {2})", "MorePlayers", "0.2.0", MaxPlayers.Value));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace MorePlayers.Patches
{
	[HarmonyPatch(typeof(DifficultyManager), "OnStartServer")]
	internal static class ResetPlayerCountPatch
	{
		private static void Prefix()
		{
			Scaling.RealPlayerCount = 0;
		}
	}
	[HarmonyPatch(typeof(DifficultyManager), "SetPlayerCount")]
	internal static class DifficultyScalingPatch
	{
		private static readonly FieldRef<DifficultyManager, float> BaseCombatScaling = AccessTools.FieldRefAccess<DifficultyManager, float>("baseCombatScaling");

		private static readonly FieldRef<DifficultyManager, float> CombatScalingPerPlayer = AccessTools.FieldRefAccess<DifficultyManager, float>("combatScalingPerPlayer");

		private static readonly FieldRef<DifficultyManager, float> BaseForgeScaling = AccessTools.FieldRefAccess<DifficultyManager, float>("baseForgeScaling");

		private static readonly FieldRef<DifficultyManager, float> ForgeScalingPerPlayer = AccessTools.FieldRefAccess<DifficultyManager, float>("forgeScalingPerPlayer");

		private static readonly MethodInfo Recalculate = AccessTools.Method(typeof(DifficultyManager), "Recalculate", (Type[])null, (Type[])null);

		private static void Prefix(DifficultyManager __instance, ref int playerCount)
		{
			if (NetworkServer.active)
			{
				if (playerCount > Scaling.RealPlayerCount)
				{
					Scaling.RealPlayerCount = playerCount;
				}
				playerCount = ReportedForgeCount(__instance, playerCount);
			}
		}

		private static void Postfix(DifficultyManager __instance)
		{
			if (NetworkServer.active && Scaling.ExtraPlayers != 0)
			{
				float num = (BaseCombatScaling.Invoke(__instance) + CombatScalingPerPlayer.Invoke(__instance) * (float)Scaling.RealPlayerCount) * Plugin.CombatDifficultyMultiplier.Value;
				if (!Mathf.Approximately(__instance.NetworksyncPlayerFactor, num))
				{
					__instance.NetworksyncPlayerFactor = num;
					Recalculate.Invoke(__instance, null);
				}
			}
		}

		private static int ReportedForgeCount(DifficultyManager manager, int playerCount)
		{
			float value = Plugin.ForgeCostMultiplier.Value;
			if (playerCount <= 4 || value <= 1f)
			{
				return playerCount;
			}
			float num = BaseForgeScaling.Invoke(manager);
			float num2 = ForgeScalingPerPlayer.Invoke(manager);
			if (num2 <= 0f)
			{
				return playerCount;
			}
			float num3 = (num + num2 * (float)playerCount) * value;
			return Mathf.Max(playerCount, Mathf.RoundToInt((num3 - num) / num2));
		}
	}
	[HarmonyPatch(typeof(EnemyManager), "SpawnCurrentWave")]
	internal static class EnemyCountPatch
	{
		private static EnemyWaveDataSO _lastClone;

		private static void Prefix(ref EnemyWaveDataSO _Wave)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || (Object)(object)_Wave == (Object)null || _Wave.Enemies == null)
			{
				return;
			}
			float num = 1f + Plugin.EnemyCountPerExtraPlayer.Value * (float)Scaling.ExtraPlayers;
			if (num <= 1f)
			{
				return;
			}
			EnemyWaveDataSO val = Object.Instantiate<EnemyWaveDataSO>(_Wave);
			List<SEnemyData> enemies = val.Enemies;
			for (int i = 0; i < enemies.Count; i++)
			{
				SEnemyData val2 = enemies[i];
				if (!(val2.countRange.y <= 1f))
				{
					int num2 = Scaling.RandomRound(val2.countRange.x * num);
					int num3 = Mathf.Max(num2, Scaling.RandomRound(val2.countRange.y * num));
					val2.countRange = new Vector2((float)num2, (float)num3);
					enemies[i] = val2;
				}
			}
			if ((Object)(object)_lastClone != (Object)null)
			{
				Object.Destroy((Object)(object)_lastClone);
			}
			_lastClone = val;
			_Wave = val;
		}
	}
	[HarmonyPatch(typeof(StoneWardsNetworkManager), "Awake")]
	internal static class RaiseMaxConnectionsPatch
	{
		private static void Postfix(StoneWardsNetworkManager __instance)
		{
			Apply((NetworkManager)(object)__instance);
		}

		internal static void Apply(NetworkManager manager)
		{
			if (!((Object)(object)manager == (Object)null))
			{
				manager.maxConnections = Plugin.MaxPlayers.Value;
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "HostLobby")]
	internal static class RefreshBeforeHostPatch
	{
		private static void Prefix()
		{
			RaiseMaxConnectionsPatch.Apply(NetworkManager.singleton);
		}
	}
	[HarmonyPatch(typeof(HubPlayersNameHolder), "InitUI")]
	internal static class HubPlayerCountLabelPatch
	{
		private static void Postfix(ref int ___maxPlayerCount)
		{
			if (___maxPlayerCount > 1)
			{
				___maxPlayerCount = NetworkManager.singleton.maxConnections;
			}
		}
	}
	internal static class ResourceYield
	{
		internal static int ScopeDepth;

		private static bool _spawningExtra;

		internal static void SpawnExtras(Action spawn)
		{
			if (_spawningExtra || !NetworkServer.active)
			{
				return;
			}
			float num = 1f + Plugin.ResourceYieldPerExtraPlayer.Value * (float)Scaling.ExtraPlayers;
			if (num <= 1f)
			{
				return;
			}
			int num2 = Scaling.RandomRound(num - 1f);
			_spawningExtra = true;
			try
			{
				for (int i = 0; i < num2; i++)
				{
					spawn();
				}
			}
			finally
			{
				_spawningExtra = false;
			}
		}
	}
	[HarmonyPatch(typeof(DiggingManager), "ServerTrySpawnResource")]
	internal static class MiningScopePatch
	{
		private static void Prefix()
		{
			ResourceYield.ScopeDepth++;
		}

		private static void Finalizer()
		{
			ResourceYield.ScopeDepth--;
		}
	}
	[HarmonyPatch(typeof(ItemBarrel), "ServerInit")]
	internal static class BarrelScopePatch
	{
		private static void Prefix()
		{
			ResourceYield.ScopeDepth++;
		}

		private static void Finalizer()
		{
			ResourceYield.ScopeDepth--;
		}
	}
	[HarmonyPatch(typeof(ItemManager), "ServerInstantiatePickableItem")]
	internal static class PickableYieldPatch
	{
		private static void Postfix(ItemManager __instance, PickableItem __result, string _ItemID, int _Count, Vector3 _Position, bool forceShow, bool disableVfx)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			if (ResourceYield.ScopeDepth == 0 || (Object)(object)__result == (Object)null)
			{
				return;
			}
			Quaternion rotation = ((Component)__result).transform.rotation;
			ResourceYield.SpawnExtras(delegate
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				PickableItem val = __instance.ServerInstantiatePickableItem(_ItemID, _Count, _Position, forceShow, disableVfx);
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).transform.rotation = rotation;
				}
			});
		}
	}
	[HarmonyPatch(typeof(ItemManager), "ServerInstantiateEnemyDrop")]
	internal static class EnemyDropYieldPatch
	{
		private static void Postfix(ItemManager __instance, PickableItem __result, Vector3 _Position)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__result == (Object)null))
			{
				ResourceYield.SpawnExtras(delegate
				{
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					__instance.ServerInstantiateEnemyDrop(_Position);
				});
			}
		}
	}
	internal static class Scaling
	{
		internal const int VanillaMaxPlayers = 4;

		internal static int RealPlayerCount;

		internal static int ExtraPlayers => Math.Max(0, RealPlayerCount - 4);

		internal static int RandomRound(float value)
		{
			int num = Mathf.FloorToInt(value);
			return num + ((Random.value < value - (float)num) ? 1 : 0);
		}
	}
}