using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using pworld.Scripts.Extensions;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Arman Ossi Loko")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Arman Ossi Loko")]
[assembly: AssemblyDescription("Scales PEAK forage food for lobbies larger than 4 players.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+db658f8820e70303e424f7141b803ff8594bd306")]
[assembly: AssemblyProduct("ExtraMouths")]
[assembly: AssemblyTitle("ExtraMouths")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
int ICollection.Count => _items.Length;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
object IList.this[int index]
{
get
{
return _items[index];
}
set
{
throw new NotSupportedException();
}
}
bool IList.IsFixedSize => true;
bool IList.IsReadOnly => true;
int IReadOnlyCollection<T>.Count => _items.Length;
T IReadOnlyList<T>.this[int index] => _items[index];
int ICollection<T>.Count => _items.Length;
bool ICollection<T>.IsReadOnly => true;
T IList<T>.this[int index]
{
get
{
return _items[index];
}
set
{
throw new NotSupportedException();
}
}
public <>z__ReadOnlyArray(T[] items)
{
_items = items;
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_items).GetEnumerator();
}
void ICollection.CopyTo(Array array, int index)
{
((ICollection)_items).CopyTo(array, index);
}
int IList.Add(object value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object value)
{
return ((IList)_items).Contains(value);
}
int IList.IndexOf(object value)
{
return ((IList)_items).IndexOf(value);
}
void IList.Insert(int index, object value)
{
throw new NotSupportedException();
}
void IList.Remove(object value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)_items).GetEnumerator();
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return ((ICollection<T>)_items).Contains(item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
((ICollection<T>)_items).CopyTo(array, arrayIndex);
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
return ((IList<T>)_items).IndexOf(item);
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}
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;
}
}
[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 BepInEx
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class BepInAutoPluginAttribute : Attribute
{
public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace BepInEx.Preloader.Core.Patching
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class PatcherAutoPluginAttribute : Attribute
{
public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace ExtraMouths
{
[BepInPlugin("ExtraMouths", "ExtraMouths", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(BerryBush))]
public static class BerryBushPatch
{
[HarmonyPrefix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPrefix(BerryBush __instance, ref List<Transform> spawnSpots, out Vector2 __state)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: 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_008a: Unknown result type (might be due to invalid IL or missing references)
__state = __instance.possibleBerries;
if (BerryBushes.Value && ShouldScale())
{
MultiplySpawnRange(ref __instance.possibleBerries, ref spawnSpots, out __state);
Vector2 possibleBerries = __instance.possibleBerries;
Log.LogInfo((object)$"[BerryBush] players={GetConnectedPlayerCount()} mult={GetMultiplier():0.###}x range {__state.x}-{__state.y} → {possibleBerries.x}-{possibleBerries.y}");
}
}
[HarmonyPostfix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPostfix(BerryBush __instance, Vector2 __state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
__instance.possibleBerries = __state;
}
}
[HarmonyPatch(typeof(BerryVine))]
public static class BerryVinePatch
{
[HarmonyPrefix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPrefix(BerryVine __instance, ref List<Transform> spawnSpots, out Vector2 __state)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: 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_008a: Unknown result type (might be due to invalid IL or missing references)
__state = __instance.possibleBerries;
if (BerryVines.Value && ShouldScale())
{
MultiplySpawnRange(ref __instance.possibleBerries, ref spawnSpots, out __state);
Vector2 possibleBerries = __instance.possibleBerries;
Log.LogInfo((object)$"[BerryVine] players={GetConnectedPlayerCount()} mult={GetMultiplier():0.###}x range {__state.x}-{__state.y} → {possibleBerries.x}-{possibleBerries.y}");
}
}
[HarmonyPostfix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPostfix(BerryVine __instance, Vector2 __state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
__instance.possibleBerries = __state;
}
}
[HarmonyPatch(typeof(GroundPlaceSpawner))]
public static class GroundPlaceSpawnerPatch
{
[HarmonyPrefix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPrefix(GroundPlaceSpawner __instance, ref List<Transform> spawnSpots, out Vector2 __state)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: 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_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
__state = __instance.possibleItems;
if (GroundSpawns.Value && ShouldScale())
{
float multiplier = GetMultiplier();
__instance.possibleItems *= multiplier;
Vector2 possibleItems = __instance.possibleItems;
float num = possibleItems.x - Mathf.Floor(possibleItems.x);
float num2 = possibleItems.y - Mathf.Floor(possibleItems.y);
possibleItems.x = ((Random.value < num) ? Mathf.Ceil(possibleItems.x) : Mathf.Floor(possibleItems.x));
possibleItems.y = ((Random.value < num2) ? Mathf.Ceil(possibleItems.y) : Mathf.Floor(possibleItems.y));
__instance.possibleItems = possibleItems;
float num3 = Math.Max(possibleItems.x, possibleItems.y);
if (num3 > (float)spawnSpots.Count)
{
List<Transform> collection = AddMoreSlotsUntil(spawnSpots, Mathf.CeilToInt(num3));
spawnSpots.Clear();
spawnSpots.AddRange(collection);
}
Log.LogInfo((object)$"[GroundPlace] players={GetConnectedPlayerCount()} mult={multiplier:0.###}x range {__state.x}-{__state.y} → {possibleItems.x}-{possibleItems.y}");
}
}
[HarmonyPostfix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPostfix(GroundPlaceSpawner __instance, Vector2 __state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
__instance.possibleItems = __state;
}
}
[HarmonyPatch(typeof(Spawner))]
public static class SpawnerPatch
{
private static bool IsConfiguredLuggage(Spawner spawner)
{
if (luggageSet.Count == 0)
{
return false;
}
Luggage val = (Luggage)(object)((spawner is Luggage) ? spawner : null);
if (val != null)
{
return luggageSet.Contains(val.displayName);
}
return false;
}
private static bool IsFoodPoolSpawner(Spawner spawner)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
if (!FoodSpawnPools.Value)
{
return false;
}
if ((spawner is BerryBush || spawner is BerryVine || spawner is GroundPlaceSpawner || spawner is Luggage) ? true : false)
{
return false;
}
return FoodPools.Contains(spawner.GetSpawnPool());
}
[HarmonyPrefix]
[HarmonyPatch("SpawnItems", new Type[] { typeof(List<Transform>) })]
public static void SpawnItemsPrefix(Spawner __instance, ref List<Transform> spawnSpots)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
if (ShouldScale())
{
bool flag = IsConfiguredLuggage(__instance);
bool flag2 = IsFoodPoolSpawner(__instance);
if (flag || flag2)
{
float multiplier = GetMultiplier();
List<Transform> collection = AddMoreSlots(spawnSpots, multiplier);
spawnSpots.Clear();
spawnSpots.AddRange(collection);
Log.LogInfo((object)$"[Spawner:{((Object)((Component)__instance).gameObject).name}] pool={__instance.spawnPool} players={GetConnectedPlayerCount()} mult={multiplier:0.###}x → {spawnSpots.Count} slots");
}
}
}
}
private static HashSet<string> luggageSet = new HashSet<string>();
private static readonly HashSet<SpawnPool> FoodPools = BuildFoodPools(new <>z__ReadOnlyArray<string>(new string[11]
{
"MushroomCluster", "BerryBushBeach", "BerryBushJungle", "SpikyVine", "CoconutTree", "WillowTreeJungle", "JungleVine", "WinterberryTree", "Nest", "Cactus",
"Redwood"
}));
public const string Id = "ExtraMouths";
internal static ManualLogSource Log { get; private set; } = null;
internal static ConfigEntry<int> ExtraPlayers { get; private set; } = null;
internal static ConfigEntry<int> BaselinePlayers { get; private set; } = null;
internal static ConfigEntry<int> MinPlayersToScale { get; private set; } = null;
internal static ConfigEntry<string> Luggages { get; private set; } = null;
internal static ConfigEntry<bool> GroundSpawns { get; private set; } = null;
internal static ConfigEntry<bool> BerryBushes { get; private set; } = null;
internal static ConfigEntry<bool> BerryVines { get; private set; } = null;
internal static ConfigEntry<bool> FoodSpawnPools { get; private set; } = null;
public static string Name => "ExtraMouths";
public static string Version => "1.0.0";
private static HashSet<SpawnPool> BuildFoodPools(IEnumerable<string> names)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
HashSet<SpawnPool> hashSet = new HashSet<SpawnPool>();
foreach (string name in names)
{
if (Enum.TryParse<SpawnPool>(name, ignoreCase: false, out SpawnPool result))
{
hashSet.Add(result);
}
}
return hashSet;
}
private void Awake()
{
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
ExtraPlayers = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "ExtraPlayers", 2, "Treat the lobby as this many extra mouths to feed. Multiplier = (connectedPlayers + ExtraPlayers) / BaselinePlayers.");
BaselinePlayers = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "BaselinePlayers", 4, "Vanilla balance player count. Food is scaled relative to this.");
MinPlayersToScale = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MinPlayersToScale", 5, "If connected players are below this, leave spawn rates fully vanilla. Default 5 so 4-player lobbies match the game.");
BerryBushes = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawners", "BerryBushes", true, "Scale berry bushes.");
BerryVines = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawners", "BerryVines", true, "Scale berry vines.");
GroundSpawns = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawners", "GroundSpawns", true, "Scale ground forage (e.g. mushrooms).");
FoodSpawnPools = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawners", "FoodSpawnPools", true, "Scale base Spawner food pools (coconuts, winterberries, kingberries, clusterberries, nests, cactus fruit, etc.).");
Luggages = ((BaseUnityPlugin)this).Config.Bind<string>("Spawners", "Luggages", "", "Optional: comma-separated luggage display names to also multiply (e.g. \"Luggage,Big Luggage,Explorer's Luggage\"). Empty = luggage untouched.");
luggageSet = BuildLuggageSet(Luggages.Value);
Luggages.SettingChanged += delegate
{
luggageSet = BuildLuggageSet(Luggages.Value);
};
Harmony val = new Harmony("ExtraMouths");
try
{
val.PatchAll();
Log.LogInfo((object)$"{Name} v{Version} loaded. Formula: (players + {ExtraPlayers.Value}) / {BaselinePlayers.Value}, skip if players < {MinPlayersToScale.Value}.");
}
catch (Exception arg)
{
Log.LogError((object)$"Failed to patch: {arg}");
}
}
private static HashSet<string> BuildLuggageSet(string raw)
{
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
if (string.IsNullOrWhiteSpace(raw))
{
return hashSet;
}
string[] array = raw.Split(',');
foreach (string text in array)
{
string text2 = text.Trim();
if (text2.Length > 0)
{
hashSet.Add(text2);
}
}
return hashSet;
}
internal static int GetConnectedPlayerCount()
{
if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null)
{
return PhotonNetwork.CurrentRoom.PlayerCount;
}
Player[] playerList = PhotonNetwork.PlayerList;
if (playerList == null)
{
return 0;
}
return playerList.Length;
}
internal static bool ShouldScale()
{
if (!PhotonNetwork.IsMasterClient)
{
return false;
}
int connectedPlayerCount = GetConnectedPlayerCount();
int num = Math.Max(1, MinPlayersToScale.Value);
return connectedPlayerCount >= num;
}
internal static float GetMultiplier()
{
if (!ShouldScale())
{
return 1f;
}
int connectedPlayerCount = GetConnectedPlayerCount();
int num = Math.Max(1, BaselinePlayers.Value);
int num2 = Math.Max(0, ExtraPlayers.Value);
return (float)(connectedPlayerCount + num2) / (float)num;
}
internal static List<Transform> AddMoreSlotsUntil(List<Transform> spawnSpots, int target, bool addRandom = false)
{
if (spawnSpots.Count == 0 || (target <= 0 && !addRandom))
{
return new List<Transform>();
}
int count = spawnSpots.Count;
List<Transform> list = new List<Transform>(Math.Max(0, target) + (addRandom ? 1 : 0));
while (target >= count)
{
list.AddRange(spawnSpots);
target -= count;
}
if (target > 0)
{
ExtCollections.Shuffle<Transform>((IList<Transform>)spawnSpots);
list.AddRange(spawnSpots.GetRange(0, target));
}
if (addRandom)
{
list.Add(spawnSpots[Random.Range(0, count)]);
}
return list;
}
internal static List<Transform> AddMoreSlots(List<Transform> spawnSpots, float multiplier)
{
if (spawnSpots.Count == 0 || multiplier <= 0f)
{
return new List<Transform>();
}
float num = (float)spawnSpots.Count * multiplier;
int num2 = Mathf.FloorToInt(num);
float num3 = num - (float)num2;
bool addRandom = Random.value < num3;
return AddMoreSlotsUntil(spawnSpots, num2, addRandom);
}
internal static void MultiplySpawnRange(ref Vector2 range, ref List<Transform> spawnSpots, out Vector2 original)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
original = range;
float multiplier = GetMultiplier();
range *= multiplier;
float num = Math.Max(range.x, range.y);
if (num > (float)spawnSpots.Count)
{
List<Transform> collection = AddMoreSlotsUntil(spawnSpots, Mathf.CeilToInt(num));
spawnSpots.Clear();
spawnSpots.AddRange(collection);
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}