Decompiled source of ShuffleUpgrade v1.0.1

ShuffleUpgrade.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("zabu")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("zabumod")]
[assembly: AssemblyTitle("zabumod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 REPOJP.ShuffleUpgrade
{
	[BepInPlugin("jp.repo.shuffleupgrade", "ShuffleUpgrade", "1.4.0")]
	public sealed class ShuffleUpgradePlugin : BaseUnityPlugin
	{
		private enum UpgradeKind
		{
			Health,
			Stamina,
			ExtraJump,
			TumbleLaunch,
			TumbleClimb,
			MapPlayerCount,
			DeathHeadBattery,
			TumbleWings,
			SprintSpeed,
			CrouchRest,
			GrabStrength,
			Throw,
			GrabRange
		}

		private enum ShuffleMode
		{
			PreserveTypeTotalsRandom,
			FullRandomKeepGrandTotal,
			ReassignWholeBuilds,
			RandomPattern
		}

		private sealed class PlayerUpgradeBuild
		{
			public string SteamId;

			public string DisplayName;

			public readonly Dictionary<UpgradeKind, int> Values = new Dictionary<UpgradeKind, int>();
		}

		private sealed class ShuffleSnapshot
		{
			public readonly List<string> SteamIds = new List<string>();

			public readonly Dictionary<string, Dictionary<UpgradeKind, int>> Before = new Dictionary<string, Dictionary<UpgradeKind, int>>();

			public readonly Dictionary<string, Dictionary<UpgradeKind, int>> After = new Dictionary<string, Dictionary<UpgradeKind, int>>();

			public string ModeName = "";

			public int ShopVisitCount;
		}

		private sealed class PlayerBiasProfile
		{
			public readonly Dictionary<string, float> PlayerTotalWeight = new Dictionary<string, float>();

			public readonly Dictionary<string, Dictionary<UpgradeKind, float>> KindWeightByPlayer = new Dictionary<string, Dictionary<UpgradeKind, float>>();
		}

		[HarmonyPatch(typeof(PlayerAvatar), "ChatMessageSend")]
		private static class Patch_PlayerAvatar_ChatMessageSend
		{
			private static bool Prefix(PlayerAvatar __instance, string _message)
			{
				if ((Object)(object)Instance == (Object)null)
				{
					return true;
				}
				if (string.IsNullOrEmpty(_message))
				{
					return true;
				}
				if (!string.Equals(_message.Trim(), "/undo", StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				try
				{
					if ((Object)(object)__instance == (Object)null || !__instance.isLocal)
					{
						return true;
					}
				}
				catch
				{
					return true;
				}
				Instance.TryUndo();
				return false;
			}
		}

		public const string PluginGuid = "jp.repo.shuffleupgrade";

		public const string PluginName = "ShuffleUpgrade";

		public const string PluginVersion = "1.4.0";

		internal static ShuffleUpgradePlugin Instance;

		private Harmony _harmony;

		private bool _wasInShop;

		private bool _ranThisShopVisit;

		private int _shopVisitCount;

		private int _lastAppliedFrame = -1;

		private readonly Queue<ShuffleSnapshot> _undoHistory = new Queue<ShuffleSnapshot>();

		private Random _random;

		private ConfigEntry<bool> CfgEnabled;

		private ConfigEntry<bool> CfgHostOnlyInMultiplayer;

		private ConfigEntry<bool> CfgTriggerOnShopEnter;

		private ConfigEntry<bool> CfgRunOncePerShopVisit;

		private ConfigEntry<int> CfgShuffleEveryNLevels;

		private ConfigEntry<ShuffleMode> CfgShuffleMode;

		private ConfigEntry<bool> CfgEnableRandomPatternMode3;

		private ConfigEntry<bool> CfgCallStatSyncAll;

		private ConfigEntry<bool> CfgUseFixedSeed;

		private ConfigEntry<int> CfgFixedSeed;

		private ConfigEntry<int> CfgChaosRandom;

		private ConfigEntry<bool> CfgLogSummary;

		private ConfigEntry<bool> CfgLogDetails;

		private ConfigEntry<bool> CfgLogExcludedUpgrades;

		private ConfigEntry<bool> CfgEnableUndoCommand;

		private ConfigEntry<bool> CfgUndoRequireHost;

		private ConfigEntry<int> CfgUndoHistoryKeepCount;

		private ConfigEntry<bool> CfgEnableMaxClampSafety;

		private ConfigEntry<bool> CfgEnableMode0;

		private ConfigEntry<bool> CfgEnableMode1;

		private ConfigEntry<bool> CfgEnableMode2;

		private ConfigEntry<bool> CfgIncludeHealth;

		private ConfigEntry<bool> CfgIncludeStamina;

		private ConfigEntry<bool> CfgIncludeExtraJump;

		private ConfigEntry<bool> CfgIncludeTumbleLaunch;

		private ConfigEntry<bool> CfgIncludeTumbleClimb;

		private ConfigEntry<bool> CfgIncludeMapPlayerCount;

		private ConfigEntry<bool> CfgIncludeDeathHeadBattery;

		private ConfigEntry<bool> CfgIncludeTumbleWings;

		private ConfigEntry<bool> CfgIncludeSprintSpeed;

		private ConfigEntry<bool> CfgIncludeCrouchRest;

		private ConfigEntry<bool> CfgIncludeGrabStrength;

		private ConfigEntry<bool> CfgIncludeThrow;

		private ConfigEntry<bool> CfgIncludeGrabRange;

		private ConfigEntry<int> CfgMaxHealth;

		private ConfigEntry<int> CfgMaxStamina;

		private ConfigEntry<int> CfgMaxExtraJump;

		private ConfigEntry<int> CfgMaxTumbleLaunch;

		private ConfigEntry<int> CfgMaxTumbleClimb;

		private ConfigEntry<int> CfgMaxMapPlayerCount;

		private ConfigEntry<int> CfgMaxDeathHeadBattery;

		private ConfigEntry<int> CfgMaxTumbleWings;

		private ConfigEntry<int> CfgMaxSprintSpeed;

		private ConfigEntry<int> CfgMaxCrouchRest;

		private ConfigEntry<int> CfgMaxGrabStrength;

		private ConfigEntry<int> CfgMaxThrow;

		private ConfigEntry<int> CfgMaxGrabRange;

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Instance = this;
			BindConfigs();
			ResetRandom();
			_harmony = new Harmony("jp.repo.shuffleupgrade");
			_harmony.PatchAll(typeof(ShuffleUpgradePlugin));
			LogInfo("Loaded");
		}

		private void OnDestroy()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
		}

		private void Update()
		{
			if (!CfgEnabled.Value || !CanRunHere() || !SafeLevelGenDone())
			{
				return;
			}
			bool flag = SafeRunIsShop();
			if (flag && !_wasInShop)
			{
				_shopVisitCount++;
				_ranThisShopVisit = false;
				LogInfo($"Shop entered. Count={_shopVisitCount}");
			}
			if (!flag && _wasInShop)
			{
				_ranThisShopVisit = false;
			}
			if (flag && CfgTriggerOnShopEnter.Value)
			{
				if (CfgRunOncePerShopVisit.Value && _ranThisShopVisit)
				{
					_wasInShop = flag;
					return;
				}
				if (_lastAppliedFrame == Time.frameCount)
				{
					_wasInShop = flag;
					return;
				}
				int num = Mathf.Clamp(CfgShuffleEveryNLevels.Value, 1, 10);
				if (_shopVisitCount % num == 0)
				{
					TryShuffleNow("ShopEnter");
				}
				else
				{
					LogInfo($"Skip by interval. ShopCount={_shopVisitCount} Every={num}");
				}
			}
			_wasInShop = flag;
		}

		private void BindConfigs()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Expected O, but got Unknown
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Expected O, but got Unknown
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Expected O, but got Unknown
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Expected O, but got Unknown
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Expected O, but got Unknown
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Expected O, but got Unknown
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Expected O, but got Unknown
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Expected O, but got Unknown
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Expected O, but got Unknown
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Expected O, but got Unknown
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Expected O, but got Unknown
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Expected O, but got Unknown
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Expected O, but got Unknown
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Expected O, but got Unknown
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Expected O, but got Unknown
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Expected O, but got Unknown
			//IL_04db: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e5: Expected O, but got Unknown
			//IL_0507: Unknown result type (might be due to invalid IL or missing references)
			//IL_0511: Expected O, but got Unknown
			//IL_0533: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Expected O, but got Unknown
			//IL_055f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0569: Expected O, but got Unknown
			//IL_058b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0595: Expected O, but got Unknown
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c1: Expected O, but got Unknown
			//IL_05e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ed: Expected O, but got Unknown
			//IL_061d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0627: Expected O, but got Unknown
			//IL_0657: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Expected O, but got Unknown
			//IL_0691: Unknown result type (might be due to invalid IL or missing references)
			//IL_069b: Expected O, but got Unknown
			//IL_06cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d5: Expected O, but got Unknown
			//IL_0705: Unknown result type (might be due to invalid IL or missing references)
			//IL_070f: Expected O, but got Unknown
			//IL_073f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0749: Expected O, but got Unknown
			//IL_0779: Unknown result type (might be due to invalid IL or missing references)
			//IL_0783: Expected O, but got Unknown
			//IL_07b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bd: Expected O, but got Unknown
			//IL_07ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f7: Expected O, but got Unknown
			//IL_0827: Unknown result type (might be due to invalid IL or missing references)
			//IL_0831: Expected O, but got Unknown
			//IL_0861: Unknown result type (might be due to invalid IL or missing references)
			//IL_086b: Expected O, but got Unknown
			//IL_089b: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a5: Expected O, but got Unknown
			//IL_08cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d7: Expected O, but got Unknown
			CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Enable this mod.このMODを有効化", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgHostOnlyInMultiplayer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HostOnlyInMultiplayer", true, new ConfigDescription("Run only on host in multiplayer.マルチではホストのみ実行", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgTriggerOnShopEnter = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TriggerOnShopEnter", true, new ConfigDescription("Shuffle automatically when entering shop.ショップ入場時に自動シャッフル", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgRunOncePerShopVisit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RunOncePerShopVisit", true, new ConfigDescription("Run only once per shop visit.同一ショップ滞在中は1回だけ実行", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgShuffleEveryNLevels = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ShuffleEveryNLevels", 1, new ConfigDescription("Run shuffle every N shop visits.ショップ訪問N回ごとにシャッフル実行", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			CfgShuffleMode = ((BaseUnityPlugin)this).Config.Bind<ShuffleMode>("General", "ShuffleMode", ShuffleMode.FullRandomKeepGrandTotal, new ConfigDescription("Shuffle mode by name.PreserveTypeTotalsRandom / FullRandomKeepGrandTotal / ReassignWholeBuilds / RandomPattern の名前選択", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgEnableRandomPatternMode3 = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableRandomPatternMode3", true, new ConfigDescription("Allow RandomPattern mode execution.RandomPatternモード実行を許可", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgCallStatSyncAll = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CallStatSyncAll", true, new ConfigDescription("Call SemiFunc.StatSyncAll after apply.適用後にSemiFunc.StatSyncAllを呼ぶ", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgUseFixedSeed = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseFixedSeed", false, new ConfigDescription("Use fixed seed for reproducible results.再現性のため固定シードを使用", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgFixedSeed = ((BaseUnityPlugin)this).Config.Bind<int>("General", "FixedSeed", 12345, new ConfigDescription("Fixed random seed value.固定乱数シード値", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgChaosRandom = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ChaosRandom", 90, new ConfigDescription("Imbalance intensity for mode 0 and 1 from 0 to 100.モード0と1の偏り強度 0から100", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			CfgLogSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogSummary", true, new ConfigDescription("Log summary messages.サマリーログ出力", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgLogDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogDetails", false, new ConfigDescription("Log per-player details.プレイヤーごとの詳細ログ出力", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgLogExcludedUpgrades = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogExcludedUpgrades", true, new ConfigDescription("Log excluded upgrade list.除外アップグレード一覧を出力", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgEnableUndoCommand = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableUndoCommand", true, new ConfigDescription("Enable /undo command./undoコマンドを有効化", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgUndoRequireHost = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UndoRequireHost", true, new ConfigDescription("Require host for /undo in multiplayer.マルチ時の/undoをホスト限定", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgUndoHistoryKeepCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "UndoHistoryKeepCount", 1, new ConfigDescription("Number of undo snapshots to keep.Undo履歴保持件数", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
			CfgEnableMaxClampSafety = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMaxClampSafety", true, new ConfigDescription("Clamp each upgrade by max settings for safety.安全のため各アップグレードを上限クランプ", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgEnableMode0 = ((BaseUnityPlugin)this).Config.Bind<bool>("RandomPatternCandidates", "EnableMode_PreserveTypeTotalsRandom", true, new ConfigDescription("Include PreserveTypeTotalsRandom in RandomPattern.RandomPattern候補にPreserveTypeTotalsRandomを含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgEnableMode1 = ((BaseUnityPlugin)this).Config.Bind<bool>("RandomPatternCandidates", "EnableMode_FullRandomKeepGrandTotal", true, new ConfigDescription("Include FullRandomKeepGrandTotal in RandomPattern.RandomPattern候補にFullRandomKeepGrandTotalを含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgEnableMode2 = ((BaseUnityPlugin)this).Config.Bind<bool>("RandomPatternCandidates", "EnableMode_ReassignWholeBuilds", true, new ConfigDescription("Include ReassignWholeBuilds in RandomPattern.RandomPattern候補にReassignWholeBuildsを含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeHealth = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeHealth", true, new ConfigDescription("Include HEALTH in shuffle.HEALTHをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeStamina = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeStamina", true, new ConfigDescription("Include STAMINA in shuffle.STAMINAをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeExtraJump = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeExtraJump", true, new ConfigDescription("Include EXTRA JUMP in shuffle.EXTRA JUMPをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeTumbleLaunch = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeTumbleLaunch", true, new ConfigDescription("Include TUMBLE LAUNCH in shuffle.TUMBLE LAUNCHをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeTumbleClimb = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeTumbleClimb", true, new ConfigDescription("Include TUMBLE CLIMB in shuffle.TUMBLE CLIMBをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeMapPlayerCount = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeMapPlayerCount", false, new ConfigDescription("Include MAP PLAYER COUNT in shuffle.MAP PLAYER COUNTをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeDeathHeadBattery = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeDeathHeadBattery", true, new ConfigDescription("Include DEATH HEAD BATTERY in shuffle.DEATH HEAD BATTERYをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeTumbleWings = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeTumbleWings", true, new ConfigDescription("Include TUMBLE WINGS in shuffle.TUMBLE WINGSをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeSprintSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeSprintSpeed", true, new ConfigDescription("Include SPRINT SPEED in shuffle.SPRINT SPEEDをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeCrouchRest = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeCrouchRest", true, new ConfigDescription("Include CROUCH REST in shuffle.CROUCH RESTをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeGrabStrength = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeGrabStrength", true, new ConfigDescription("Include GRAB STRENGTH in shuffle.GRAB STRENGTHをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeThrow = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeThrow", false, new ConfigDescription("Include THROW in shuffle.THROWをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgIncludeGrabRange = ((BaseUnityPlugin)this).Config.Bind<bool>("IncludeUpgrade", "IncludeGrabRange", true, new ConfigDescription("Include GRAB RANGE in shuffle.GRAB RANGEをシャッフル対象に含める", (AcceptableValueBase)null, Array.Empty<object>()));
			CfgMaxHealth = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxHealth", 999, new ConfigDescription("Max HEALTH per player.1人あたりのHEALTH最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxStamina = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxStamina", 999, new ConfigDescription("Max STAMINA per player.1人あたりのSTAMINA最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxExtraJump = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxExtraJump", 999, new ConfigDescription("Max EXTRA JUMP per player.1人あたりのEXTRA JUMP最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxTumbleLaunch = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxTumbleLaunch", 999, new ConfigDescription("Max TUMBLE LAUNCH per player.1人あたりのTUMBLE LAUNCH最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxTumbleClimb = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxTumbleClimb", 999, new ConfigDescription("Max TUMBLE CLIMB per player.1人あたりのTUMBLE CLIMB最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxMapPlayerCount = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxMapPlayerCount", 999, new ConfigDescription("Max MAP PLAYER COUNT per player.1人あたりのMAP PLAYER COUNT最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxDeathHeadBattery = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxDeathHeadBattery", 999, new ConfigDescription("Max DEATH HEAD BATTERY per player.1人あたりのDEATH HEAD BATTERY最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxTumbleWings = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxTumbleWings", 999, new ConfigDescription("Max TUMBLE WINGS per player.1人あたりのTUMBLE WINGS最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxSprintSpeed = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxSprintSpeed", 999, new ConfigDescription("Max SPRINT SPEED per player.1人あたりのSPRINT SPEED最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxCrouchRest = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxCrouchRest", 999, new ConfigDescription("Max CROUCH REST per player.1人あたりのCROUCH REST最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxGrabStrength = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxGrabStrength", 999, new ConfigDescription("Max GRAB STRENGTH per player.1人あたりのGRAB STRENGTH最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxThrow = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxThrow", 999, new ConfigDescription("Max THROW per player.1人あたりのTHROW最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			CfgMaxGrabRange = ((BaseUnityPlugin)this).Config.Bind<int>("UpgradeMaxClamp", "MaxGrabRange", 8, new ConfigDescription("Max GRAB RANGE per player.1人あたりのGRAB RANGE最大値", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), Array.Empty<object>()));
		}

		private void ResetRandom()
		{
			if (CfgUseFixedSeed != null && CfgUseFixedSeed.Value)
			{
				_random = new Random(CfgFixedSeed.Value);
			}
			else
			{
				_random = new Random(Environment.TickCount ^ DateTime.Now.Millisecond);
			}
		}

		private bool CanRunHere()
		{
			if (CfgHostOnlyInMultiplayer.Value && SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient)
			{
				return false;
			}
			return true;
		}

		private bool SafeRunIsShop()
		{
			try
			{
				return SemiFunc.RunIsShop();
			}
			catch
			{
				return false;
			}
		}

		private bool SafeLevelGenDone()
		{
			try
			{
				return SemiFunc.LevelGenDone();
			}
			catch
			{
				return false;
			}
		}

		private void TryShuffleNow(string reason)
		{
			if (_lastAppliedFrame == Time.frameCount)
			{
				return;
			}
			List<PlayerUpgradeBuild> list = BuildPlayerList();
			if (list.Count <= 0)
			{
				LogInfo("Skip shuffle: no valid players");
				return;
			}
			List<UpgradeKind> includedKinds = GetIncludedKinds();
			if (includedKinds.Count <= 0)
			{
				LogInfo("Skip shuffle: no included upgrades");
				return;
			}
			if (CfgLogExcludedUpgrades.Value)
			{
				List<string> list2 = (from UpgradeKind k in Enum.GetValues(typeof(UpgradeKind))
					where !includedKinds.Contains(k)
					select k.ToString()).ToList();
				LogInfo("ExcludedUpgrades: " + string.Join(", ", list2.ToArray()));
			}
			ReadCurrentUpgrades(list);
			ShuffleMode shuffleMode = ResolveMode(CfgShuffleMode.Value, list.Count);
			ShuffleSnapshot shuffleSnapshot = new ShuffleSnapshot
			{
				ShopVisitCount = _shopVisitCount,
				ModeName = shuffleMode.ToString()
			};
			foreach (PlayerUpgradeBuild item in list)
			{
				shuffleSnapshot.SteamIds.Add(item.SteamId);
				shuffleSnapshot.Before[item.SteamId] = CloneValues(item.Values);
			}
			Dictionary<string, Dictionary<UpgradeKind, int>> targets = CreateTargets(list, includedKinds, shuffleMode);
			MergeExcludedValues(list, targets, includedKinds);
			ApplyClampToTargets(targets, includeExcluded: false, includedKinds);
			if (CfgLogDetails.Value)
			{
				LogPlayerValues("Before", list);
				LogTargets("Target", list, targets);
			}
			if (!ApplyTargetsWithBatchedDeltas(list, targets, includedKinds))
			{
				LogWarn("Shuffle apply failed");
				return;
			}
			ReadCurrentUpgrades(list);
			foreach (PlayerUpgradeBuild item2 in list)
			{
				shuffleSnapshot.After[item2.SteamId] = CloneValues(item2.Values);
			}
			EnqueueUndo(shuffleSnapshot);
			_ranThisShopVisit = true;
			_lastAppliedFrame = Time.frameCount;
			if (CfgLogSummary.Value)
			{
				LogInfo($"Shuffle applied. Reason={reason} Mode={shuffleMode} Players={list.Count} ShopCount={_shopVisitCount} ChaosRandom={CfgChaosRandom.Value}");
			}
			if (CfgLogDetails.Value)
			{
				LogPlayerValues("After", list);
			}
		}

		private List<PlayerUpgradeBuild> BuildPlayerList()
		{
			List<PlayerUpgradeBuild> list = new List<PlayerUpgradeBuild>();
			if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
			{
				return list;
			}
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player == (Object)null)
				{
					continue;
				}
				string text;
				try
				{
					text = player.steamID;
				}
				catch
				{
					text = "";
				}
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				string displayName = text;
				try
				{
					string text2 = SemiFunc.PlayerGetName(player);
					if (!string.IsNullOrEmpty(text2))
					{
						displayName = text2;
					}
				}
				catch
				{
				}
				PlayerUpgradeBuild playerUpgradeBuild = new PlayerUpgradeBuild
				{
					SteamId = text,
					DisplayName = displayName
				};
				foreach (UpgradeKind value in Enum.GetValues(typeof(UpgradeKind)))
				{
					playerUpgradeBuild.Values[value] = 0;
				}
				list.Add(playerUpgradeBuild);
			}
			return list.OrderBy<PlayerUpgradeBuild, string>((PlayerUpgradeBuild p) => p.SteamId, StringComparer.Ordinal).ToList();
		}

		private void ReadCurrentUpgrades(List<PlayerUpgradeBuild> players)
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			foreach (PlayerUpgradeBuild player in players)
			{
				player.Values[UpgradeKind.Health] = GetDictValue(instance.playerUpgradeHealth, player.SteamId);
				player.Values[UpgradeKind.Stamina] = GetDictValue(instance.playerUpgradeStamina, player.SteamId);
				player.Values[UpgradeKind.ExtraJump] = GetDictValue(instance.playerUpgradeExtraJump, player.SteamId);
				player.Values[UpgradeKind.TumbleLaunch] = GetDictValue(instance.playerUpgradeLaunch, player.SteamId);
				player.Values[UpgradeKind.TumbleClimb] = GetDictValue(instance.playerUpgradeTumbleClimb, player.SteamId);
				player.Values[UpgradeKind.MapPlayerCount] = GetDictValue(instance.playerUpgradeMapPlayerCount, player.SteamId);
				player.Values[UpgradeKind.DeathHeadBattery] = GetDictValue(instance.playerUpgradeDeathHeadBattery, player.SteamId);
				player.Values[UpgradeKind.TumbleWings] = GetDictValue(instance.playerUpgradeTumbleWings, player.SteamId);
				player.Values[UpgradeKind.SprintSpeed] = GetDictValue(instance.playerUpgradeSpeed, player.SteamId);
				player.Values[UpgradeKind.CrouchRest] = GetDictValue(instance.playerUpgradeCrouchRest, player.SteamId);
				player.Values[UpgradeKind.GrabStrength] = GetDictValue(instance.playerUpgradeStrength, player.SteamId);
				player.Values[UpgradeKind.Throw] = GetDictValue(instance.playerUpgradeThrow, player.SteamId);
				player.Values[UpgradeKind.GrabRange] = GetDictValue(instance.playerUpgradeRange, player.SteamId);
			}
		}

		private int GetDictValue(Dictionary<string, int> dict, string key)
		{
			if (dict == null || string.IsNullOrEmpty(key))
			{
				return 0;
			}
			if (dict.TryGetValue(key, out var value))
			{
				return Mathf.Max(0, value);
			}
			return 0;
		}

		private List<UpgradeKind> GetIncludedKinds()
		{
			List<UpgradeKind> list = new List<UpgradeKind>();
			if (CfgIncludeHealth.Value)
			{
				list.Add(UpgradeKind.Health);
			}
			if (CfgIncludeStamina.Value)
			{
				list.Add(UpgradeKind.Stamina);
			}
			if (CfgIncludeExtraJump.Value)
			{
				list.Add(UpgradeKind.ExtraJump);
			}
			if (CfgIncludeTumbleLaunch.Value)
			{
				list.Add(UpgradeKind.TumbleLaunch);
			}
			if (CfgIncludeTumbleClimb.Value)
			{
				list.Add(UpgradeKind.TumbleClimb);
			}
			if (CfgIncludeMapPlayerCount.Value)
			{
				list.Add(UpgradeKind.MapPlayerCount);
			}
			if (CfgIncludeDeathHeadBattery.Value)
			{
				list.Add(UpgradeKind.DeathHeadBattery);
			}
			if (CfgIncludeTumbleWings.Value)
			{
				list.Add(UpgradeKind.TumbleWings);
			}
			if (CfgIncludeSprintSpeed.Value)
			{
				list.Add(UpgradeKind.SprintSpeed);
			}
			if (CfgIncludeCrouchRest.Value)
			{
				list.Add(UpgradeKind.CrouchRest);
			}
			if (CfgIncludeGrabStrength.Value)
			{
				list.Add(UpgradeKind.GrabStrength);
			}
			if (CfgIncludeThrow.Value)
			{
				list.Add(UpgradeKind.Throw);
			}
			if (CfgIncludeGrabRange.Value)
			{
				list.Add(UpgradeKind.GrabRange);
			}
			return list;
		}

		private ShuffleMode ResolveMode(ShuffleMode configured, int playerCount)
		{
			if (configured == ShuffleMode.RandomPattern && !CfgEnableRandomPatternMode3.Value)
			{
				return ShuffleMode.PreserveTypeTotalsRandom;
			}
			if (configured == ShuffleMode.ReassignWholeBuilds && playerCount < 2)
			{
				return ShuffleMode.PreserveTypeTotalsRandom;
			}
			if (configured != ShuffleMode.RandomPattern)
			{
				return configured;
			}
			List<ShuffleMode> list = new List<ShuffleMode>();
			if (CfgEnableMode0.Value)
			{
				list.Add(ShuffleMode.PreserveTypeTotalsRandom);
			}
			if (CfgEnableMode1.Value)
			{
				list.Add(ShuffleMode.FullRandomKeepGrandTotal);
			}
			if (CfgEnableMode2.Value && playerCount >= 2)
			{
				list.Add(ShuffleMode.ReassignWholeBuilds);
			}
			if (list.Count <= 0)
			{
				return ShuffleMode.PreserveTypeTotalsRandom;
			}
			int index = _random.Next(list.Count);
			return list[index];
		}

		private Dictionary<string, Dictionary<UpgradeKind, int>> CreateTargets(List<PlayerUpgradeBuild> players, List<UpgradeKind> includedKinds, ShuffleMode mode)
		{
			Dictionary<string, Dictionary<UpgradeKind, int>> dictionary = new Dictionary<string, Dictionary<UpgradeKind, int>>();
			foreach (PlayerUpgradeBuild player in players)
			{
				dictionary[player.SteamId] = new Dictionary<UpgradeKind, int>();
				foreach (UpgradeKind value in Enum.GetValues(typeof(UpgradeKind)))
				{
					dictionary[player.SteamId][value] = 0;
				}
			}
			PlayerBiasProfile profile = BuildBiasProfiles(players, includedKinds);
			switch (mode)
			{
			case ShuffleMode.PreserveTypeTotalsRandom:
				CreateTargetsMode0(players, includedKinds, dictionary, profile);
				break;
			case ShuffleMode.FullRandomKeepGrandTotal:
				CreateTargetsMode1(players, includedKinds, dictionary, profile);
				break;
			case ShuffleMode.ReassignWholeBuilds:
				CreateTargetsMode2(players, includedKinds, dictionary);
				break;
			default:
				CreateTargetsMode0(players, includedKinds, dictionary, profile);
				break;
			}
			return dictionary;
		}

		private PlayerBiasProfile BuildBiasProfiles(List<PlayerUpgradeBuild> players, List<UpgradeKind> includedKinds)
		{
			PlayerBiasProfile playerBiasProfile = new PlayerBiasProfile();
			int num = Mathf.Clamp(CfgChaosRandom.Value, 0, 100);
			float num2 = (float)num / 100f;
			foreach (PlayerUpgradeBuild player in players)
			{
				float num3 = Mathf.Lerp(1f, 0.9f, num2);
				float num4 = Mathf.Lerp(1f, 1.15f, num2);
				float value = Mathf.Lerp(num3, num4, (float)_random.NextDouble());
				playerBiasProfile.PlayerTotalWeight[player.SteamId] = value;
			}
			foreach (PlayerUpgradeBuild player2 in players)
			{
				Dictionary<UpgradeKind, float> dictionary = new Dictionary<UpgradeKind, float>();
				foreach (UpgradeKind includedKind in includedKinds)
				{
					dictionary[includedKind] = 1f;
				}
				if (includedKinds.Count <= 0)
				{
					playerBiasProfile.KindWeightByPlayer[player2.SteamId] = dictionary;
					continue;
				}
				int num5 = Mathf.Max(1, includedKinds.Count);
				int num6 = Mathf.Clamp(1 + (int)Mathf.Floor(num2 * (float)Mathf.Min(3, num5 - 1)), 1, num5);
				int num7 = Mathf.Clamp(1 + (int)Mathf.Floor(num2 * (float)Mathf.Min(3, num5 - 1)), 1, num5);
				List<UpgradeKind> list = includedKinds.OrderBy((UpgradeKind _) => _random.Next()).ToList();
				for (int i = 0; i < num6 && i < list.Count; i++)
				{
					UpgradeKind key = list[i];
					float num8 = Mathf.Lerp(1f, 3.5f, num2);
					dictionary[key] *= num8;
				}
				for (int j = 0; j < num7 && j < list.Count; j++)
				{
					UpgradeKind key2 = list[list.Count - 1 - j];
					float num9 = Mathf.Lerp(1f, 0.3f, num2);
					dictionary[key2] *= num9;
				}
				bool flag = false;
				foreach (UpgradeKind includedKind2 in includedKinds)
				{
					dictionary[includedKind2] = Mathf.Clamp(dictionary[includedKind2], 0.1f, 100f);
					if (dictionary[includedKind2] >= 1.2f)
					{
						flag = true;
					}
				}
				if (!flag && includedKinds.Count > 0)
				{
					UpgradeKind key3 = includedKinds[_random.Next(includedKinds.Count)];
					dictionary[key3] = Mathf.Max(dictionary[key3], Mathf.Lerp(1.4f, 2.4f, num2));
				}
				playerBiasProfile.KindWeightByPlayer[player2.SteamId] = dictionary;
			}
			return playerBiasProfile;
		}

		private void CreateTargetsMode0(List<PlayerUpgradeBuild> players, List<UpgradeKind> includedKinds, Dictionary<string, Dictionary<UpgradeKind, int>> targets, PlayerBiasProfile profile)
		{
			int num = 0;
			Dictionary<UpgradeKind, int> dictionary = new Dictionary<UpgradeKind, int>();
			foreach (UpgradeKind includedKind in includedKinds)
			{
				int num2 = 0;
				foreach (PlayerUpgradeBuild player in players)
				{
					num2 += Mathf.Max(0, player.Values[includedKind]);
				}
				dictionary[includedKind] = num2;
				num += num2;
			}
			Dictionary<string, int> dictionary2 = BuildPlayerQuotas(players, num, profile);
			Dictionary<string, Dictionary<UpgradeKind, int>> caps = BuildRemainingCaps(players);
			foreach (UpgradeKind includedKind2 in includedKinds)
			{
				for (int num3 = dictionary[includedKind2]; num3 > 0; num3--)
				{
					List<PlayerUpgradeBuild> list = new List<PlayerUpgradeBuild>();
					foreach (PlayerUpgradeBuild player2 in players)
					{
						if (HasCapacity(player2.SteamId, includedKind2, caps))
						{
							int num4 = SumIncludedForPlayer(targets[player2.SteamId], includedKinds);
							int num5 = dictionary2[player2.SteamId];
							int num6 = Mathf.Max(1, num3 / Mathf.Max(1, players.Count));
							if (num4 <= num5 + num6)
							{
								list.Add(player2);
							}
						}
					}
					if (list.Count <= 0)
					{
						foreach (PlayerUpgradeBuild player3 in players)
						{
							if (HasCapacity(player3.SteamId, includedKind2, caps))
							{
								list.Add(player3);
							}
						}
					}
					if (list.Count <= 0)
					{
						break;
					}
					PlayerUpgradeBuild playerUpgradeBuild = WeightedPickPlayerForKindMode0(list, includedKind2, targets, includedKinds, dictionary2, profile);
					targets[playerUpgradeBuild.SteamId][includedKind2]++;
					ConsumeCap(playerUpgradeBuild.SteamId, includedKind2, caps);
				}
			}
			RebalanceMode0PlayerTotals(players, includedKinds, targets, dictionary2);
		}

		private void CreateTargetsMode1(List<PlayerUpgradeBuild> players, List<UpgradeKind> includedKinds, Dictionary<string, Dictionary<UpgradeKind, int>> targets, PlayerBiasProfile profile)
		{
			int num = 0;
			foreach (PlayerUpgradeBuild player in players)
			{
				foreach (UpgradeKind includedKind in includedKinds)
				{
					num += Mathf.Max(0, player.Values[includedKind]);
				}
			}
			Dictionary<string, int> dictionary = BuildPlayerQuotas(players, num, profile);
			Dictionary<string, Dictionary<UpgradeKind, int>> caps = BuildRemainingCaps(players);
			foreach (PlayerUpgradeBuild player2 in players)
			{
				for (int num2 = dictionary[player2.SteamId]; num2 > 0; num2--)
				{
					List<UpgradeKind> list = new List<UpgradeKind>();
					foreach (UpgradeKind includedKind2 in includedKinds)
					{
						if (HasCapacity(player2.SteamId, includedKind2, caps))
						{
							list.Add(includedKind2);
						}
					}
					if (list.Count <= 0)
					{
						break;
					}
					UpgradeKind upgradeKind = WeightedPickKindForPlayerMode1(player2.SteamId, list, targets[player2.SteamId], includedKinds, profile);
					targets[player2.SteamId][upgradeKind]++;
					ConsumeCap(player2.SteamId, upgradeKind, caps);
				}
			}
			int num3 = 0;
			foreach (PlayerUpgradeBuild player3 in players)
			{
				num3 += SumIncludedForPlayer(targets[player3.SteamId], includedKinds);
			}
			for (int num4 = num - num3; num4 > 0; num4--)
			{
				List<PlayerUpgradeBuild> list2 = new List<PlayerUpgradeBuild>();
				foreach (PlayerUpgradeBuild player4 in players)
				{
					bool flag = false;
					foreach (UpgradeKind includedKind3 in includedKinds)
					{
						if (HasCapacity(player4.SteamId, includedKind3, caps))
						{
							flag = true;
							break;
						}
					}
					if (flag)
					{
						list2.Add(player4);
					}
				}
				if (list2.Count <= 0)
				{
					break;
				}
				PlayerUpgradeBuild playerUpgradeBuild = WeightedPickPlayerByTotalNeed(list2, targets, includedKinds, dictionary, profile);
				List<UpgradeKind> list3 = new List<UpgradeKind>();
				foreach (UpgradeKind includedKind4 in includedKinds)
				{
					if (HasCapacity(playerUpgradeBuild.SteamId, includedKind4, caps))
					{
						list3.Add(includedKind4);
					}
				}
				if (list3.Count <= 0)
				{
					break;
				}
				UpgradeKind upgradeKind2 = WeightedPickKindForPlayerMode1(playerUpgradeBuild.SteamId, list3, targets[playerUpgradeBuild.SteamId], includedKinds, profile);
				targets[playerUpgradeBuild.SteamId][upgradeKind2]++;
				ConsumeCap(playerUpgradeBuild.SteamId, upgradeKind2, caps);
			}
		}

		private void CreateTargetsMode2(List<PlayerUpgradeBuild> players, List<UpgradeKind> includedKinds, Dictionary<string, Dictionary<UpgradeKind, int>> targets)
		{
			if (players.Count < 2)
			{
				foreach (PlayerUpgradeBuild player in players)
				{
					foreach (UpgradeKind includedKind in includedKinds)
					{
						targets[player.SteamId][includedKind] = Mathf.Max(0, player.Values[includedKind]);
					}
				}
				return;
			}
			List<int> list = BuildDerangement(players.Count);
			for (int i = 0; i < players.Count; i++)
			{
				int index = list[i];
				foreach (UpgradeKind includedKind2 in includedKinds)
				{
					targets[players[i].SteamId][includedKind2] = Mathf.Max(0, players[index].Values[includedKind2]);
				}
			}
		}

		private Dictionary<string, int> BuildPlayerQuotas(List<PlayerUpgradeBuild> players, int grandTotal, PlayerBiasProfile profile)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			int num = Mathf.Max(1, players.Count);
			int value = grandTotal / num;
			int num2 = grandTotal % num;
			foreach (PlayerUpgradeBuild player in players)
			{
				dictionary[player.SteamId] = value;
			}
			if (num2 > 0)
			{
				float num3 = 0f;
				Dictionary<string, float> dictionary2 = new Dictionary<string, float>();
				foreach (PlayerUpgradeBuild player2 in players)
				{
					float num4 = 1f;
					if (profile != null && profile.PlayerTotalWeight.ContainsKey(player2.SteamId))
					{
						num4 = Mathf.Max(0.01f, profile.PlayerTotalWeight[player2.SteamId]);
					}
					dictionary2[player2.SteamId] = num4;
					num3 += num4;
				}
				while (num2 > 0)
				{
					dictionary[WeightedPickSteamId(dictionary2, num3)]++;
					num2--;
				}
			}
			return dictionary;
		}

		private PlayerUpgradeBuild WeightedPickPlayerForKindMode0(List<PlayerUpgradeBuild> candidates, UpgradeKind kind, Dictionary<string, Dictionary<UpgradeKind, int>> targets, List<UpgradeKind> includedKinds, Dictionary<string, int> playerQuotas, PlayerBiasProfile profile)
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>();
			float num = 0f;
			foreach (PlayerUpgradeBuild candidate in candidates)
			{
				float num2 = 1f;
				if (profile != null && profile.KindWeightByPlayer.ContainsKey(candidate.SteamId) && profile.KindWeightByPlayer[candidate.SteamId].ContainsKey(kind))
				{
					num2 = Mathf.Max(0.05f, profile.KindWeightByPlayer[candidate.SteamId][kind]);
				}
				int num3 = SumIncludedForPlayer(targets[candidate.SteamId], includedKinds);
				int num4 = playerQuotas[candidate.SteamId];
				float num5 = ((num3 >= num4) ? (0.65f / (1f + (float)(num3 - num4) * 0.25f)) : (1.25f + (float)(num4 - num3) * 0.15f));
				float num6 = Mathf.Clamp(num2 * num5, 0.01f, 100000f);
				dictionary[candidate.SteamId] = num6;
				num += num6;
			}
			string selectedId = WeightedPickSteamId(dictionary, num);
			return candidates.First((PlayerUpgradeBuild x) => x.SteamId == selectedId);
		}

		private PlayerUpgradeBuild WeightedPickPlayerByTotalNeed(List<PlayerUpgradeBuild> candidates, Dictionary<string, Dictionary<UpgradeKind, int>> targets, List<UpgradeKind> includedKinds, Dictionary<string, int> playerQuotas, PlayerBiasProfile profile)
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>();
			float num = 0f;
			foreach (PlayerUpgradeBuild candidate in candidates)
			{
				int num2 = SumIncludedForPlayer(targets[candidate.SteamId], includedKinds);
				int num3 = (playerQuotas.ContainsKey(candidate.SteamId) ? playerQuotas[candidate.SteamId] : 0);
				float num4 = 1f + (float)Mathf.Max(0, num3 - num2) * 0.2f;
				float num5 = 1f;
				if (profile != null && profile.PlayerTotalWeight.ContainsKey(candidate.SteamId))
				{
					num5 = Mathf.Max(0.05f, profile.PlayerTotalWeight[candidate.SteamId]);
				}
				float num6 = Mathf.Clamp(num4 * num5, 0.01f, 100000f);
				dictionary[candidate.SteamId] = num6;
				num += num6;
			}
			string selectedId = WeightedPickSteamId(dictionary, num);
			return candidates.First((PlayerUpgradeBuild x) => x.SteamId == selectedId);
		}

		private UpgradeKind WeightedPickKindForPlayerMode1(string steamId, List<UpgradeKind> kindCandidates, Dictionary<UpgradeKind, int> currentMap, List<UpgradeKind> includedKinds, PlayerBiasProfile profile)
		{
			Dictionary<UpgradeKind, float> dictionary = new Dictionary<UpgradeKind, float>();
			float num = 0f;
			foreach (UpgradeKind kindCandidate in kindCandidates)
			{
				float num2 = 1f;
				if (profile != null && profile.KindWeightByPlayer.ContainsKey(steamId) && profile.KindWeightByPlayer[steamId].ContainsKey(kindCandidate))
				{
					num2 = Mathf.Max(0.05f, profile.KindWeightByPlayer[steamId][kindCandidate]);
				}
				int num3 = (currentMap.ContainsKey(kindCandidate) ? currentMap[kindCandidate] : 0);
				float num4 = 1f / (1f + (float)num3 * 0.12f);
				float num5 = Mathf.Clamp01((float)CfgChaosRandom.Value / 100f);
				num4 = Mathf.Lerp(num4, 1f, num5 * 0.55f);
				float num7 = (dictionary[kindCandidate] = Mathf.Clamp(num2 * num4, 0.01f, 100000f));
				num += num7;
			}
			return WeightedPickKind(dictionary, num);
		}

		private void RebalanceMode0PlayerTotals(List<PlayerUpgradeBuild> players, List<UpgradeKind> includedKinds, Dictionary<string, Dictionary<UpgradeKind, int>> targets, Dictionary<string, int> playerQuotas)
		{
			if (players.Count < 2)
			{
				return;
			}
			int num = players.Count * includedKinds.Count * 8;
			for (int i = 0; i < num; i++)
			{
				PlayerUpgradeBuild playerUpgradeBuild = null;
				PlayerUpgradeBuild playerUpgradeBuild2 = null;
				int num2 = 0;
				int num3 = 0;
				foreach (PlayerUpgradeBuild player in players)
				{
					int num4 = SumIncludedForPlayer(targets[player.SteamId], includedKinds);
					int num5 = playerQuotas[player.SteamId];
					int num6 = num5 - num4;
					if (num6 > num2)
					{
						num2 = num6;
						playerUpgradeBuild = player;
					}
					if (-num6 > num3)
					{
						num3 = -num6;
						playerUpgradeBuild2 = player;
					}
				}
				if (playerUpgradeBuild == null || playerUpgradeBuild2 == null || num2 <= 0 || num3 <= 0)
				{
					break;
				}
				UpgradeKind? upgradeKind = null;
				float num7 = float.MinValue;
				foreach (UpgradeKind includedKind in includedKinds)
				{
					int num8 = targets[playerUpgradeBuild2.SteamId][includedKind];
					if (num8 <= 0)
					{
						continue;
					}
					if (CfgEnableMaxClampSafety.Value)
					{
						int maxForKind = GetMaxForKind(includedKind);
						if (targets[playerUpgradeBuild.SteamId][includedKind] >= maxForKind)
						{
							continue;
						}
					}
					float num9 = 1f + (float)Mathf.Max(0, 3 - targets[playerUpgradeBuild.SteamId][includedKind]) * 0.25f;
					float num10 = 1f + (float)Mathf.Max(0, targets[playerUpgradeBuild2.SteamId][includedKind] - 3) * 0.15f;
					float num11 = num9 + num10;
					if (num11 > num7)
					{
						num7 = num11;
						upgradeKind = includedKind;
					}
				}
				if (!upgradeKind.HasValue)
				{
					break;
				}
				targets[playerUpgradeBuild2.SteamId][upgradeKind.Value]--;
				targets[playerUpgradeBuild.SteamId][upgradeKind.Value]++;
			}
		}

		private List<int> BuildDerangement(int count)
		{
			if (count == 2)
			{
				return new List<int> { 1, 0 };
			}
			for (int i = 0; i < 64; i++)
			{
				List<int> list = Enumerable.Range(0, count).ToList();
				for (int num = list.Count - 1; num > 0; num--)
				{
					int index = _random.Next(num + 1);
					int value = list[num];
					list[num] = list[index];
					list[index] = value;
				}
				bool flag = true;
				for (int j = 0; j < count; j++)
				{
					if (list[j] == j)
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					return list;
				}
			}
			List<int> list2 = new List<int>();
			int num2 = _random.Next(1, count);
			for (int k = 0; k < count; k++)
			{
				list2.Add((k + num2) % count);
			}
			return list2;
		}

		private void MergeExcludedValues(List<PlayerUpgradeBuild> players, Dictionary<string, Dictionary<UpgradeKind, int>> targets, List<UpgradeKind> includedKinds)
		{
			HashSet<UpgradeKind> hashSet = new HashSet<UpgradeKind>(includedKinds);
			foreach (PlayerUpgradeBuild player in players)
			{
				foreach (UpgradeKind value in Enum.GetValues(typeof(UpgradeKind)))
				{
					if (!hashSet.Contains(value))
					{
						targets[player.SteamId][value] = Mathf.Max(0, player.Values[value]);
					}
				}
			}
		}

		private void ApplyClampToTargets(Dictionary<string, Dictionary<UpgradeKind, int>> targets, bool includeExcluded, List<UpgradeKind> includedKinds)
		{
			if (!CfgEnableMaxClampSafety.Value)
			{
				return;
			}
			HashSet<UpgradeKind> hashSet = new HashSet<UpgradeKind>(includedKinds);
			foreach (string item in targets.Keys.ToList())
			{
				Dictionary<UpgradeKind, int> dictionary = targets[item];
				foreach (UpgradeKind item2 in dictionary.Keys.ToList())
				{
					if (includeExcluded || hashSet.Contains(item2))
					{
						dictionary[item2] = Mathf.Clamp(dictionary[item2], 0, GetMaxForKind(item2));
					}
				}
			}
		}

		private bool ApplyTargetsWithBatchedDeltas(List<PlayerUpgradeBuild> players, Dictionary<string, Dictionary<UpgradeKind, int>> targets, List<UpgradeKind> includedKinds)
		{
			if ((Object)(object)PunManager.instance == (Object)null || (Object)(object)StatsManager.instance == (Object)null)
			{
				LogWarn("PunManager or StatsManager is null");
				return false;
			}
			ApplyClampToTargets(targets, includeExcluded: false, includedKinds);
			foreach (PlayerUpgradeBuild player in players)
			{
				Dictionary<UpgradeKind, int> values = player.Values;
				Dictionary<UpgradeKind, int> dictionary = targets[player.SteamId];
				foreach (UpgradeKind includedKind in includedKinds)
				{
					int num = (values.ContainsKey(includedKind) ? Mathf.Max(0, values[includedKind]) : 0);
					int num2 = (dictionary.ContainsKey(includedKind) ? Mathf.Max(0, dictionary[includedKind]) : 0);
					if (CfgEnableMaxClampSafety.Value)
					{
						num2 = Mathf.Clamp(num2, 0, GetMaxForKind(includedKind));
					}
					int num3 = num2 - num;
					if (num3 != 0)
					{
						try
						{
							ApplyDelta(player.SteamId, includedKind, num3);
						}
						catch (Exception ex)
						{
							LogWarn($"ApplyDelta failed. Player={player.DisplayName} Kind={includedKind} Delta={num3} Err={ex.Message}");
							return false;
						}
					}
				}
			}
			if (CfgCallStatSyncAll.Value)
			{
				try
				{
					SemiFunc.StatSyncAll();
				}
				catch (Exception ex2)
				{
					LogWarn("StatSyncAll failed. " + ex2.Message);
				}
			}
			return true;
		}

		private void ApplyDelta(string steamId, UpgradeKind kind, int delta)
		{
			switch (kind)
			{
			case UpgradeKind.Health:
				PunManager.instance.UpgradePlayerHealth(steamId, delta);
				break;
			case UpgradeKind.Stamina:
				PunManager.instance.UpgradePlayerEnergy(steamId, delta);
				break;
			case UpgradeKind.ExtraJump:
				PunManager.instance.UpgradePlayerExtraJump(steamId, delta);
				break;
			case UpgradeKind.TumbleLaunch:
				PunManager.instance.UpgradePlayerTumbleLaunch(steamId, delta);
				break;
			case UpgradeKind.TumbleClimb:
				PunManager.instance.UpgradePlayerTumbleClimb(steamId, delta);
				break;
			case UpgradeKind.MapPlayerCount:
				PunManager.instance.UpgradeMapPlayerCount(steamId, delta);
				break;
			case UpgradeKind.DeathHeadBattery:
				PunManager.instance.UpgradeDeathHeadBattery(steamId, delta);
				break;
			case UpgradeKind.TumbleWings:
				PunManager.instance.UpgradePlayerTumbleWings(steamId, delta);
				break;
			case UpgradeKind.SprintSpeed:
				PunManager.instance.UpgradePlayerSprintSpeed(steamId, delta);
				break;
			case UpgradeKind.CrouchRest:
				PunManager.instance.UpgradePlayerCrouchRest(steamId, delta);
				break;
			case UpgradeKind.GrabStrength:
				PunManager.instance.UpgradePlayerGrabStrength(steamId, delta);
				break;
			case UpgradeKind.Throw:
				PunManager.instance.UpgradePlayerThrowStrength(steamId, delta);
				break;
			case UpgradeKind.GrabRange:
				PunManager.instance.UpgradePlayerGrabRange(steamId, delta);
				break;
			}
		}

		private int GetMaxForKind(UpgradeKind kind)
		{
			return kind switch
			{
				UpgradeKind.Health => Mathf.Max(0, CfgMaxHealth.Value), 
				UpgradeKind.Stamina => Mathf.Max(0, CfgMaxStamina.Value), 
				UpgradeKind.ExtraJump => Mathf.Max(0, CfgMaxExtraJump.Value), 
				UpgradeKind.TumbleLaunch => Mathf.Max(0, CfgMaxTumbleLaunch.Value), 
				UpgradeKind.TumbleClimb => Mathf.Max(0, CfgMaxTumbleClimb.Value), 
				UpgradeKind.MapPlayerCount => Mathf.Max(0, CfgMaxMapPlayerCount.Value), 
				UpgradeKind.DeathHeadBattery => Mathf.Max(0, CfgMaxDeathHeadBattery.Value), 
				UpgradeKind.TumbleWings => Mathf.Max(0, CfgMaxTumbleWings.Value), 
				UpgradeKind.SprintSpeed => Mathf.Max(0, CfgMaxSprintSpeed.Value), 
				UpgradeKind.CrouchRest => Mathf.Max(0, CfgMaxCrouchRest.Value), 
				UpgradeKind.GrabStrength => Mathf.Max(0, CfgMaxGrabStrength.Value), 
				UpgradeKind.Throw => Mathf.Max(0, CfgMaxThrow.Value), 
				UpgradeKind.GrabRange => Mathf.Max(0, CfgMaxGrabRange.Value), 
				_ => 999, 
			};
		}

		private Dictionary<string, Dictionary<UpgradeKind, int>> BuildRemainingCaps(List<PlayerUpgradeBuild> players)
		{
			Dictionary<string, Dictionary<UpgradeKind, int>> dictionary = new Dictionary<string, Dictionary<UpgradeKind, int>>();
			foreach (PlayerUpgradeBuild player in players)
			{
				dictionary[player.SteamId] = new Dictionary<UpgradeKind, int>();
				foreach (UpgradeKind value in Enum.GetValues(typeof(UpgradeKind)))
				{
					if (!CfgEnableMaxClampSafety.Value)
					{
						dictionary[player.SteamId][value] = 536870911;
					}
					else
					{
						dictionary[player.SteamId][value] = Mathf.Max(0, GetMaxForKind(value));
					}
				}
			}
			return dictionary;
		}

		private bool HasCapacity(string steamId, UpgradeKind kind, Dictionary<string, Dictionary<UpgradeKind, int>> caps)
		{
			if (caps == null)
			{
				return true;
			}
			if (!caps.ContainsKey(steamId))
			{
				return true;
			}
			if (!caps[steamId].ContainsKey(kind))
			{
				return true;
			}
			return caps[steamId][kind] > 0;
		}

		private void ConsumeCap(string steamId, UpgradeKind kind, Dictionary<string, Dictionary<UpgradeKind, int>> caps)
		{
			if (caps != null && caps.ContainsKey(steamId) && caps[steamId].ContainsKey(kind) && caps[steamId][kind] > 0)
			{
				caps[steamId][kind]--;
			}
		}

		private string WeightedPickSteamId(Dictionary<string, float> weights, float sum)
		{
			if (weights == null || weights.Count <= 0)
			{
				return "";
			}
			if (sum <= 0f)
			{
				return weights.Keys.ElementAt(_random.Next(weights.Count));
			}
			double num = _random.NextDouble() * (double)sum;
			float num2 = 0f;
			foreach (KeyValuePair<string, float> weight in weights)
			{
				num2 += Mathf.Max(0.0001f, weight.Value);
				if (num <= (double)num2)
				{
					return weight.Key;
				}
			}
			return weights.Keys.Last();
		}

		private UpgradeKind WeightedPickKind(Dictionary<UpgradeKind, float> weights, float sum)
		{
			if (weights == null || weights.Count <= 0)
			{
				return UpgradeKind.Health;
			}
			if (sum <= 0f)
			{
				return weights.Keys.ElementAt(_random.Next(weights.Count));
			}
			double num = _random.NextDouble() * (double)sum;
			float num2 = 0f;
			foreach (KeyValuePair<UpgradeKind, float> weight in weights)
			{
				num2 += Mathf.Max(0.0001f, weight.Value);
				if (num <= (double)num2)
				{
					return weight.Key;
				}
			}
			return weights.Keys.Last();
		}

		private int SumIncludedForPlayer(Dictionary<UpgradeKind, int> map, List<UpgradeKind> includedKinds)
		{
			int num = 0;
			foreach (UpgradeKind includedKind in includedKinds)
			{
				if (map.ContainsKey(includedKind))
				{
					num += Mathf.Max(0, map[includedKind]);
				}
			}
			return num;
		}

		private void EnqueueUndo(ShuffleSnapshot snapshot)
		{
			_undoHistory.Enqueue(snapshot);
			int num = Mathf.Clamp(CfgUndoHistoryKeepCount.Value, 1, 5);
			while (_undoHistory.Count > num)
			{
				_undoHistory.Dequeue();
			}
		}

		private void TryUndo()
		{
			if (!CfgEnableUndoCommand.Value)
			{
				LogInfo("Undo disabled");
				return;
			}
			if (CfgUndoRequireHost.Value && SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient)
			{
				LogInfo("Undo denied: host only");
				return;
			}
			if (_undoHistory.Count <= 0)
			{
				LogInfo("Undo failed: no history");
				return;
			}
			ShuffleSnapshot shuffleSnapshot = _undoHistory.Last();
			List<PlayerUpgradeBuild> list = BuildPlayerList();
			List<string> list2 = list.Select((PlayerUpgradeBuild p) => p.SteamId).OrderBy<string, string>((string x) => x, StringComparer.Ordinal).ToList();
			List<string> list3 = shuffleSnapshot.SteamIds.OrderBy<string, string>((string x) => x, StringComparer.Ordinal).ToList();
			if (list2.Count != list3.Count)
			{
				LogInfo("Undo failed: player count changed");
				return;
			}
			for (int i = 0; i < list2.Count; i++)
			{
				if (!string.Equals(list2[i], list3[i], StringComparison.Ordinal))
				{
					LogInfo("Undo failed: players changed");
					return;
				}
			}
			ReadCurrentUpgrades(list);
			List<UpgradeKind> includedKinds = GetIncludedKinds();
			Dictionary<string, Dictionary<UpgradeKind, int>> dictionary = new Dictionary<string, Dictionary<UpgradeKind, int>>();
			foreach (PlayerUpgradeBuild item in list)
			{
				dictionary[item.SteamId] = CloneValues(shuffleSnapshot.Before[item.SteamId]);
			}
			ApplyClampToTargets(dictionary, includeExcluded: false, includedKinds);
			if (!ApplyTargetsWithBatchedDeltas(list, dictionary, includedKinds))
			{
				LogInfo("Undo failed: apply error");
				return;
			}
			_undoHistory.Clear();
			LogInfo($"Undo success. Restored last shuffle. Mode={shuffleSnapshot.ModeName} ShopCount={shuffleSnapshot.ShopVisitCount}");
		}

		private Dictionary<UpgradeKind, int> CloneValues(Dictionary<UpgradeKind, int> src)
		{
			Dictionary<UpgradeKind, int> dictionary = new Dictionary<UpgradeKind, int>();
			foreach (KeyValuePair<UpgradeKind, int> item in src)
			{
				dictionary[item.Key] = item.Value;
			}
			return dictionary;
		}

		private void LogPlayerValues(string prefix, List<PlayerUpgradeBuild> players)
		{
			foreach (PlayerUpgradeBuild player in players)
			{
				LogInfo(prefix + " " + player.DisplayName + "(" + player.SteamId + ") " + FormatValues(player.Values));
			}
		}

		private void LogTargets(string prefix, List<PlayerUpgradeBuild> players, Dictionary<string, Dictionary<UpgradeKind, int>> targets)
		{
			foreach (PlayerUpgradeBuild player in players)
			{
				if (targets.ContainsKey(player.SteamId))
				{
					LogInfo(prefix + " " + player.DisplayName + "(" + player.SteamId + ") " + FormatValues(targets[player.SteamId]));
				}
			}
		}

		private string FormatValues(Dictionary<UpgradeKind, int> values)
		{
			return string.Join(", ", (from x in values.OrderBy<KeyValuePair<UpgradeKind, int>, string>((KeyValuePair<UpgradeKind, int> x) => x.Key.ToString(), StringComparer.Ordinal)
				select $"{x.Key}={x.Value}").ToArray());
		}

		private void LogInfo(string message)
		{
			ConfigEntry<bool> cfgLogSummary = CfgLogSummary;
			if (cfgLogSummary == null || cfgLogSummary.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[ShuffleUpgrade] " + message));
			}
		}

		private void LogWarn(string message)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[ShuffleUpgrade] " + message));
		}
	}
}