using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterTeamUpgrades.Config;
using BetterTeamUpgrades.Patches;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BetterTeamUpgrades")]
[assembly: AssemblyDescription("DLL for REPO mod.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("MrBytesized")]
[assembly: AssemblyProduct("BetterTeamUpgrades")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ef74d5e5-8fe6-4b6a-86ed-0e29e12695bb")]
[assembly: AssemblyFileVersion("2.2.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("2.2.0.0")]
namespace BetterTeamUpgrades
{
[BepInPlugin("MrBytesized.REPO.BetterTeamUpgrades", "Better Team Upgrades", "2.2.0")]
public class Plugin : BaseUnityPlugin
{
private const string mod_guid = "MrBytesized.REPO.BetterTeamUpgrades";
private const string mod_name = "Better Team Upgrades";
private const string mod_version = "2.2.0";
private readonly Harmony harmony = new Harmony("MrBytesized.REPO.BetterTeamUpgrades");
private static Plugin instance;
internal static ManualLogSource Log;
private (ConfigEntry<bool> configEntry, Action enablePatch, Action disablePatch, string description)[] _patchArray;
public static ConfigFile PlguinConfig;
internal static readonly object RandomLock = new object();
internal static readonly Random Random = new Random();
private void Awake()
{
if ((Object)(object)instance == (Object)null)
{
instance = this;
}
Log = Logger.CreateLogSource("MrBytesized.REPO.BetterTeamUpgrades");
PlguinConfig = ((BaseUnityPlugin)this).Config;
harmony.PatchAll(typeof(StatsManagerInitPatch));
Configuration.Init(PlguinConfig);
_patchArray = new(ConfigEntry<bool>, Action, Action, string)[2]
{
(Configuration.EnableSharedUpgradesPatch, delegate
{
harmony.PatchAll(typeof(SharedUpgradesPatch));
}, delegate
{
harmony.UnpatchSelf(typeof(SharedUpgradesPatch));
}, "Shared Upgrades"),
(Configuration.EnableLateJoinPlayerUpdateSyncPatch, delegate
{
harmony.PatchAll(typeof(LateJoinPlayerUpgradeSyncPatch));
}, delegate
{
harmony.UnpatchSelf(typeof(LateJoinPlayerUpgradeSyncPatch));
}, "Late Join Player Upgrade Sync")
};
(ConfigEntry<bool>, Action, Action, string)[] patchArray = _patchArray;
for (int i = 0; i < patchArray.Length; i++)
{
var (configEntry, enablePatch, disablePatch, description) = patchArray[i];
UpdatePatchFromConfig(configEntry, enablePatch, disablePatch, description);
configEntry.SettingChanged += delegate
{
UpdatePatchFromConfig(configEntry, enablePatch, disablePatch, description);
};
}
Log.LogInfo((object)"Better Team Upgrades mod has been activated");
}
private void UpdatePatchFromConfig(ConfigEntry<bool> configEntry, Action enablePatch, Action disablePatch, string description)
{
if (configEntry.Value)
{
try
{
enablePatch();
Log.LogInfo((object)(description + " patch enabled."));
return;
}
catch (Exception ex)
{
Log.LogError((object)("Failed to enable " + description + ": " + ex.Message));
return;
}
}
try
{
disablePatch();
Log.LogInfo((object)(description + " patch disabled."));
}
catch (Exception ex2)
{
Log.LogError((object)("Failed to disable " + description + ": " + ex2.Message));
}
}
internal static int Roll(int min, int max)
{
lock (RandomLock)
{
return Random.Next(min, max);
}
}
}
public static class HarmonyExtensions
{
public static void UnpatchSelf(this Harmony harmony, Type patchClass)
{
HarmonyPatch[] array = patchClass.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).OfType<HarmonyPatch>().ToArray();
for (int i = 0; i < array.Length; i++)
{
HarmonyMethod info = ((HarmonyAttribute)array[i]).info;
if (info == null)
{
Plugin.Log.LogWarning((object)("Invalid HarmonyPatch method info on class: " + patchClass.FullName));
continue;
}
MethodInfo methodInfo = ResolveOriginal(info);
if (methodInfo == null)
{
Plugin.Log.LogWarning((object)("Original method not found for class patch: " + FormatInfo(info)));
}
else
{
harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)0, harmony.Id);
}
}
MethodInfo[] methods = patchClass.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo2 in methods)
{
HarmonyPatch[] array2 = methodInfo2.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).OfType<HarmonyPatch>().ToArray();
if (array2.Length == 0)
{
continue;
}
array = array2;
for (int j = 0; j < array.Length; j++)
{
HarmonyMethod info2 = ((HarmonyAttribute)array[j]).info;
if (info2 == null)
{
Plugin.Log.LogWarning((object)("Invalid HarmonyPatch info on method: " + methodInfo2.DeclaringType.FullName + "." + methodInfo2.Name));
continue;
}
MethodInfo methodInfo3 = ResolveOriginal(info2);
if (methodInfo3 == null)
{
Plugin.Log.LogWarning((object)("Original method not found for method-level patch: " + FormatInfo(info2)));
}
else
{
harmony.Unpatch((MethodBase)methodInfo3, (HarmonyPatchType)0, harmony.Id);
}
}
}
}
private static MethodInfo ResolveOriginal(HarmonyMethod info)
{
if (info.method != null)
{
return info.method;
}
if (info.declaringType == null || string.IsNullOrEmpty(info.methodName))
{
return null;
}
return AccessTools.Method(info.declaringType, info.methodName, info.argumentTypes, (Type[])null);
}
private static string FormatInfo(HarmonyMethod info)
{
string obj = ((info.declaringType != null) ? info.declaringType.FullName : "<null>");
string text = ((!string.IsNullOrEmpty(info.methodName)) ? info.methodName : "<null>");
return obj + "." + text;
}
}
}
namespace BetterTeamUpgrades.Patches
{
[HarmonyPatch(typeof(PlayerAvatar), "Start")]
public class LateJoinPlayerUpgradeSyncPatch
{
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public string id;
public Func<PlayerAvatar, bool> <>9__2;
internal bool <SyncWithDelay>b__2(PlayerAvatar p)
{
return SemiFunc.PlayerGetSteamID(p) == id;
}
}
[CompilerGenerated]
private sealed class <SyncWithDelay>d__1 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public PlayerAvatar newPlayer;
private float <timeWaited>5__2;
private float <timeout>5__3;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <SyncWithDelay>d__1(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<timeWaited>5__2 = 0f;
<timeout>5__3 = 10f;
goto IL_006c;
case 1:
<>1__state = -1;
<timeWaited>5__2 += 0.5f;
goto IL_006c;
case 2:
{
<>1__state = -1;
if ((Object)(object)StatsManager.instance == (Object)null || (Object)(object)PunManager.instance == (Object)null)
{
return false;
}
PhotonView component = ((Component)PunManager.instance).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null)
{
Plugin.Log.LogWarning((object)"Late Join: PunManager PhotonView not found.");
return false;
}
string text = SemiFunc.PlayerGetSteamID(newPlayer);
if (string.IsNullOrEmpty(text))
{
Plugin.Log.LogWarning((object)$"Late Join: Timed out waiting for SteamID for player {newPlayer.photonView.ViewID}. Skipping sync.");
return false;
}
string text2 = (string)AccessTools.Field(typeof(PlayerAvatar), "playerName").GetValue(newPlayer);
Plugin.Log.LogInfo((object)("Late Join: Player " + text2 + " (" + text + ") is ready. Starting sync..."));
List<PlayerAvatar> source = SemiFunc.PlayerGetAll();
List<string> list = (from p in source
select SemiFunc.PlayerGetSteamID(p) into id
where !string.IsNullOrEmpty(id)
select id).ToList();
foreach (KeyValuePair<string, Dictionary<string, int>> dictionaryOfDictionary in StatsManager.instance.dictionaryOfDictionaries)
{
if (!dictionaryOfDictionary.Key.StartsWith("playerUpgrade"))
{
continue;
}
string key = dictionaryOfDictionary.Key;
Dictionary<string, int> value = dictionaryOfDictionary.Value;
bool flag = SharedUpgradesPatch.VanillaKeys.Contains(key);
string text3 = (flag ? "Vanilla Upgrade Settings" : "Modded Upgrade Settings");
string text4 = key.Replace("player", "");
if (!Plugin.PlguinConfig.Bind<bool>(text3, text4, true, "Enable upgrade syncing for " + key).Value)
{
Plugin.Log.LogInfo((object)("Late Join: Skipping " + key + " because config toggle '" + text3 + ":" + text4 + "' is disabled."));
continue;
}
if (!flag && !Configuration.EnableCustomUpgradeSyncing.Value)
{
Plugin.Log.LogInfo((object)("Late Join: Custom Upgrade Syncing is disabled. Skipping: " + key));
continue;
}
int num = 0;
foreach (string item in list)
{
if (value.TryGetValue(item, out var value2) && value2 > num)
{
num = value2;
}
}
if (num <= 0)
{
continue;
}
using List<string>.Enumerator enumerator2 = list.GetEnumerator();
while (enumerator2.MoveNext())
{
<>c__DisplayClass1_0 CS$<>8__locals0 = new <>c__DisplayClass1_0
{
id = enumerator2.Current
};
int num2 = (value.ContainsKey(CS$<>8__locals0.id) ? value[CS$<>8__locals0.id] : 0);
int num3 = num - num2;
if (num3 <= 0)
{
continue;
}
for (int i = 0; i < num3; i++)
{
Plugin.Log.LogInfo((object)("Late Join: Considering sync " + key + " for " + CS$<>8__locals0.id + " (+1)"));
int num4 = Plugin.Roll(0, 100);
if (num4 >= Configuration.LateJoinUpgradeSyncChance.Value)
{
Plugin.Log.LogInfo((object)$"Late Join: Skipped syncing {key} for {CS$<>8__locals0.id} due to chance roll ({num4} >= {Configuration.LateJoinUpgradeSyncChance.Value})");
continue;
}
if (flag)
{
string text5 = key.Substring("playerUpgrade".Length);
component.RPC("TesterUpgradeCommandRPC", (RpcTarget)1, new object[3] { CS$<>8__locals0.id, text5, 1 });
if (value.ContainsKey(CS$<>8__locals0.id))
{
value[CS$<>8__locals0.id]++;
}
else
{
value[CS$<>8__locals0.id] = 1;
}
}
else
{
component.RPC("UpdateStatRPC", (RpcTarget)1, new object[3]
{
key,
CS$<>8__locals0.id,
num2 + 1
});
value[CS$<>8__locals0.id] = num2 + 1;
}
string text6 = "Unknown";
PlayerAvatar val = ((IEnumerable<PlayerAvatar>)source).FirstOrDefault((Func<PlayerAvatar, bool>)((PlayerAvatar p) => SemiFunc.PlayerGetSteamID(p) == CS$<>8__locals0.id));
if ((Object)(object)val != (Object)null)
{
text6 = (string)AccessTools.Field(typeof(PlayerAvatar), "playerName").GetValue(val);
}
Plugin.Log.LogInfo((object)("Late Join: Synced " + key + " for " + text6 + " (+1)"));
num2++;
}
}
}
Plugin.Log.LogInfo((object)("Late Join: Sync complete for " + text2 + "."));
return false;
}
IL_006c:
if (string.IsNullOrEmpty(SemiFunc.PlayerGetSteamID(newPlayer)) && <timeWaited>5__2 < <timeout>5__3)
{
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 1;
return true;
}
<>2__current = (object)new WaitForSeconds(1f);
<>1__state = 2;
return true;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[HarmonyPostfix]
private static void Postfix(PlayerAvatar __instance)
{
if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)RunManager.instance.levelCurrent == (Object)(object)RunManager.instance.levelMainMenu) && !((Object)(object)RunManager.instance.levelCurrent == (Object)(object)RunManager.instance.levelLobbyMenu) && !((Object)(object)RunManager.instance.levelCurrent == (Object)(object)RunManager.instance.levelRecording) && !((Object)(object)RunManager.instance.levelCurrent == (Object)(object)RunManager.instance.levelSplashScreen))
{
((MonoBehaviour)__instance).StartCoroutine(SyncWithDelay(__instance));
}
}
[IteratorStateMachine(typeof(<SyncWithDelay>d__1))]
private static IEnumerator SyncWithDelay(PlayerAvatar newPlayer)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <SyncWithDelay>d__1(0)
{
newPlayer = newPlayer
};
}
}
[HarmonyPatch(typeof(ItemUpgrade), "PlayerUpgrade")]
public class SharedUpgradesPatch
{
public struct UpgradeContext
{
public string SteamID;
public int ViewID;
public string PlayerName;
public Dictionary<string, int> PreUpgradeStats;
}
public static HashSet<string> VanillaKeys = new HashSet<string>();
public static HashSet<string> ModdedKeys = new HashSet<string>();
[HarmonyPrefix]
public static void Prefix(ItemUpgrade __instance, out UpgradeContext __state)
{
__state = default(UpgradeContext);
if (!SemiFunc.IsMasterClientOrSingleplayer())
{
return;
}
object? value = AccessTools.Field(typeof(ItemUpgrade), "itemToggle").GetValue(__instance);
ItemToggle val = (ItemToggle)((value is ItemToggle) ? value : null);
if ((Object)(object)val == (Object)null || !val.toggleState)
{
return;
}
int num = (int)AccessTools.Field(typeof(ItemToggle), "playerTogglePhotonID").GetValue(val);
PlayerAvatar val2 = SemiFunc.PlayerAvatarGetFromPhotonID(num);
if ((Object)(object)val2 == (Object)null)
{
return;
}
string playerName = (string)AccessTools.Field(typeof(PlayerAvatar), "playerName").GetValue(val2);
string text = (string)AccessTools.Field(typeof(PlayerAvatar), "steamID").GetValue(val2);
Dictionary<string, int> dictionary = new Dictionary<string, int>();
if ((Object)(object)StatsManager.instance != (Object)null)
{
foreach (KeyValuePair<string, Dictionary<string, int>> dictionaryOfDictionary in StatsManager.instance.dictionaryOfDictionaries)
{
if (dictionaryOfDictionary.Key.StartsWith("playerUpgrade"))
{
if (dictionaryOfDictionary.Value.TryGetValue(text, out var value2))
{
dictionary[dictionaryOfDictionary.Key] = value2;
}
else
{
dictionary[dictionaryOfDictionary.Key] = 0;
}
}
}
}
__state = new UpgradeContext
{
SteamID = text,
ViewID = num,
PlayerName = playerName,
PreUpgradeStats = dictionary
};
}
[HarmonyPostfix]
public static void Postfix(ItemUpgrade __instance, UpgradeContext __state)
{
if (!SemiFunc.IsMasterClientOrSingleplayer() || string.IsNullOrEmpty(__state.SteamID) || (Object)(object)PunManager.instance == (Object)null)
{
return;
}
PhotonView component = ((Component)PunManager.instance).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null)
{
Plugin.Log.LogError((object)"SharedUpgrades: PunManager PhotonView not found!");
return;
}
foreach (KeyValuePair<string, Dictionary<string, int>> dictionaryOfDictionary in StatsManager.instance.dictionaryOfDictionaries)
{
if (!dictionaryOfDictionary.Key.StartsWith("playerUpgrade"))
{
continue;
}
bool flag = VanillaKeys.Contains(dictionaryOfDictionary.Key);
string text = (flag ? "Vanilla Upgrade Settings" : "Modded Upgrade Settings");
string text2 = dictionaryOfDictionary.Key.Replace("player", "");
if (!Plugin.PlguinConfig.Bind<bool>(text, text2, true, "Enable shared upgrade syncing for " + dictionaryOfDictionary.Key).Value)
{
Plugin.Log.LogInfo((object)("SharedUpgrades: Skipping " + dictionaryOfDictionary.Key + " because config toggle '" + text + ":" + text2 + "' is disabled."));
continue;
}
int num = (dictionaryOfDictionary.Value.ContainsKey(__state.SteamID) ? dictionaryOfDictionary.Value[__state.SteamID] : 0);
int num2 = (__state.PreUpgradeStats.ContainsKey(dictionaryOfDictionary.Key) ? __state.PreUpgradeStats[dictionaryOfDictionary.Key] : 0);
if (num > num2)
{
int num3 = num - num2;
string key = dictionaryOfDictionary.Key;
Plugin.Log.LogInfo((object)$"Detected upgrade: {key} (+{num3}) for {__state.PlayerName}({__state.SteamID})");
int num4 = Plugin.Roll(0, 100);
if (num4 >= Configuration.SharedUpgradeChance.Value)
{
Plugin.Log.LogInfo((object)$"Skipped syncing {key} due to chance roll ({num4} >= {Configuration.SharedUpgradeChance.Value})");
}
else if (flag)
{
string command = key.Substring("playerUpgrade".Length);
DistributeVanillaUpgrade(component, command, num3, __state);
}
else if (!Configuration.EnableCustomUpgradeSyncing.Value)
{
Plugin.Log.LogInfo((object)("Custom Upgrade Syncing is disabled. Skipping: " + key));
}
else
{
DistributeCustomUpgrade(component, key, num, __state);
}
}
}
}
private static void DistributeVanillaUpgrade(PhotonView punView, string command, int amount, UpgradeContext context)
{
foreach (PlayerAvatar item in SemiFunc.PlayerGetAll())
{
if ((Object)(object)item == (Object)null || (Object)(object)item.photonView == (Object)null)
{
continue;
}
if (item.photonView.ViewID == context.ViewID)
{
Plugin.Log.LogInfo((object)("Skipping original upgrader: " + command + " for " + context.PlayerName + "(" + context.SteamID + ")"));
continue;
}
string text = (string)AccessTools.Field(typeof(PlayerAvatar), "playerName").GetValue(item);
if (string.IsNullOrEmpty(text))
{
text = "Unknown";
}
string text2 = (string)AccessTools.Field(typeof(PlayerAvatar), "steamID").GetValue(item);
if (!string.IsNullOrEmpty(text2))
{
punView.RPC("TesterUpgradeCommandRPC", (RpcTarget)0, new object[3] { text2, command, amount });
Plugin.Log.LogInfo((object)("Synced Vanilla: " + command + " for " + text + "(" + text2 + ")"));
}
}
}
private static void DistributeCustomUpgrade(PhotonView punView, string dictionaryKey, int totalValue, UpgradeContext context)
{
foreach (PlayerAvatar item in SemiFunc.PlayerGetAll())
{
if ((Object)(object)item == (Object)null || (Object)(object)item.photonView == (Object)null)
{
continue;
}
if (item.photonView.ViewID == context.ViewID)
{
Plugin.Log.LogInfo((object)("Skipping original upgrader: " + dictionaryKey + " for " + context.PlayerName + "(" + context.SteamID + ")"));
continue;
}
string text = (string)AccessTools.Field(typeof(PlayerAvatar), "playerName").GetValue(item);
if (string.IsNullOrEmpty(text))
{
text = "Unknown";
}
string text2 = (string)AccessTools.Field(typeof(PlayerAvatar), "steamID").GetValue(item);
if (!string.IsNullOrEmpty(text2))
{
punView.RPC("UpdateStatRPC", (RpcTarget)0, new object[3] { dictionaryKey, text2, totalValue });
Plugin.Log.LogInfo((object)("Synced Custom: " + dictionaryKey + " for " + text + "(" + text2 + ")"));
}
}
}
}
[HarmonyPatch(typeof(StatsManager), "Start")]
public class StatsManagerInitPatch
{
[HarmonyPostfix]
public static void Postfix(StatsManager __instance)
{
SharedUpgradesPatch.VanillaKeys.Clear();
SharedUpgradesPatch.ModdedKeys.Clear();
HashSet<string> hashSet = (from f in typeof(StatsManager).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
select f.Name).ToHashSet();
foreach (string key in __instance.dictionaryOfDictionaries.Keys)
{
if (key.StartsWith("playerUpgrade"))
{
string text = key.Replace("player", "");
if (hashSet.Contains(key))
{
SharedUpgradesPatch.VanillaKeys.Add(key);
Plugin.PlguinConfig.Bind<bool>("Vanilla Upgrade Settings", text, true, "Enable shared upgrade syncing for " + key);
}
else
{
SharedUpgradesPatch.ModdedKeys.Add(key);
Plugin.PlguinConfig.Bind<bool>("Modded Upgrade Settings", text, true, "Enable shared upgrade syncing for modded upgrade " + key);
}
}
}
Plugin.Log.LogInfo((object)$"Auto-discovered {SharedUpgradesPatch.VanillaKeys.Count} vanilla upgrade keys and {SharedUpgradesPatch.ModdedKeys.Count} modded upgrade keys.");
}
}
}
namespace BetterTeamUpgrades.Config
{
internal class Configuration
{
public static ConfigEntry<bool> EnableSharedUpgradesPatch;
public static ConfigEntry<int> SharedUpgradeChance;
public static ConfigEntry<bool> EnableLateJoinPlayerUpdateSyncPatch;
public static ConfigEntry<int> LateJoinUpgradeSyncChance;
public static ConfigEntry<bool> EnableCustomUpgradeSyncing;
public static void Init(ConfigFile config)
{
//IL_0026: 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_0049: Expected O, but got Unknown
//IL_0049: Expected O, but got Unknown
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Expected O, but got Unknown
//IL_0097: Expected O, but got Unknown
EnableSharedUpgradesPatch = config.Bind<bool>("Shared Upgrade Settings", "EnableSharedUpgrades", true, "Enables Shared Upgrades for all supported Upgrades");
SharedUpgradeChance = config.Bind<int>(new ConfigDefinition("Shared Upgrade Settings", "SharedUpgradeChance"), 100, new ConfigDescription("The percentage chance (0-100) that an upgrade will be shared with team members when purchased.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
EnableLateJoinPlayerUpdateSyncPatch = config.Bind<bool>("Late Join Settings", "EnableLateJoinPlayerUpgradeSync", false, "Enables Upgrade Sync for Late Joining Players");
LateJoinUpgradeSyncChance = config.Bind<int>(new ConfigDefinition("Late Join Settings", "LateJoinUpgradeSyncChance"), 100, new ConfigDescription("The percentage chance (0-100) that a late joining player will receive each upgrade their team members have.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
EnableCustomUpgradeSyncing = config.Bind<bool>("Extra Sync Settings", "EnableCustomUpgradeSyncing", true, "Enables Custom Upgrade Syncing for Modded Upgrades (may cause issues with some mods)");
}
}
}