Decompiled source of ArenaRaceMultiplayerSpawnFix v4.0.2

ArenaRaceMultiplayerSpawnFix.dll

Decompiled 2 weeks ago
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 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("REPOJP")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOJP.ArenaRaceMultiplayerSpawnFix
{
	[BepInPlugin("REPOJP.ArenaRaceMultiplayerSpawnFix", "ArenaRaceMultiplayerSpawnFix", "4.0.2")]
	public class ArenaRaceMultiplayerSpawnFixPlugin : BaseUnityPlugin
	{
		private sealed class LayoutPlan
		{
			public readonly List<Vector3> Positions = new List<Vector3>();
		}

		[HarmonyPatch(typeof(LevelGenerator), "PlayerSpawn")]
		private static class LevelGeneratorPlayerSpawnPatch
		{
			private static void Postfix()
			{
				try
				{
					ScheduleLayoutApplyFromPlayerSpawn();
				}
				catch (Exception ex)
				{
					LogError("Failure: PlayerSpawn Postfix\n" + ex);
				}
			}
		}

		[HarmonyPatch(typeof(ArenaRace), "StateSetRPC")]
		private static class ArenaRaceStateSetRPCPatch
		{
			private static void Postfix(ArenaRace __instance, States _state)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0004: Invalid comparison between Unknown and I4
				try
				{
					if ((int)_state == 2)
					{
						ApplyStartBoostOnce(__instance);
					}
				}
				catch (Exception ex)
				{
					LogError("Failure: ArenaRace.StateSetRPC Postfix\n" + ex);
				}
			}
		}

		[CompilerGenerated]
		private sealed class <DelayedApplyLayoutCoroutine>d__31 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public int scheduleId;

			private int <attempt>5__1;

			private string <waitReason>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedApplyLayoutCoroutine>d__31(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<waitReason>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<attempt>5__1 = 1;
					break;
				case 1:
					<>1__state = -1;
					if (scheduleId != layoutScheduleId)
					{
						return false;
					}
					if (!CanApplyLayoutNow(out <waitReason>5__2))
					{
						if (<attempt>5__1 == 45)
						{
							LogWarning("Skipped layout apply after retry: " + <waitReason>5__2 + " | Attempts=" + <attempt>5__1 + " | " + BuildContextSummary());
						}
						<attempt>5__1++;
						break;
					}
					TryApplyLayout(scheduleId, <attempt>5__1);
					return false;
				}
				if (<attempt>5__1 <= 45)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "REPOJP.ArenaRaceMultiplayerSpawnFix";

		public const string PluginName = "ArenaRaceMultiplayerSpawnFix";

		public const string PluginVersion = "4.0.2";

		private const float FixedHorizontalSpacing = 0.8f;

		private const float FixedVerticalSpacing = 3f;

		private const float FixedHeightOffset = 5f;

		private const float FixedBackwardOffset = 10f;

		private static ManualLogSource logSource;

		private static Harmony harmony;

		private static ArenaRaceMultiplayerSpawnFixPlugin pluginInstance;

		private static ConfigEntry<bool> enabledConfig;

		private static ConfigEntry<int> horizontalPlayersConfig;

		private static ConfigEntry<int> verticalPlayersConfig;

		private static ConfigEntry<bool> startBoostEnabledConfig;

		private static ConfigEntry<float> startBoostMultiplierConfig;

		private static FieldInfo arenaRacePlayerVehicleMapField;

		private static FieldInfo arenaRaceVehiclesField;

		private static MethodInfo itemVehicleOverrideYawMethod;

		private static MethodInfo itemVehicleOverridePitchMethod;

		private static MethodInfo playerAvatarSpawnRPCMethod;

		private static int lastStartBoostArenaRaceInstanceId;

		private static int layoutScheduleId;

		private static bool layoutApplyInProgress;

		private const int DelayedLayoutMaxAttempts = 45;

		private void Awake()
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			try
			{
				((Component)this).transform.parent = null;
				((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				pluginInstance = this;
				logSource = ((BaseUnityPlugin)this).Logger;
				BindConfig();
				arenaRacePlayerVehicleMapField = AccessTools.Field(typeof(ArenaRace), "playerVehicleMap");
				arenaRaceVehiclesField = AccessTools.Field(typeof(ArenaRace), "vehicles");
				itemVehicleOverrideYawMethod = AccessTools.Method(typeof(ItemVehicle), "OverrideYaw", new Type[3]
				{
					typeof(Vector3),
					typeof(float),
					typeof(int)
				}, (Type[])null);
				itemVehicleOverridePitchMethod = AccessTools.Method(typeof(ItemVehicle), "OverridePitch", new Type[2]
				{
					typeof(float),
					typeof(float)
				}, (Type[])null);
				playerAvatarSpawnRPCMethod = AccessTools.Method(typeof(PlayerAvatar), "SpawnRPC", new Type[3]
				{
					typeof(Vector3),
					typeof(Quaternion),
					typeof(PhotonMessageInfo)
				}, (Type[])null);
				harmony = new Harmony("REPOJP.ArenaRaceMultiplayerSpawnFix");
				harmony.PatchAll();
				LogInfo("Loaded ArenaRaceMultiplayerSpawnFix v4.0.2");
				LogInfo("Config: Enabled=" + GetConfigBool(enabledConfig, defaultValue: false) + ", HorizontalPlayers=" + GetConfigInt(horizontalPlayersConfig, 10) + ", VerticalPlayers=" + GetConfigInt(verticalPlayersConfig, 2) + ", StartBoostEnabled=" + GetConfigBool(startBoostEnabledConfig, defaultValue: false) + ", StartBoostMultiplier=" + GetConfigFloat(startBoostMultiplierConfig, 10f));
				if (arenaRacePlayerVehicleMapField == null)
				{
					LogWarning("Warning: ArenaRace.playerVehicleMap field was not found. Start boost will use fallback vehicle list if available.");
				}
				if (arenaRaceVehiclesField == null)
				{
					LogWarning("Warning: ArenaRace.vehicles field was not found. Start boost fallback vehicle list is unavailable.");
				}
				if (itemVehicleOverrideYawMethod == null)
				{
					LogWarning("Warning: ItemVehicle.OverrideYaw method was not found. Start boost cannot be applied.");
				}
				if (playerAvatarSpawnRPCMethod == null)
				{
					LogWarning("Warning: PlayerAvatar.SpawnRPC method was not found. Singleplayer compatibility fallback is unavailable.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Awake\n" + ex));
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				LogError("Failure: OnDestroy\n" + ex);
			}
		}

		private void BindConfig()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			enabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod.このMODを有効にします");
			horizontalPlayersConfig = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn Layout", "HorizontalPlayers", 10, new ConfigDescription("Number of players per horizontal row.横1行に並べる人数", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			verticalPlayersConfig = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn Layout", "VerticalPlayers", 2, new ConfigDescription("Number of vertical rows.縦方向の行数", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			startBoostEnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Start Boost", "StartBoostEnabled", true, "Apply a temporary level 3 boost after the countdown.321後に一時的なレベル3ブーストを付与します");
			startBoostMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Start Boost", "StartBoostMultiplier", 10f, new ConfigDescription("Level 3 boost power multiplier.レベル3ブーストの強さ倍率", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		}

		private static void ScheduleLayoutApplyFromPlayerSpawn()
		{
			if (!CanScheduleLayoutApply(out var reason))
			{
				LogWarning("Skipped layout schedule: " + reason + " | " + BuildContextSummary());
				return;
			}
			if ((Object)(object)pluginInstance == (Object)null)
			{
				LogWarning("Skipped layout schedule: plugin instance is null | " + BuildContextSummary());
				return;
			}
			lastStartBoostArenaRaceInstanceId = 0;
			layoutScheduleId++;
			int scheduleId = layoutScheduleId;
			LogInfo("PlayerSpawn detected. Scheduling Arena Race spawn layout. ScheduleId=" + scheduleId + " | " + BuildContextSummary());
			((MonoBehaviour)pluginInstance).StartCoroutine(DelayedApplyLayoutCoroutine(scheduleId));
		}

		[IteratorStateMachine(typeof(<DelayedApplyLayoutCoroutine>d__31))]
		private static IEnumerator DelayedApplyLayoutCoroutine(int scheduleId)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedApplyLayoutCoroutine>d__31(0)
			{
				scheduleId = scheduleId
			};
		}

		private static void TryApplyLayout(int scheduleId, int attempt)
		{
			if (layoutApplyInProgress)
			{
				LogWarning("Skipped layout apply: another layout apply is already running. ScheduleId=" + scheduleId);
				return;
			}
			layoutApplyInProgress = true;
			try
			{
				List<PlayerAvatar> randomizedPlayers = GetRandomizedPlayers();
				if (randomizedPlayers.Count == 0)
				{
					LogWarning("Skipped layout apply: no valid players found | ScheduleId=" + scheduleId + " | " + BuildContextSummary());
					return;
				}
				LayoutPlan layoutPlan = BuildLayoutPlan(randomizedPlayers);
				if (layoutPlan == null || layoutPlan.Positions.Count == 0)
				{
					LogWarning("Skipped layout apply: layout plan is empty | ScheduleId=" + scheduleId + " | Players=" + randomizedPlayers.Count);
					return;
				}
				int num = ApplyLayout(randomizedPlayers, layoutPlan);
				LogInfo("Applied Arena Race spawn layout by SpawnRPC. ScheduleId=" + scheduleId + ", Attempt=" + attempt + ", Players=" + randomizedPlayers.Count + ", Applied=" + num + ", HorizontalPlayers=" + GetConfigInt(horizontalPlayersConfig, 10) + ", VerticalPlayers=" + GetConfigInt(verticalPlayersConfig, 2) + ", Slots=" + layoutPlan.Positions.Count + " | " + BuildContextSummary());
			}
			catch (Exception ex)
			{
				LogError("Failure: TryApplyLayout | ScheduleId=" + scheduleId + " | " + BuildContextSummary() + "\n" + ex);
			}
			finally
			{
				layoutApplyInProgress = false;
			}
		}

		private static bool CanScheduleLayoutApply(out string reason)
		{
			if (enabledConfig == null || !enabledConfig.Value)
			{
				reason = "mod is disabled";
				return false;
			}
			if (!SafeIsMasterClientOrSingleplayer())
			{
				reason = "not host or singleplayer";
				return false;
			}
			if ((Object)(object)LevelGenerator.Instance == (Object)null)
			{
				reason = "LevelGenerator.Instance is null";
				return false;
			}
			if (!SafeCurrentLevelLooksArenaRace() && !SafeArenaRaceInstanceExists())
			{
				reason = "current level is not Arena Race";
				return false;
			}
			if (SafeLevelGenerated())
			{
				reason = "level is already generated";
				return false;
			}
			reason = "ready";
			return true;
		}

		private static bool CanApplyLayoutNow(out string reason)
		{
			if (enabledConfig == null || !enabledConfig.Value)
			{
				reason = "mod is disabled";
				return false;
			}
			if (!SafeIsMasterClientOrSingleplayer())
			{
				reason = "not host or singleplayer";
				return false;
			}
			if (!SafeCurrentLevelLooksArenaRace() && !SafeArenaRaceInstanceExists())
			{
				reason = "current level is not Arena Race";
				return false;
			}
			if (!SafeArenaRaceInstanceExists())
			{
				reason = "ArenaRace.instance is null. This is not Arena Race, or Arena Race is not ready yet";
				return false;
			}
			if (!SafeArenaRaceTrackSpawnOriginExists())
			{
				reason = "ArenaRace.trackSpawnOrigin is null. Arena Race is not ready yet";
				return false;
			}
			int playerCountSafe = GetPlayerCountSafe();
			if (playerCountSafe <= 0)
			{
				reason = "no players in GameDirector.PlayerList";
				return false;
			}
			reason = "ready";
			return true;
		}

		private static List<PlayerAvatar> GetRandomizedPlayers()
		{
			List<PlayerAvatar> list = new List<PlayerAvatar>();
			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 && (Object)(object)((Component)player).gameObject != (Object)null)
				{
					list.Add(player);
				}
			}
			return ShufflePlayers(list);
		}

		private static LayoutPlan BuildLayoutPlan(List<PlayerAvatar> players)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			LayoutPlan layoutPlan = new LayoutPlan();
			if (players == null || players.Count == 0)
			{
				return layoutPlan;
			}
			Vector3 val = GetVanillaCenter(players) + Vector3.up * 5f;
			Vector3 courseForward = GetCourseForward();
			Vector3 val2 = Vector3.Cross(Vector3.up, courseForward);
			Vector3 val3 = ((Vector3)(ref val2)).normalized;
			if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
			{
				val3 = Vector3.right;
			}
			int num = Mathf.Clamp((horizontalPlayersConfig != null) ? horizontalPlayersConfig.Value : 10, 1, 20);
			int num2 = Mathf.Clamp((verticalPlayersConfig != null) ? verticalPlayersConfig.Value : 2, 1, 20);
			int num3 = Mathf.CeilToInt((float)players.Count / (float)Mathf.Max(1, num));
			num2 = Mathf.Max(num2, num3);
			List<Vector3> list = new List<Vector3>();
			for (int i = 0; i < num2; i++)
			{
				for (int j = 0; j < num; j++)
				{
					float num4 = ((float)j - ((float)num - 1f) * 0.5f) * 0.8f;
					float num5 = 0f - ((float)i * 3f + 10f);
					Vector3 item = val + val3 * num4 + courseForward * num5;
					list.Add(item);
				}
			}
			list = ShufflePositions(list);
			for (int k = 0; k < players.Count && k < list.Count; k++)
			{
				layoutPlan.Positions.Add(list[k]);
			}
			return layoutPlan;
		}

		private static List<Vector3> ShufflePositions(List<Vector3> positions)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>(positions);
			Random random = new Random(Guid.NewGuid().GetHashCode() ^ Environment.TickCount ^ list.Count);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = random.Next(num + 1);
				Vector3 value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			return list;
		}

		private static int ApplyLayout(List<PlayerAvatar> players, LayoutPlan plan)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			int num2 = Mathf.Min(players.Count, plan.Positions.Count);
			for (int i = 0; i < num2; i++)
			{
				PlayerAvatar val = players[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					Vector3 position = plan.Positions[i];
					Quaternion rotation = ((Component)val).transform.rotation;
					if (TryApplySpawnPositionByRpc(val, position, rotation, i))
					{
						num++;
					}
				}
				catch (Exception ex)
				{
					LogError("Failure: ApplyLayout player index " + i + "\n" + ex);
				}
			}
			return num;
		}

		private static bool TryApplySpawnPositionByRpc(PlayerAvatar player, Vector3 position, Quaternion rotation, int index)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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)
			if ((Object)(object)player == (Object)null)
			{
				LogWarning("Skipped SpawnRPC apply: player is null. Index=" + index);
				return false;
			}
			try
			{
				if ((Object)(object)GameManager.instance != (Object)null && GameManager.instance.gameMode == 0)
				{
					if (playerAvatarSpawnRPCMethod == null)
					{
						LogWarning("Skipped SpawnRPC apply: SpawnRPC method was not found. Index=" + index + ", Player=" + GetPlayerDebugName(player));
						return false;
					}
					playerAvatarSpawnRPCMethod.Invoke(player, new object[3]
					{
						position,
						rotation,
						(object)default(PhotonMessageInfo)
					});
					return true;
				}
				if ((Object)(object)player.photonView == (Object)null)
				{
					player.photonView = ((Component)player).GetComponent<PhotonView>();
				}
				if ((Object)(object)player.photonView == (Object)null)
				{
					LogWarning("Skipped SpawnRPC apply: PhotonView is null. Index=" + index + ", Player=" + GetPlayerDebugName(player));
					return false;
				}
				player.photonView.RPC("SpawnRPC", (RpcTarget)0, new object[2] { position, rotation });
				return true;
			}
			catch (Exception ex)
			{
				LogError("Failure: TryApplySpawnPositionByRpc | Index=" + index + ", Player=" + GetPlayerDebugName(player) + "\n" + ex);
				return false;
			}
		}

		private static string GetPlayerDebugName(PlayerAvatar player)
		{
			try
			{
				if ((Object)(object)player == (Object)null)
				{
					return "null";
				}
				if (!string.IsNullOrEmpty(((Object)player).name))
				{
					return ((Object)player).name;
				}
				return "Unknown";
			}
			catch
			{
				return "Unknown";
			}
		}

		private static Vector3 GetVanillaCenter(List<PlayerAvatar> players)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			int num = 0;
			foreach (PlayerAvatar player in players)
			{
				if (!((Object)(object)player == (Object)null))
				{
					val += ((Component)player).transform.position;
					num++;
				}
			}
			if (num == 0)
			{
				return Vector3.zero;
			}
			return val / (float)num;
		}

		private static Vector3 GetCourseForward()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 forward = Vector3.forward;
			try
			{
				if ((Object)(object)ArenaRace.instance != (Object)null && (Object)(object)ArenaRace.instance.trackSpawnOrigin != (Object)null)
				{
					forward = ArenaRace.instance.trackSpawnOrigin.forward;
				}
			}
			catch
			{
			}
			forward.y = 0f;
			if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
			{
				forward = Vector3.forward;
			}
			return ((Vector3)(ref forward)).normalized;
		}

		private static List<PlayerAvatar> ShufflePlayers(List<PlayerAvatar> players)
		{
			List<PlayerAvatar> list = new List<PlayerAvatar>(players);
			Random random = new Random(Guid.NewGuid().GetHashCode() ^ Environment.TickCount);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = random.Next(num + 1);
				PlayerAvatar value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			return list;
		}

		private static void ApplyStartBoostOnce(ArenaRace arenaRace)
		{
			if ((Object)(object)arenaRace == (Object)null || enabledConfig == null || !enabledConfig.Value || startBoostEnabledConfig == null || !startBoostEnabledConfig.Value || !SafeIsMasterClientOrSingleplayer())
			{
				return;
			}
			if ((Object)(object)arenaRace == (Object)null && !SafeRunIsArena())
			{
				LogWarning("Skipped start boost: Arena Race was not detected | " + BuildContextSummary());
				return;
			}
			int instanceID = ((Object)arenaRace).GetInstanceID();
			if (lastStartBoostArenaRaceInstanceId == instanceID)
			{
				return;
			}
			lastStartBoostArenaRaceInstanceId = instanceID;
			List<ItemVehicle> arenaRaceVehicles = GetArenaRaceVehicles(arenaRace);
			if (arenaRaceVehicles.Count == 0)
			{
				LogWarning("Skipped start boost: no Arena Race vehicles found | " + BuildContextSummary());
				return;
			}
			int num = 0;
			foreach (ItemVehicle item in arenaRaceVehicles)
			{
				if (ApplyStartBoostToVehicle(arenaRace, item))
				{
					num++;
				}
			}
			LogInfo("Applied start boost. Vehicles=" + arenaRaceVehicles.Count + ", Applied=" + num + ", Multiplier=" + GetConfigFloat(startBoostMultiplierConfig, 10f));
		}

		private static List<ItemVehicle> GetArenaRaceVehicles(ArenaRace arenaRace)
		{
			List<ItemVehicle> list = new List<ItemVehicle>();
			if ((Object)(object)arenaRace == (Object)null)
			{
				return list;
			}
			try
			{
				if (arenaRacePlayerVehicleMapField != null)
				{
					object value = arenaRacePlayerVehicleMapField.GetValue(arenaRace);
					if (value is Dictionary<PlayerAvatar, ItemVehicle> dictionary)
					{
						foreach (KeyValuePair<PlayerAvatar, ItemVehicle> item in dictionary)
						{
							if ((Object)(object)item.Value != (Object)null && !list.Contains(item.Value))
							{
								list.Add(item.Value);
							}
						}
					}
				}
			}
			catch
			{
			}
			try
			{
				if (list.Count == 0 && arenaRaceVehiclesField != null)
				{
					object value2 = arenaRaceVehiclesField.GetValue(arenaRace);
					if (value2 is List<ItemVehicle> list2)
					{
						foreach (ItemVehicle item2 in list2)
						{
							if ((Object)(object)item2 != (Object)null && !list.Contains(item2))
							{
								list.Add(item2);
							}
						}
					}
				}
			}
			catch
			{
			}
			return list;
		}

		private static bool ApplyStartBoostToVehicle(ArenaRace arenaRace, ItemVehicle vehicle)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)arenaRace == (Object)null || (Object)(object)vehicle == (Object)null)
			{
				return false;
			}
			if (itemVehicleOverrideYawMethod == null)
			{
				return false;
			}
			float driftBoostLevel3ForwardBoost = vehicle.driftBoostLevel3ForwardBoost;
			float driftBoostLevel3SpeedBoostMultiplier = vehicle.driftBoostLevel3SpeedBoostMultiplier;
			try
			{
				float num = ((startBoostMultiplierConfig != null) ? startBoostMultiplierConfig.Value : 10f);
				float num2 = Mathf.Clamp(num, 0f, 100f);
				vehicle.driftBoostLevel3ForwardBoost = driftBoostLevel3ForwardBoost * num2;
				vehicle.driftBoostLevel3SpeedBoostMultiplier = driftBoostLevel3SpeedBoostMultiplier * num2;
				Vector3 startBoostForward = GetStartBoostForward(arenaRace, vehicle);
				float num3 = Mathf.Asin(Mathf.Clamp(startBoostForward.y, -1f, 1f)) * 57.29578f;
				Vector3 val = startBoostForward;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					val = ((Component)vehicle).transform.forward;
					val.y = 0f;
				}
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					val = Vector3.forward;
				}
				((Vector3)(ref val)).Normalize();
				itemVehicleOverrideYawMethod.Invoke(vehicle, new object[3] { val, 0.25f, 3 });
				if (itemVehicleOverridePitchMethod != null)
				{
					itemVehicleOverridePitchMethod.Invoke(vehicle, new object[2] { num3, 1f });
				}
				return true;
			}
			catch (Exception ex)
			{
				LogError("Failure: ApplyStartBoostToVehicle\n" + ex);
				return false;
			}
			finally
			{
				vehicle.driftBoostLevel3ForwardBoost = driftBoostLevel3ForwardBoost;
				vehicle.driftBoostLevel3SpeedBoostMultiplier = driftBoostLevel3SpeedBoostMultiplier;
			}
		}

		private static Vector3 GetStartBoostForward(ArenaRace arenaRace, ItemVehicle vehicle)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)arenaRace != (Object)null && (Object)(object)arenaRace.trackSpawnOrigin != (Object)null)
				{
					return arenaRace.trackSpawnOrigin.forward;
				}
				if ((Object)(object)vehicle != (Object)null)
				{
					return ((Component)vehicle).transform.forward;
				}
			}
			catch
			{
			}
			return Vector3.forward;
		}

		private static bool SafeIsMasterClientOrSingleplayer()
		{
			try
			{
				return SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
				return false;
			}
		}

		private static bool SafeCurrentLevelLooksArenaRace()
		{
			try
			{
				if ((Object)(object)RunManager.instance == (Object)null || (Object)(object)RunManager.instance.levelCurrent == (Object)null)
				{
					return false;
				}
				string name = ((Object)RunManager.instance.levelCurrent).name;
				if (string.IsNullOrEmpty(name))
				{
					return false;
				}
				return name.IndexOf("Arena Race", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			catch
			{
				return false;
			}
		}

		private static string SafeCurrentLevelName()
		{
			try
			{
				if ((Object)(object)RunManager.instance == (Object)null || (Object)(object)RunManager.instance.levelCurrent == (Object)null)
				{
					return "null";
				}
				return ((Object)RunManager.instance.levelCurrent).name ?? "null";
			}
			catch
			{
				return "Unknown";
			}
		}

		private static bool SafeArenaRaceInstanceExists()
		{
			try
			{
				return (Object)(object)ArenaRace.instance != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static bool SafeArenaRaceTrackSpawnOriginExists()
		{
			try
			{
				return (Object)(object)ArenaRace.instance != (Object)null && (Object)(object)ArenaRace.instance.trackSpawnOrigin != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static bool SafeRunIsArena()
		{
			try
			{
				return SemiFunc.RunIsArena();
			}
			catch
			{
				return false;
			}
		}

		private static bool SafeLevelGenerated()
		{
			try
			{
				return (Object)(object)LevelGenerator.Instance != (Object)null && LevelGenerator.Instance.Generated;
			}
			catch
			{
				return false;
			}
		}

		private static string BuildContextSummary()
		{
			bool configBool = GetConfigBool(enabledConfig, defaultValue: false);
			bool flag = SafeIsMasterClientOrSingleplayer();
			bool flag2 = (Object)(object)LevelGenerator.Instance != (Object)null;
			bool flag3 = SafeLevelGenerated();
			string text = SafeCurrentLevelName();
			bool flag4 = SafeCurrentLevelLooksArenaRace();
			bool flag5 = SafeArenaRaceInstanceExists();
			bool flag6 = SafeArenaRaceTrackSpawnOriginExists();
			bool flag7 = SafeRunIsArena();
			int playerCountSafe = GetPlayerCountSafe();
			int spawnPointCountSafe = GetSpawnPointCountSafe();
			bool flag8 = SafeTruckSafetySpawnPointExists();
			return "Enabled=" + configBool + ", HostOrSingleplayer=" + flag + ", LevelGenerator=" + flag2 + ", LevelGenerated=" + flag3 + ", CurrentLevel=" + text + ", CurrentLevelIsArenaRace=" + flag4 + ", ArenaRaceInstance=" + flag5 + ", ArenaRaceTrackSpawnOrigin=" + flag6 + ", RunIsArena=" + flag7 + ", PlayerCount=" + playerCountSafe + ", SpawnPointCount=" + spawnPointCountSafe + ", TruckSafetySpawnPoint=" + flag8;
		}

		private static int GetPlayerCountSafe()
		{
			try
			{
				if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
				{
					return 0;
				}
				return GameDirector.instance.PlayerList.Count;
			}
			catch
			{
				return -1;
			}
		}

		private static int GetSpawnPointCountSafe()
		{
			try
			{
				SpawnPoint[] array = Object.FindObjectsOfType<SpawnPoint>();
				return (array != null) ? array.Length : 0;
			}
			catch
			{
				return -1;
			}
		}

		private static bool SafeTruckSafetySpawnPointExists()
		{
			try
			{
				return (Object)(object)TruckSafetySpawnPoint.instance != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static bool GetConfigBool(ConfigEntry<bool> config, bool defaultValue)
		{
			try
			{
				return config?.Value ?? defaultValue;
			}
			catch
			{
				return defaultValue;
			}
		}

		private static int GetConfigInt(ConfigEntry<int> config, int defaultValue)
		{
			try
			{
				return config?.Value ?? defaultValue;
			}
			catch
			{
				return defaultValue;
			}
		}

		private static float GetConfigFloat(ConfigEntry<float> config, float defaultValue)
		{
			try
			{
				return config?.Value ?? defaultValue;
			}
			catch
			{
				return defaultValue;
			}
		}

		private static void LogInfo(string message)
		{
			if (logSource != null)
			{
				logSource.LogInfo((object)message);
			}
		}

		private static void LogWarning(string message)
		{
			if (logSource != null)
			{
				logSource.LogWarning((object)message);
			}
		}

		private static void LogError(string message)
		{
			if (logSource != null)
			{
				logSource.LogError((object)message);
			}
		}
	}
}