Decompiled source of Beetleball Match Rules v0.1.0

Mods/BeetleballMatchRules.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using BeetleballMatchRules;
using BeetleballMatchRules.Core;
using BeetleballMatchRules.Rules;
using BeetleballMatchRules.UI;
using HarmonyLib;
using Il2Cpp;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Reflection;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "Beetleball Match Rules", "0.1.0", "bbmr", null)]
[assembly: MelonGame("Bugfight Studio", "Beetleball")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BeetleballMatchRules")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("BeetleballMatchRules")]
[assembly: AssemblyTitle("BeetleballMatchRules")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BeetleballMatchRules
{
	public class Mod : MelonMod
	{
		internal static Instance Log;

		internal static RuleSet Local;

		internal static string CurrentScene = "";

		private RuleSet _toastedFor;

		public override void OnInitializeMelon()
		{
			Log = ((MelonBase)this).LoggerInstance;
			PresetStore.EnsureFolder();
			PresetStore.DeleteLegacyCurrent();
			Local = new RuleSet();
			Patcher patcher = new Patcher(((MelonBase)this).HarmonyInstance);
			DungPatches.Register(patcher);
			MatchPatches.Register(patcher);
			KickoffFreeze.Register(patcher);
			Log.Msg($"Loaded. {patcher.Ok} patches ok, {patcher.Failed} failed. Set rules in the custom lobby: Lobby Config > match rules.");
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			CurrentScene = sceneName;
			KickoffFreeze.Clear();
			Session.ForceReapply();
		}

		public override void OnUpdate()
		{
			DungPatches.ResetFlags();
			Session.Tick(Local);
			LobbyRulesPanel.Tick();
			KickoffFreeze.Tick();
			ArenaWalls.Tick();
			if (Session.Role == Role.Client && Session.Received != null && _toastedFor != Session.Received)
			{
				_toastedFor = Session.Received;
				if (Session.Received.ToJson(indented: false) != "{}")
				{
					RulesMenu.Toast("The host is using custom match rules (Lobby Config > match rules).");
				}
			}
		}

		public override void OnGUI()
		{
			RulesMenu.Draw();
		}

		public override void OnDeinitializeMelon()
		{
			AssetOverrides.RestoreAll();
		}
	}
	public sealed class Patcher
	{
		private readonly Harmony _harmony;

		public int Ok { get; private set; }

		public int Failed { get; private set; }

		public Patcher(Harmony harmony)
		{
			_harmony = harmony;
		}

		public void Prefix(Type target, string method, string hook, Type hooks)
		{
			Patch(target, method, hook, hooks, prefix: true);
		}

		public void Postfix(Type target, string method, string hook, Type hooks)
		{
			Patch(target, method, hook, hooks, prefix: false);
		}

		private void Patch(Type target, string method, string hook, Type hooks, bool prefix)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(target, method, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					throw new MissingMethodException(target.Name, method);
				}
				HarmonyMethod val = new HarmonyMethod(hooks, hook, (Type[])null);
				_harmony.Patch((MethodBase)methodInfo, prefix ? val : null, prefix ? null : val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Ok++;
			}
			catch (Exception ex)
			{
				Failed++;
				Mod.Log.Error($"[patch] {target.Name}.{method} -> {hook} failed: {ex.Message}");
			}
		}
	}
}
namespace BeetleballMatchRules.UI
{
	public static class LobbyRulesPanel
	{
		private sealed class Row
		{
			public RuleField Field;

			public Slider Slider;

			public Toggle Toggle;

			public TMP_Text Value;

			public int Steps;
		}

		private const string ContainerName = "BBMR_MatchRules";

		private const float Spacing = 14f;

		private const string ScreenName = "BBMR_MatchRulesScreen";

		private const string ButtonName = "Button_MatchRules";

		private static GameObject _container;

		private static GameObject _screen;

		private static GameObject _button;

		private static MenuScreen _menu;

		private static readonly List<Row> Rows = new List<Row>();

		private static readonly List<Selectable> Controls = new List<Selectable>();

		private static TMP_Text _presetLabel;

		private static TMP_Text _statusLabel;

		private static float _nextTick;

		private const float RowWidth = 900f;

		private static bool _refreshing;

		private static bool Editable => Session.Role != Role.Client;

		private static RuleSet Shown
		{
			get
			{
				if (Session.Role != Role.Client)
				{
					return Mod.Local;
				}
				return Session.Received ?? new RuleSet();
			}
		}

		private static bool Alive(GameObject go)
		{
			if ((Object)(object)go != (Object)null)
			{
				return !((Il2CppObjectBase)go).WasCollected;
			}
			return false;
		}

		public static void Tick()
		{
			if (Time.unscaledTime < _nextTick)
			{
				return;
			}
			_nextTick = Time.unscaledTime + 0.25f;
			try
			{
				if (!Alive(_container) || !Alive(_screen) || !Alive(_button))
				{
					TryInject();
				}
				if (Alive(_screen) && _screen.activeInHierarchy)
				{
					Refresh();
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[lobby-ui] " + ex.Message);
				_nextTick = Time.unscaledTime + 5f;
			}
		}

		private static void TryInject()
		{
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			CustomLobbyBotsUI val = FindInScene<CustomLobbyBotsUI>();
			CustomLobbyHostOptionsUI val2 = FindInScene<CustomLobbyHostOptionsUI>();
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return;
			}
			GameObject val3 = (((Object)(object)((Component)val).transform.parent != (Object)null) ? ((Component)((Component)val).transform.parent).gameObject : null);
			ScrollRect componentInChildren = ((Component)val).GetComponentInChildren<ScrollRect>(true);
			RectTransform val4 = ((componentInChildren != null) ? componentInChildren.content : null);
			Transform transform = ((Component)val2).transform;
			Transform obj = transform.Find("Toggle_IsPrivate");
			GameObject val5 = ((obj != null) ? ((Component)obj).gameObject : null);
			Transform obj2 = transform.Find("Slider_MaxPlayers");
			GameObject val6 = ((obj2 != null) ? ((Component)obj2).gameObject : null);
			Transform obj3 = transform.Find("Button_Advanced");
			GameObject val7 = ((obj3 != null) ? ((Component)obj3).gameObject : null);
			object obj4;
			if (val4 == null)
			{
				obj4 = null;
			}
			else
			{
				Transform obj5 = ((Transform)val4).Find("AddBots/Text (TMP)");
				obj4 = ((obj5 != null) ? ((Component)obj5).gameObject : null);
			}
			if (obj4 == null)
			{
				if (val4 == null)
				{
					obj4 = null;
				}
				else
				{
					Transform obj6 = ((Transform)val4).Find("RemoveBots/Text (TMP)");
					obj4 = ((obj6 != null) ? ((Component)obj6).gameObject : null);
				}
			}
			GameObject val8 = (GameObject)obj4;
			if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponent<MenuScreen>() == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null || (Object)(object)val8 == (Object)null)
			{
				Mod.Log.Warning("[lobby-ui] UI templates not found; the in-lobby rules screen is disabled.");
				_nextTick = Time.unscaledTime + 10f;
				return;
			}
			DestroyChildNamed(val3.transform.parent, "BBMR_MatchRulesScreen");
			DestroyChildNamed(transform, "Button_MatchRules");
			Rows.Clear();
			Controls.Clear();
			_screen = BuildScreen(val3, out var content);
			_container = BuildContainer(content);
			Transform transform2 = _container.transform;
			_statusLabel = AddHeader(val8, transform2, "");
			TMP_Text statusLabel = _statusLabel;
			statusLabel.fontSize *= 0.7f;
			((Graphic)_statusLabel).color = new Color(0.85f, 0.85f, 0.85f);
			Transform root = HorizontalRow(transform2, 95f);
			_presetLabel = AddButton(val7, root, "Preset: -", CyclePreset);
			AddButton(val7, root, "save as preset", SavePreset);
			AddButton(val7, root, "reset all", ResetAll);
			foreach (Tab tab in RuleField.VisibleTabs)
			{
				AddHeader(val8, transform2, TabInfo.Title(tab));
				foreach (RuleField item in RuleField.Visible.Where((RuleField f) => f.Attr.Tab == tab))
				{
					Rows.Add(item.IsBool ? AddToggleRow(val5, transform2, item) : AddSliderRow(val6, transform2, item));
				}
			}
			FitContainer(content);
			_button = BuildOpenButton(val7, transform);
			Mod.Log.Msg($"[lobby-ui] 'match rules' button and screen added ({Rows.Count} rules).");
		}

		private static void DestroyChildNamed(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			for (int num = parent.childCount - 1; num >= 0; num--)
			{
				if (((Object)parent.GetChild(num)).name == name)
				{
					Object.DestroyImmediate((Object)(object)((Component)parent.GetChild(num)).gameObject);
				}
			}
		}

		private static GameObject BuildScreen(GameObject advanced, out RectTransform content)
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(advanced, advanced.transform.parent, false);
			((Object)val).name = "BBMR_MatchRulesScreen";
			val.SetActive(false);
			val.transform.SetSiblingIndex(advanced.transform.GetSiblingIndex() + 1);
			StripGameLogic(val, alsoBots: true);
			content = val.GetComponentInChildren<ScrollRect>(true).content;
			for (int num = ((Transform)content).childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)((Transform)content).GetChild(num)).gameObject);
			}
			foreach (TMP_Text componentsInChild in val.GetComponentsInChildren<TMP_Text>(true))
			{
				if (componentsInChild.text != null && componentsInChild.text.Trim().Equals("ADVANCED SETTINGS", StringComparison.OrdinalIgnoreCase))
				{
					componentsInChild.text = "MATCH RULES";
				}
			}
			Transform obj = val.transform.Find("ExitButton");
			Button val2 = ((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.onClick = new ButtonClickedEvent();
				((UnityEvent)val2.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)new Action(CloseScreen)));
			}
			_menu = val.GetComponent<MenuScreen>();
			return val;
		}

		private static GameObject BuildOpenButton(GameObject advancedButton, Transform cfg)
		{
			//IL_0020: 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_0030: 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)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			GameObject obj = Clone(advancedButton, cfg);
			((Object)obj).name = "Button_MatchRules";
			RectTransform component = advancedButton.GetComponent<RectTransform>();
			RectTransform component2 = obj.GetComponent<RectTransform>();
			Vector2 anchoredPosition = component.anchoredPosition;
			Rect rect = component.rect;
			component2.anchoredPosition = anchoredPosition + new Vector2(0f, 0f - (((Rect)(ref rect)).height + 15f));
			SetText(obj.GetComponentInChildren<TMP_Text>(true), "match rules");
			Button componentInChildren = obj.GetComponentInChildren<Button>(true);
			componentInChildren.onClick = new ButtonClickedEvent();
			((UnityEvent)componentInChildren.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)new Action(OpenScreen)));
			return obj;
		}

		private static void OpenScreen()
		{
			if (!Alive(_screen))
			{
				return;
			}
			_screen.SetActive(true);
			try
			{
				MenuScreen menu = _menu;
				if (menu != null)
				{
					menu.Show(true);
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[lobby-ui] Show failed, opening directly: " + ex.Message);
				CanvasGroup component = _screen.GetComponent<CanvasGroup>();
				if ((Object)(object)component != (Object)null)
				{
					component.alpha = 1f;
					component.interactable = true;
					component.blocksRaycasts = true;
				}
			}
			Refresh();
		}

		private static void CloseScreen()
		{
			if (!Alive(_screen))
			{
				return;
			}
			try
			{
				MenuScreen menu = _menu;
				if (menu != null)
				{
					menu.Hide(false);
				}
			}
			catch
			{
			}
			_screen.SetActive(false);
		}

		private static void StripGameLogic(GameObject go, bool alsoBots = false)
		{
			foreach (Component item in (Il2CppArrayBase<Component>)(object)go.GetComponentsInChildren(Il2CppType.Of<Component>(), true))
			{
				if (!((Object)(object)item == (Object)null))
				{
					string name = ((MemberInfo)((Object)item).GetIl2CppType()).Name;
					bool flag;
					switch (name)
					{
					case "LocalizeStringEvent":
					case "TextAnimator":
					case "SliderValueText":
					case "Tooltip":
					case "DirectedNavigation":
						flag = true;
						break;
					default:
						flag = false;
						break;
					}
					if (flag || (alsoBots && name == "CustomLobbyBotsUI"))
					{
						Object.DestroyImmediate((Object)(object)item);
					}
				}
			}
		}

		private static GameObject BuildContainer(RectTransform content)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			GameObject val = new GameObject("BBMR_MatchRules");
			RectTransform obj = val.AddComponent<RectTransform>();
			((Transform)obj).SetParent((Transform)(object)content, false);
			((Transform)obj).SetAsLastSibling();
			obj.anchorMin = new Vector2(0.5f, 1f);
			obj.anchorMax = new Vector2(0.5f, 1f);
			obj.pivot = new Vector2(0.5f, 1f);
			obj.sizeDelta = new Vector2(1000f, 100f);
			VerticalLayoutGroup obj2 = val.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 14f;
			((LayoutGroup)obj2).childAlignment = (TextAnchor)1;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			((LayoutGroup)obj2).padding.top = 30;
			((LayoutGroup)obj2).padding.bottom = 30;
			val.AddComponent<LayoutElement>();
			return val;
		}

		private static void FitContainer(RectTransform content)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = _container.GetComponent<RectTransform>();
			float num = 60f;
			Rect rect;
			for (int i = 0; i < ((Transform)component).childCount; i++)
			{
				float num2 = num;
				rect = ((Component)((Transform)component).GetChild(i)).GetComponent<RectTransform>().rect;
				num = num2 + (((Rect)(ref rect)).height + 14f);
			}
			component.sizeDelta = new Vector2(1000f, num);
			LayoutElement component2 = _container.GetComponent<LayoutElement>();
			component2.minHeight = num;
			component2.preferredHeight = num;
			component2.preferredWidth = 1000f;
			if ((Object)(object)((Component)content).GetComponent<LayoutGroup>() != (Object)null)
			{
				return;
			}
			float num3 = 0f;
			for (int j = 0; j < ((Transform)content).childCount; j++)
			{
				RectTransform component3 = ((Component)((Transform)content).GetChild(j)).GetComponent<RectTransform>();
				if (!((Object)(object)component3 == (Object)null) && !((Object)(object)component3 == (Object)(object)component) && ((Component)component3).gameObject.activeSelf)
				{
					float y = component3.anchoredPosition.y;
					rect = component3.rect;
					float num4 = y - ((Rect)(ref rect)).height * component3.pivot.y;
					num3 = Mathf.Min(num3, num4);
				}
			}
			component.anchoredPosition = new Vector2(0f, num3 - 20f);
			content.sizeDelta = new Vector2(content.sizeDelta.x, Mathf.Max(content.sizeDelta.y, 0f - num3 + 20f + num));
		}

		private static GameObject Clone(GameObject template, Transform parent)
		{
			GameObject obj = Object.Instantiate<GameObject>(template, parent, false);
			obj.SetActive(true);
			StripGameLogic(obj);
			return obj;
		}

		private static void SetText(TMP_Text t, string text)
		{
			if (!((Object)(object)t == (Object)null))
			{
				t.text = text;
				t.enableAutoSizing = true;
				t.fontSizeMin = 12f;
				t.fontSizeMax = Mathf.Max(t.fontSize, 30f);
			}
		}

		private static GameObject Sized(GameObject go, float width, float height)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = go.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(width, height);
			LayoutElement obj = go.GetComponent<LayoutElement>() ?? go.AddComponent<LayoutElement>();
			obj.preferredWidth = width;
			obj.preferredHeight = height;
			return go;
		}

		private static TMP_Text AddHeader(GameObject tpl, Transform root, string text)
		{
			GameObject val = Sized(Clone(tpl, root), 900f, 56f);
			TMP_Text obj = val.GetComponent<TMP_Text>() ?? val.GetComponentInChildren<TMP_Text>(true);
			SetText(obj, text);
			return obj;
		}

		private static Transform HorizontalRow(Transform root, float height)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("BBMR_Buttons");
			((Transform)val.AddComponent<RectTransform>()).SetParent(root, false);
			Sized(val, 900f, height);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 20f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)4;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			return val.transform;
		}

		private static TMP_Text AddButton(GameObject tpl, Transform root, string text, Action onClick)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			GameObject obj = Sized(Clone(tpl, root), 285f, 85f);
			TMP_Text componentInChildren = obj.GetComponentInChildren<TMP_Text>(true);
			SetText(componentInChildren, text);
			Button componentInChildren2 = obj.GetComponentInChildren<Button>(true);
			componentInChildren2.onClick = new ButtonClickedEvent();
			((UnityEvent)componentInChildren2.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)onClick));
			Controls.Add((Selectable)(object)componentInChildren2);
			return componentInChildren;
		}

		private static Row AddToggleRow(GameObject tpl, Transform root, RuleField field)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			GameObject obj = Clone(tpl, root);
			WidenRow(obj, "Label Variant");
			Transform obj2 = obj.transform.Find("Label Variant/LabelText");
			SetText((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null, field.Attr.Label);
			Toggle componentInChildren = obj.GetComponentInChildren<Toggle>(true);
			componentInChildren.onValueChanged = new ToggleEvent();
			((UnityEvent<bool>)(object)componentInChildren.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<bool>>((Delegate)(Action<bool>)delegate(bool on)
			{
				Set(field, on ? 1 : 0);
			}));
			Controls.Add((Selectable)(object)componentInChildren);
			return new Row
			{
				Field = field,
				Toggle = componentInChildren
			};
		}

		private static Row AddSliderRow(GameObject tpl, Transform root, RuleField field)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			bool flag = field.Attr.Choices != null;
			GameObject obj = Clone(tpl, root);
			WidenRow(obj, "Label Variant", flag ? 450f : 540f);
			Transform obj2 = obj.transform.Find("Label Variant/LabelText");
			SetText((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null, field.Attr.Label);
			RuleAttribute a = field.Attr;
			int num = (int)Math.Round((a.Max - a.Min) / a.Step);
			Slider componentInChildren = obj.GetComponentInChildren<Slider>(true);
			componentInChildren.onValueChanged = new SliderEvent();
			componentInChildren.wholeNumbers = true;
			componentInChildren.minValue = 0f;
			componentInChildren.maxValue = num;
			((UnityEvent<float>)(object)componentInChildren.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<float>>((Delegate)(Action<float>)delegate(float v)
			{
				Set(field, a.Min + Math.Round(v) * a.Step);
			}));
			Controls.Add((Selectable)(object)componentInChildren);
			float num2 = (flag ? 200f : 110f);
			Transform obj3 = obj.transform.Find("Label_Value/LabelText");
			TMP_Text val = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
			Transform obj4 = obj.transform.Find("Label_Value");
			LayoutElement val2 = ((obj4 != null) ? ((Component)obj4).GetComponent<LayoutElement>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.preferredWidth = num2;
				val2.minWidth = num2;
			}
			RectTransform val3 = ((val != null) ? ((Component)val).GetComponent<RectTransform>() : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.sizeDelta = new Vector2(num2, val3.sizeDelta.y);
			}
			SetText(val, "");
			return new Row
			{
				Field = field,
				Slider = componentInChildren,
				Value = val,
				Steps = num
			};
		}

		private static void WidenRow(GameObject row, string labelName, float labelWidth = 560f)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = row.GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(900f, component.sizeDelta.y);
			Transform val = row.transform.Find(labelName);
			LayoutElement val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<LayoutElement>() : null);
			if ((Object)(object)val2 == (Object)null && (Object)(object)val != (Object)null)
			{
				val2 = ((Component)val).gameObject.AddComponent<LayoutElement>();
			}
			if ((Object)(object)val2 != (Object)null)
			{
				val2.preferredWidth = labelWidth;
				val2.minWidth = labelWidth;
			}
			RectTransform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<RectTransform>() : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.sizeDelta = new Vector2(labelWidth, val3.sizeDelta.y);
			}
		}

		private static void Set(RuleField field, double value)
		{
			if (Editable && !_refreshing)
			{
				field.Set(Mod.Local, (Math.Abs(value - field.Attr.Default) < field.Attr.Step / 2.0) ? ((double?)null) : new double?(value));
				RulesMenu.NotifyChanged();
			}
		}

		private static void CyclePreset()
		{
			if (Editable)
			{
				List<string> list = PresetStore.List();
				if (list.Count != 0)
				{
					int num = list.IndexOf(PresetStore.FindMatching(Mod.Local) ?? "");
					Mod.Local = PresetStore.Load(list[(num + 1) % list.Count]);
					RulesMenu.NotifyChanged();
				}
			}
		}

		private static void SavePreset()
		{
			if (Editable)
			{
				string text = PresetStore.SaveNew(Mod.Local);
				RulesMenu.Toast("Saved preset \"" + text + "\" in UserData/MatchRules", 5f);
			}
		}

		private static void ResetAll()
		{
			if (Editable)
			{
				Mod.Local = new RuleSet();
				RulesMenu.NotifyChanged();
			}
		}

		private static void Refresh()
		{
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			RuleSet shown = Shown;
			_refreshing = true;
			try
			{
				foreach (Selectable control in Controls)
				{
					if ((Object)(object)control != (Object)null)
					{
						control.interactable = Editable;
					}
				}
				foreach (Row row in Rows)
				{
					double? num = row.Field.Get(shown);
					double num2 = num ?? row.Field.Attr.Default;
					if ((Object)(object)row.Toggle != (Object)null)
					{
						row.Toggle.SetIsOnWithoutNotify(num2 >= 0.5);
					}
					if ((Object)(object)row.Slider != (Object)null)
					{
						row.Slider.SetValueWithoutNotify((float)Math.Round((num2 - row.Field.Attr.Min) / row.Field.Attr.Step));
						if ((Object)(object)row.Value != (Object)null)
						{
							row.Value.text = row.Field.FormatValue(num2);
							((Graphic)row.Value).color = (Color)((!num.HasValue) ? Color.white : new Color(1f, 0.83f, 0.3f));
						}
					}
				}
				if ((Object)(object)_presetLabel != (Object)null)
				{
					_presetLabel.text = "Preset: " + (PresetStore.FindMatching(shown) ?? "custom");
				}
				if ((Object)(object)_statusLabel != (Object)null)
				{
					string text = MissingModWarning(shown);
					TMP_Text statusLabel = _statusLabel;
					string text2 = text;
					if (text2 == null)
					{
						text2 = Session.Role switch
						{
							Role.Host => "Your rules are active for this room", 
							Role.Client => (Session.Received == null) ? "Host isn't using Match Rules" : "Host's rules (read-only)", 
							_ => "Rules apply when you host", 
						};
					}
					statusLabel.text = text2;
					((Graphic)_statusLabel).color = ((text != null) ? new Color(1f, 0.6f, 0.3f) : new Color(0.85f, 0.85f, 0.85f));
				}
			}
			finally
			{
				_refreshing = false;
			}
		}

		private static string MissingModWarning(RuleSet rules)
		{
			if (Session.Role == Role.Inactive || !rules.HasAllPlayersRules)
			{
				return null;
			}
			List<string> list = (from m in Session.Members()
				where string.IsNullOrEmpty(m.Version)
				select m.Name).ToList();
			if (list.Count == 0)
			{
				return null;
			}
			string text = string.Join(", ", list.Take(3)) + ((list.Count > 3) ? $" +{list.Count - 3}" : "");
			return "Without the mod: " + text + ". Physics & Arena rules won't work for them!";
		}

		private static T FindInScene<T>() where T : Component
		{
			//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)
			foreach (Object item in (Il2CppArrayBase<Object>)(object)Resources.FindObjectsOfTypeAll(Il2CppType.Of<T>()))
			{
				T val = ((Il2CppObjectBase)item).TryCast<T>();
				if ((Object)(object)val != (Object)null)
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						return val;
					}
				}
			}
			return default(T);
		}
	}
	public static class RulesMenu
	{
		private const string InputLockKey = "bbmr.menu";

		private static readonly string[] Tabs = RuleField.VisibleTabs.Select(TabInfo.Short).Concat(new string[2] { "Presets", "Players" }).ToArray();

		private static readonly int RuleTabs = RuleField.VisibleTabs.Count;

		private static int _tab;

		private static int _row;

		private static string _flash;

		private static float _flashUntil;

		private static string _toast;

		private static float _toastUntil;

		private static GUIStyle _label;

		private static List<string> _presets = new List<string>();

		private static int PresetsTab => RuleTabs;

		private static Tab? CurrentTab
		{
			get
			{
				if (_tab >= RuleTabs)
				{
					return null;
				}
				return RuleField.VisibleTabs[_tab];
			}
		}

		public static bool Open { get; private set; }

		private static bool Editable => Session.Role != Role.Client;

		private static RuleSet Shown
		{
			get
			{
				if (Session.Role != Role.Client)
				{
					return Mod.Local;
				}
				return Session.Received ?? new RuleSet();
			}
		}

		public static void Toast(string text, float seconds = 8f)
		{
			_toast = text;
			_toastUntil = Time.unscaledTime + seconds;
		}

		private static void Flash(string text)
		{
			_flash = text;
			_flashUntil = Time.unscaledTime + 3f;
		}

		public static void Update()
		{
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return;
			}
			if (((ButtonControl)current.f6Key).wasPressedThisFrame)
			{
				SetOpen(!Open);
			}
			if (!Open)
			{
				return;
			}
			if (((ButtonControl)current.qKey).wasPressedThisFrame || ((ButtonControl)current.pageUpKey).wasPressedThisFrame)
			{
				_tab = (_tab + Tabs.Length - 1) % Tabs.Length;
				_row = 0;
			}
			if (((ButtonControl)current.eKey).wasPressedThisFrame || ((ButtonControl)current.pageDownKey).wasPressedThisFrame)
			{
				_tab = (_tab + 1) % Tabs.Length;
				_row = 0;
			}
			int num = RowCount();
			if (num > 0)
			{
				if (((ButtonControl)current.upArrowKey).wasPressedThisFrame)
				{
					_row = (_row + num - 1) % num;
				}
				if (((ButtonControl)current.downArrowKey).wasPressedThisFrame)
				{
					_row = (_row + 1) % num;
				}
				_row = Math.Clamp(_row, 0, num - 1);
			}
			bool flag = ((ButtonControl)current.leftShiftKey).isPressed || ((ButtonControl)current.rightShiftKey).isPressed;
			int num2 = (((ButtonControl)current.rightArrowKey).wasPressedThisFrame ? 1 : (((ButtonControl)current.leftArrowKey).wasPressedThisFrame ? (-1) : 0));
			if (_tab < RuleTabs)
			{
				RuleField ruleField = FieldsFor(_tab).ElementAtOrDefault(_row);
				if (ruleField == null)
				{
					return;
				}
				if (!Editable)
				{
					if (num2 != 0 || ((ButtonControl)current.backspaceKey).wasPressedThisFrame)
					{
						Flash("Only the host can change the rules.");
					}
					return;
				}
				if (num2 != 0)
				{
					double num3 = ruleField.Get(Mod.Local) ?? ruleField.Attr.Default;
					double value = (ruleField.IsBool ? ((double)((!(num3 >= 0.5)) ? 1 : 0)) : (num3 + (double)num2 * ruleField.Attr.Step * (double)((!flag) ? 1 : 10)));
					ruleField.Set(Mod.Local, value);
					Changed();
				}
				if (((ButtonControl)current.backspaceKey).wasPressedThisFrame || ((ButtonControl)current.deleteKey).wasPressedThisFrame)
				{
					ruleField.Set(Mod.Local, null);
					Changed();
				}
			}
			else if (_tab == PresetsTab && (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame))
			{
				UsePresetRow();
			}
		}

		public static void NotifyChanged()
		{
			Changed();
		}

		private static void Changed()
		{
			Session.ForceReapply();
		}

		private static void UsePresetRow()
		{
			if (!Editable)
			{
				Flash("Only the host can change the rules.");
				return;
			}
			try
			{
				if (_row < _presets.Count)
				{
					Mod.Local = PresetStore.Load(_presets[_row]);
					Changed();
					Flash("Loaded preset \"" + _presets[_row] + "\"");
				}
				else if (_row == _presets.Count)
				{
					string text = PresetStore.SaveNew(Mod.Local);
					RefreshPresets();
					Flash("Saved as \"" + text + "\" in UserData/MatchRules");
				}
			}
			catch (Exception ex)
			{
				Flash("Preset error: " + ex.Message);
			}
		}

		private static void RefreshPresets()
		{
			_presets = PresetStore.List();
		}

		private static IEnumerable<RuleField> FieldsFor(int tab)
		{
			if (tab >= RuleTabs)
			{
				return Enumerable.Empty<RuleField>();
			}
			return RuleField.Visible.Where((RuleField f) => f.Attr.Tab == RuleField.VisibleTabs[tab]);
		}

		private static int RowCount()
		{
			_ = _tab;
			if (_tab < RuleTabs)
			{
				return FieldsFor(_tab).Count();
			}
			if (_tab == PresetsTab)
			{
				return _presets.Count + 1;
			}
			return 0;
		}

		private static void SetOpen(bool open)
		{
			if (open == Open)
			{
				return;
			}
			Open = open;
			if (open)
			{
				RefreshPresets();
			}
			try
			{
				PlayerControls controls = PlayerInputManager.Controls;
				InputActionMap val = ((controls != null) ? controls.Actions.Get() : null);
				if (val != null)
				{
					if (open)
					{
						PlayerInputManager.AddKeyedGroupInputLock("bbmr.menu", val, false);
					}
					else
					{
						PlayerInputManager.RemoveKeyedGroupInputLock("bbmr.menu", val);
					}
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[menu] input lock failed: " + ex.Message);
			}
		}

		public static void Draw()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_01ac: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EnsureStyle();
				float num = Mathf.Max(1f, (float)Screen.height / 1080f);
				GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
				if (!Open)
				{
					if (_toast != null && Time.unscaledTime < _toastUntil)
					{
						Panel(new Rect(20f, 20f, 520f, 40f), "<b>Match Rules</b>  " + _toast);
					}
					return;
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("<size=22><b>Beetleball Match Rules</b></size>   <color=#aaaaaa>v0.1.0</color>");
				stringBuilder.AppendLine(StatusLine());
				stringBuilder.AppendLine();
				for (int i = 0; i < Tabs.Length; i++)
				{
					stringBuilder.Append((i == _tab) ? ("<color=#ffd34d><b>[" + Tabs[i] + "]</b></color>  ") : ("<color=#bbbbbb>" + Tabs[i] + "</color>  "));
				}
				stringBuilder.AppendLine();
				stringBuilder.AppendLine();
				if (_tab < RuleTabs)
				{
					DrawRules(stringBuilder);
				}
				else if (_tab == PresetsTab)
				{
					DrawPresets(stringBuilder);
				}
				else
				{
					DrawPlayers(stringBuilder);
				}
				stringBuilder.AppendLine();
				if (_flash != null && Time.unscaledTime < _flashUntil)
				{
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(23, 1, stringBuilder2);
					handler.AppendLiteral("<color=#7fff7f>");
					handler.AppendFormatted(_flash);
					handler.AppendLiteral("</color>");
					stringBuilder2.AppendLine(ref handler);
				}
				stringBuilder.Append("<color=#999999>F6 close · Q/E tab · ↑↓ select · ←→ change (Shift ×10) · Backspace normal · Enter use preset</color>");
				Panel(new Rect(20f, 20f, 640f, 700f), stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[menu] draw failed: " + ex.Message);
				Open = false;
			}
		}

		private static string StatusLine()
		{
			switch (Session.Role)
			{
			case Role.Host:
				return "<color=#7fff7f>Hosting a custom room: these rules are active and shared with the room.</color>";
			case Role.Client:
				if (Session.Received != null)
				{
					return "<color=#7fd4ff>Host's rules (read-only).</color>";
				}
				return "<color=#ffb04d>The host is not using Match Rules: normal rules.</color>";
			default:
				return "<color=#bbbbbb>Not in a custom room. Rules take effect when you host one.</color>";
			}
		}

		private static void DrawRules(StringBuilder sb)
		{
			RuleSet shown = Shown;
			int num = 0;
			foreach (RuleField item in FieldsFor(_tab))
			{
				bool flag = num++ == _row;
				string text = item.Format(shown);
				string text2 = string.Concat(str2: item.Get(shown).HasValue ? ("<color=#ffd34d>" + text + "</color>") : text, str0: item.Attr.Label, str1: ": ");
				sb.AppendLine(flag ? ("<color=#ffffff><b>> " + text2 + "</b></color>") : ("  <color=#dddddd>" + text2 + "</color>"));
			}
			if (CurrentTab == Tab.AllPlayers)
			{
				sb.AppendLine();
				sb.AppendLine("<color=#ffb04d>Every player needs the mod for these. Players without it will see glitchy balls/movement.</color>");
			}
			else if (CurrentTab == Tab.RoundStart)
			{
				sb.AppendLine();
				sb.AppendLine("<color=#999999>Applies at match start and after every goal. \"Full grown\" = max dung size (5 normally).</color>");
			}
			else if (CurrentTab == Tab.Match)
			{
				sb.AppendLine();
				sb.AppendLine("<color=#999999>Match length and goals apply from the next match start.</color>");
			}
		}

		private static void DrawPresets(StringBuilder sb)
		{
			for (int i = 0; i <= _presets.Count; i++)
			{
				string text = ((i < _presets.Count) ? _presets[i] : "+ Save current rules as a new preset");
				sb.AppendLine((i == _row) ? ("<color=#ffffff><b>> " + text + "</b></color>") : ("  <color=#dddddd>" + text + "</color>"));
			}
			sb.AppendLine();
			sb.AppendLine("<color=#999999>Preset files: UserData/MatchRules/*.json (share them with friends).</color>");
		}

		private static void DrawPlayers(StringBuilder sb)
		{
			List<Session.MemberStatus> list = Session.Members();
			if (list.Count == 0)
			{
				sb.AppendLine("<color=#bbbbbb>Not in a room.</color>");
				return;
			}
			foreach (Session.MemberStatus item in list)
			{
				string value = (string.IsNullOrEmpty(item.Version) ? "<color=#ff7f7f>no mod</color>" : ("<color=#7fff7f>mod v" + item.Version + "</color>"));
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, sb);
				handler.AppendLiteral("  ");
				handler.AppendFormatted(item.Name);
				handler.AppendLiteral(": ");
				handler.AppendFormatted(value);
				sb.AppendLine(ref handler);
			}
			if (Mod.Local.HasAllPlayersRules && list.Any((Session.MemberStatus m) => string.IsNullOrEmpty(m.Version)))
			{
				sb.AppendLine("\n<color=#ffb04d>Physics & Arena rules are on, but some players don't have the mod.</color>");
			}
		}

		private static void EnsureStyle()
		{
			if (_label == null)
			{
				_label = GUI.skin.label;
				_label.richText = true;
				_label.fontSize = 17;
				_label.wordWrap = true;
			}
		}

		private static void Panel(Rect r, string text)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			GUI.Box(r, "");
			GUI.Box(r, "");
			GUI.Label(new Rect(((Rect)(ref r)).x + 14f, ((Rect)(ref r)).y + 10f, ((Rect)(ref r)).width - 28f, ((Rect)(ref r)).height - 20f), text);
		}
	}
	public static class WallEditor
	{
		private const float MinHeight = 2f;

		private const float MaxHeight = 60f;

		private const float HeightStep = 2f;

		private static readonly string[] MirrorNames = new string[3] { "Off", "Other side of the pitch", "All 4 corners" };

		private static WallLayout _layout;

		private static GameObject _preview;

		private static GameObject _cursor;

		private static GameObject _ghost;

		private static Material _glass;

		private static Material _rim;

		private static Material _faint;

		private static Material _marker;

		private static Material _ghostMat;

		private static Vector3? _aim;

		private static string _flash;

		private static float _flashUntil;

		private static float _confirmClearUntil;

		public static bool Open { get; private set; }

		private static Material GlassMat => Mat(ref _glass, new Color(0.55f, 0.85f, 1f, 0.3f));

		private static Material RimMat => Mat(ref _rim, new Color(0.75f, 0.95f, 1f, 0.8f));

		private static Material FaintMat => Mat(ref _faint, new Color(0.55f, 0.85f, 1f, 0.12f));

		private static Material MarkerMat => Mat(ref _marker, new Color(1f, 0.8f, 0.2f, 0.95f));

		private static Material GhostMat => Mat(ref _ghostMat, new Color(1f, 0.85f, 0.3f, 0.2f));

		private static void Flash(string text)
		{
			_flash = text;
			_flashUntil = Time.unscaledTime + 3f;
		}

		public static void Update()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return;
			}
			if (((ButtonControl)current.f7Key).wasPressedThisFrame)
			{
				if (Open)
				{
					Close();
				}
				else
				{
					TryOpen();
				}
			}
			if (!Open)
			{
				return;
			}
			MatchStateController val = null;
			try
			{
				val = MatchStateController.Instance;
			}
			catch
			{
			}
			if ((Object)(object)val == (Object)null || Mod.CurrentScene != _layout.Scene)
			{
				Close();
			}
			else
			{
				if (RulesMenu.Open)
				{
					return;
				}
				_aim = Aim();
				List<float[]> list = CurrentLine();
				if (((ButtonControl)current.f8Key).wasPressedThisFrame)
				{
					if (_aim.HasValue)
					{
						list.Add(WallLayout.P(_aim.Value));
						Rebuild(val);
					}
					else
					{
						Flash("Aim the crosshair at the ground first.");
					}
				}
				if (((ButtonControl)current.f9Key).wasPressedThisFrame)
				{
					Undo();
					Rebuild(val);
				}
				if (((ButtonControl)current.f10Key).wasPressedThisFrame)
				{
					if (list.Count > 0)
					{
						_layout.Lines.Add(new List<float[]>());
						Flash("New wall line started.");
					}
					else
					{
						Flash("This line is already empty: just place points.");
					}
				}
				if (((ButtonControl)current.f11Key).wasPressedThisFrame)
				{
					CloseShape(val);
				}
				if (((ButtonControl)current.insertKey).wasPressedThisFrame)
				{
					_layout.Mirror = (_layout.Mirror + 1) % MirrorNames.Length;
					Rebuild(val);
					Flash("Mirror: " + MirrorNames[_layout.Mirror]);
				}
				if (((ButtonControl)current.homeKey).wasPressedThisFrame && !WallLayout.IsInfinite(_layout.Height))
				{
					_layout.Height = ((_layout.Height + 2f > 60f) ? 1000f : (_layout.Height + 2f));
					Rebuild(val);
				}
				if (((ButtonControl)current.endKey).wasPressedThisFrame)
				{
					_layout.Height = (WallLayout.IsInfinite(_layout.Height) ? 60f : Mathf.Max(2f, _layout.Height - 2f));
					Rebuild(val);
				}
				if (((ButtonControl)current.deleteKey).wasPressedThisFrame)
				{
					if (Time.unscaledTime < _confirmClearUntil)
					{
						_layout.Lines.Clear();
						_layout.Lines.Add(new List<float[]>());
						Rebuild(val);
						Flash("All walls on this map removed.");
						_confirmClearUntil = 0f;
					}
					else
					{
						_confirmClearUntil = Time.unscaledTime + 3f;
						Flash("Press Delete again to remove ALL walls on this map.");
					}
				}
				UpdateCursorAndGhost();
			}
		}

		private static void TryOpen()
		{
			MatchStateController val = null;
			try
			{
				val = MatchStateController.Instance;
			}
			catch
			{
			}
			if ((Object)(object)val == (Object)null)
			{
				RulesMenu.Toast("Wall editor: start a match on the map you want to edit, then press F7.");
				return;
			}
			_layout = WallLayout.Load(Mod.CurrentScene) ?? new WallLayout
			{
				Scene = Mod.CurrentScene
			};
			_layout.Scene = Mod.CurrentScene;
			if (_layout.Lines.Count != 0)
			{
				List<List<float[]>> lines = _layout.Lines;
				if (lines[lines.Count - 1].Count <= 0)
				{
					goto IL_009c;
				}
			}
			_layout.Lines.Add(new List<float[]>());
			goto IL_009c;
			IL_009c:
			Open = true;
			ArenaWalls.Invalidate();
			Rebuild(val);
			Mod.Log.Msg("[wall-editor] editing " + _layout.Scene);
		}

		private static void Close()
		{
			if (!Open)
			{
				return;
			}
			Open = false;
			try
			{
				_layout.Lines.RemoveAll((List<float[]> l) => l.Count == 0);
				if (_layout.IsEmpty)
				{
					_layout.Delete();
					RulesMenu.Toast("No walls on " + _layout.Scene + ".");
				}
				else
				{
					_layout.Save();
					RulesMenu.Toast("Walls saved for " + _layout.Scene + ". They appear when \"Glass walls\" is On.");
				}
				Mod.Log.Msg($"[wall-editor] saved {_layout.Scene}: {_layout.Lines.Count} lines, mirror {_layout.Mirror}, height {_layout.Height}");
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[wall-editor] save failed: " + ex.Message);
			}
			Destroy(ref _preview);
			Destroy(ref _cursor);
			Destroy(ref _ghost);
			ArenaWalls.Invalidate();
		}

		private static void Destroy(ref GameObject go)
		{
			if ((Object)(object)go != (Object)null && !((Il2CppObjectBase)go).WasCollected)
			{
				Object.Destroy((Object)(object)go);
			}
			go = null;
		}

		private static List<float[]> CurrentLine()
		{
			if (_layout.Lines.Count == 0)
			{
				_layout.Lines.Add(new List<float[]>());
			}
			List<List<float[]>> lines = _layout.Lines;
			return lines[lines.Count - 1];
		}

		private static void CloseShape(MatchStateController match)
		{
			List<float[]> list = CurrentLine();
			if (list.Count < 3)
			{
				Flash("Place at least 3 points before closing the shape.");
				return;
			}
			float[] array = list[0];
			float[] array2 = list[list.Count - 1];
			if (array[0] == array2[0] && array[1] == array2[1] && array[2] == array2[2])
			{
				Flash("This shape is already closed.");
				return;
			}
			list.Add((float[])array.Clone());
			_layout.Lines.Add(new List<float[]>());
			Rebuild(match);
			Flash("Shape closed. Place points to start a new wall line.");
		}

		private static void Undo()
		{
			List<float[]> list = CurrentLine();
			if (list.Count > 0)
			{
				list.RemoveAt(list.Count - 1);
			}
			else if (_layout.Lines.Count > 1)
			{
				_layout.Lines.RemoveAt(_layout.Lines.Count - 1);
				List<float[]> list2 = CurrentLine();
				if (list2.Count > 0)
				{
					list2.RemoveAt(list2.Count - 1);
				}
			}
		}

		private static Vector3? Aim()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return null;
			}
			Ray val = main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
			Vector3? result = null;
			float num = float.MaxValue;
			foreach (RaycastHit item in (Il2CppArrayBase<RaycastHit>)(object)Physics.RaycastAll(val, 500f, WallLayout.GroundMask()))
			{
				RaycastHit current = item;
				Collider collider = ((RaycastHit)(ref current)).collider;
				if (!((Object)(object)collider == (Object)null) && !collider.isTrigger && !((Object)(object)collider.attachedRigidbody != (Object)null) && (!((Object)(object)_preview != (Object)null) || !((Component)collider).transform.IsChildOf(_preview.transform)) && ((RaycastHit)(ref current)).distance < num)
				{
					num = ((RaycastHit)(ref current)).distance;
					result = ((RaycastHit)(ref current)).point;
				}
			}
			return result;
		}

		private static Material Mat(ref Material m, Color c)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)m != (Object)null) || ((Il2CppObjectBase)m).WasCollected)
			{
				return m = WallLayout.MakeMaterial(c);
			}
			return m;
		}

		private static void Rebuild(MatchStateController match)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			Destroy(ref _preview);
			_preview = new GameObject("BBMR_WallEditor");
			var (layer, surface) = WallLayout.WallPhysics((Session.Active ?? Mod.Local).WallsNotWalkable == true);
			try
			{
				foreach (var (a, b) in _layout.Segments(match))
				{
					WallLayout.AddWall(_preview.transform, a, b, _layout.Height, layer, GlassMat, RimMat, FaintMat, collide: true, surface);
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[wall-editor] preview failed: " + ex.Message);
			}
			foreach (List<float[]> line in _layout.Lines)
			{
				foreach (float[] item in line)
				{
					Marker(_preview.transform, WallLayout.V(item), new Vector3(0.8f, 3f, 0.8f));
				}
			}
		}

		private static GameObject Marker(Transform parent, Vector3 groundPos, Vector3 size)
		{
			//IL_0039: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)val).name = "Marker";
			Object.Destroy((Object)(object)val.GetComponent<Collider>());
			if ((Object)(object)parent != (Object)null)
			{
				val.transform.SetParent(parent, false);
			}
			val.transform.position = groundPos + Vector3.up * (size.y * 0.5f);
			val.transform.localScale = size;
			WallLayout.Style(val, MarkerMat);
			return val;
		}

		private static void UpdateCursorAndGhost()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_cursor == (Object)null || ((Il2CppObjectBase)_cursor).WasCollected)
			{
				_cursor = Marker(null, Vector3.zero, new Vector3(0.5f, 8f, 0.5f));
			}
			_cursor.SetActive(_aim.HasValue);
			if (_aim.HasValue)
			{
				_cursor.transform.position = _aim.Value + Vector3.up * 4f;
			}
			List<float[]> list = CurrentLine();
			bool flag = _aim.HasValue && list.Count > 0;
			if ((Object)(object)_ghost == (Object)null || ((Il2CppObjectBase)_ghost).WasCollected)
			{
				_ghost = GameObject.CreatePrimitive((PrimitiveType)3);
				((Object)_ghost).name = "Ghost";
				Object.Destroy((Object)(object)_ghost.GetComponent<Collider>());
				WallLayout.Style(_ghost, GhostMat);
			}
			_ghost.SetActive(flag);
			if (flag)
			{
				Vector3 val = WallLayout.V(list[list.Count - 1]);
				Vector3 value = _aim.Value;
				Vector3 val2 = value - val;
				val2.y = 0f;
				if (((Vector3)(ref val2)).magnitude < 0.2f)
				{
					_ghost.SetActive(false);
					return;
				}
				bool flag2 = WallLayout.IsInfinite(_layout.Height);
				float num = Mathf.Min(val.y, value.y) - (flag2 ? 30f : 3f);
				float num2 = Mathf.Max(val.y, value.y) + (flag2 ? 30f : _layout.Height);
				Vector3 val3 = (val + value) * 0.5f;
				_ghost.transform.position = new Vector3(val3.x, (num + num2) * 0.5f, val3.z);
				_ghost.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up);
				_ghost.transform.localScale = new Vector3(2f, num2 - num, ((Vector3)(ref val2)).magnitude);
			}
		}

		public static void Draw()
		{
			//IL_0027: 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_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_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			if (!Open || _layout == null)
			{
				return;
			}
			try
			{
				float num = Mathf.Max(1f, (float)Screen.height / 1080f);
				GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
				int num2 = 0;
				foreach (List<float[]> line in _layout.Lines)
				{
					num2 += line.Count;
				}
				string value = (_aim.HasValue ? "" : "   <color=#ffb04d>(aim at the ground)</color>");
				string text = ((Session.Role == Role.Client) ? "\n<color=#ffb04d>You're not the host: your walls are only used in rooms you host.</color>" : "");
				string text2 = ((_flash != null && Time.unscaledTime < _flashUntil) ? ("\n<color=#7fff7f>" + _flash + "</color>") : "");
				string text3 = $"<size=20><b>WALL EDITOR</b></size>  <color=#aaaaaa>{_layout.Scene}</color>{value}\nLines: {_layout.Lines.FindAll((List<float[]> l) => l.Count > 0).Count}   Points: {num2}   Mirror: <color=#ffd34d>{MirrorNames[_layout.Mirror]}</color>   Height: <color=#ffd34d>{WallLayout.HeightText(_layout.Height)}</color>\n" + "<color=#dddddd>F8</color> place point at crosshair   <color=#dddddd>F9</color> undo   <color=#dddddd>F10</color> new wall line   <color=#dddddd>F11</color> close shape\n<color=#dddddd>Insert</color> mirror   <color=#dddddd>Home/End</color> height (above 60m = Infinite)   <color=#dddddd>Delete</color> x2 clear map   <color=#dddddd>F7</color> save & exit" + text + text2;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(20f, (float)Screen.height / num - 210f, 760f, 190f);
				GUI.Box(val, "");
				GUI.Box(val, "");
				GUI.Label(new Rect(((Rect)(ref val)).x + 14f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 28f, ((Rect)(ref val)).height - 20f), text3);
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[wall-editor] draw failed: " + ex.Message);
			}
		}
	}
}
namespace BeetleballMatchRules.Rules
{
	public static class ArenaWalls
	{
		private const string RootName = "BBMR_ArenaWalls";

		public const string LobbyKey = "bbmr.walls";

		private static GameObject _root;

		private static IntPtr _builtFor;

		private static float _seenAt = -1f;

		private static float _next;

		private static string _published;

		private static Material _glass;

		private static Material _rim;

		private static Material _faint;

		public static Material Glass
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				if (!Alive(_glass))
				{
					return _glass = WallLayout.MakeMaterial(new Color(0.65f, 0.9f, 1f, 0.12f));
				}
				return _glass;
			}
		}

		public static Material Rim
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				if (!Alive(_rim))
				{
					return _rim = WallLayout.MakeMaterial(new Color(0.75f, 0.95f, 1f, 0.5f));
				}
				return _rim;
			}
		}

		public static Material Faint
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				if (!Alive(_faint))
				{
					return _faint = WallLayout.MakeMaterial(new Color(0.65f, 0.9f, 1f, 0.05f));
				}
				return _faint;
			}
		}

		private static bool Alive(Material m)
		{
			if ((Object)(object)m != (Object)null)
			{
				return !((Il2CppObjectBase)m).WasCollected;
			}
			return false;
		}

		public static void Invalidate()
		{
			Remove();
			_builtFor = IntPtr.Zero;
			_published = null;
		}

		public static void Tick()
		{
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < _next)
			{
				return;
			}
			_next = Time.unscaledTime + 0.5f;
			MatchStateController val = null;
			try
			{
				val = MatchStateController.Instance;
			}
			catch
			{
			}
			RuleSet active = Session.Active;
			if (active == null || active.ArenaWalls != true || Session.Role == Role.Inactive || !((Object)(object)val != (Object)null) || WallEditor.Open)
			{
				Remove();
				_seenAt = -1f;
				_builtFor = IntPtr.Zero;
				return;
			}
			if (Session.Role == Role.Host)
			{
				PublishLayout();
			}
			if ((Object)(object)_root != (Object)null && !((Il2CppObjectBase)_root).WasCollected && _builtFor == ((Il2CppObjectBase)val).Pointer)
			{
				return;
			}
			if (_builtFor != ((Il2CppObjectBase)val).Pointer)
			{
				Remove();
				_builtFor = ((Il2CppObjectBase)val).Pointer;
				_seenAt = Time.unscaledTime;
			}
			float num = Time.unscaledTime - _seenAt;
			if (num < 2f)
			{
				return;
			}
			WallLayout layout;
			if (Session.Role == Role.Host)
			{
				layout = WallLayout.Load(Mod.CurrentScene);
			}
			else if (!TryReadHostLayout(out layout))
			{
				if (num < 10f)
				{
					return;
				}
				Mod.Log.Warning("[walls] no wall layout received from the host for " + Mod.CurrentScene);
			}
			_root = new GameObject("BBMR_ArenaWalls");
			if (layout == null || layout.IsEmpty)
			{
				Mod.Log.Msg("[walls] " + Mod.CurrentScene + ": this map has no wall layout");
				return;
			}
			try
			{
				(int layer, PhysicsMaterial surface) tuple = WallLayout.WallPhysics(Session.Active.WallsNotWalkable == true);
				int item = tuple.layer;
				PhysicsMaterial item2 = tuple.surface;
				List<(Vector3, Vector3)> list = layout.Segments(val);
				foreach (var (a, b) in list)
				{
					WallLayout.AddWall(_root.transform, a, b, layout.Height, item, Glass, Rim, Faint, collide: true, item2);
				}
				Mod.Log.Msg($"[walls] {Mod.CurrentScene}: built {list.Count} wall sections");
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[walls] build failed: " + ex.Message);
			}
		}

		private static void Remove()
		{
			if ((Object)(object)_root != (Object)null && !((Il2CppObjectBase)_root).WasCollected)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
		}

		private static void PublishLayout()
		{
			string text = (WallLayout.Load(Mod.CurrentScene) ?? new WallLayout
			{
				Scene = Mod.CurrentScene
			}).ToJson();
			if (text == _published)
			{
				return;
			}
			try
			{
				ILobby currentLobby = Session.CurrentLobby;
				if (currentLobby != null)
				{
					currentLobby.SetData("bbmr.walls", text);
				}
				_published = text;
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[walls] publish failed: " + ex.Message);
			}
		}

		private static bool TryReadHostLayout(out WallLayout layout)
		{
			layout = null;
			try
			{
				ILobby currentLobby = Session.CurrentLobby;
				WallLayout wallLayout = WallLayout.FromJson((currentLobby != null) ? currentLobby.GetData("bbmr.walls") : null);
				if (wallLayout == null || wallLayout.Scene != Mod.CurrentScene)
				{
					return false;
				}
				layout = wallLayout;
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	public static class DungPatches
	{
		private static bool _inBunny;

		private static bool _inStartingBalls;

		private static bool _spawningExtras;

		private static bool _kickoffSpawn;

		private static int _singleBallFrame = -1;

		private static TeamType _singleBallTeam;

		private static IntPtr _singleBallMatch;

		private static int _centerBallFrame = -1;

		private static DungBallDataSO _data;

		private static DungBallDataSO Data
		{
			get
			{
				if ((Object)(object)_data != (Object)null && !((Il2CppObjectBase)_data).WasCollected)
				{
					return _data;
				}
				_data = null;
				DungBallDataSO[] array = AssetOverrides.All<DungBallDataSO>();
				foreach (DungBallDataSO val in array)
				{
					if ((Object)(object)_data == (Object)null || ((Object)val).name == "Data_DungBall")
					{
						_data = val;
					}
				}
				return _data;
			}
		}

		public static void Register(Patcher p)
		{
			p.Prefix(typeof(BunnySpawner), "SpawnBunnyAndUpdateTime", "BunnySpawnPrefix", typeof(DungPatches));
			p.Prefix(typeof(BunnyPathJumper), "Update", "BunnyUpdatePrefix", typeof(DungPatches));
			p.Postfix(typeof(BunnyPathJumper), "Update", "BunnyUpdatePostfix", typeof(DungPatches));
			p.Prefix(typeof(MatchStateController), "SpawnStartingBallsAtTeam", "StartingPrefix", typeof(DungPatches));
			p.Postfix(typeof(MatchStateController), "SpawnStartingBallsAtTeam", "StartingPostfix", typeof(DungPatches));
			p.Prefix(typeof(NetworkPrefabSpawner), "SpawnDungBallAsServer", "SpawnPrefix", typeof(DungPatches));
			p.Postfix(typeof(NetworkPrefabSpawner), "SpawnDungBallAsServer", "SpawnPostfix", typeof(DungPatches));
			p.Prefix(typeof(DungBall), "IncrementSize_ServerRpc", "IncrementSizePrefix", typeof(DungPatches));
		}

		public static void ResetFlags()
		{
			_inBunny = false;
			_inStartingBalls = false;
			_spawningExtras = false;
			_kickoffSpawn = false;
		}

		public static bool BunnySpawnPrefix(BunnySpawner __instance)
		{
			RuleSet active = Session.Active;
			if (!Session.HostRules)
			{
				return true;
			}
			if (active.BunniesEnabled == false)
			{
				return false;
			}
			int? bunnyInterval = active.BunnyInterval;
			if (bunnyInterval.HasValue)
			{
				int valueOrDefault = bunnyInterval.GetValueOrDefault();
				__instance.spawnInterval = valueOrDefault;
			}
			bunnyInterval = active.BunnyIntervalSuddenDeath;
			if (bunnyInterval.HasValue)
			{
				int valueOrDefault2 = bunnyInterval.GetValueOrDefault();
				__instance.spawnIntervalSuddenDeath = valueOrDefault2;
			}
			return true;
		}

		public static void BunnyUpdatePrefix()
		{
			_inBunny = true;
		}

		public static void BunnyUpdatePostfix()
		{
			_inBunny = false;
		}

		public static bool StartingPrefix(MatchStateController __instance, TeamType team)
		{
			//IL_0052: 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)
			_inStartingBalls = true;
			if (!Session.HostRules)
			{
				return true;
			}
			if (Session.Active.StartingBallsPerTeam == 0)
			{
				return false;
			}
			int? singleStartingBall = Session.Active.SingleStartingBall;
			if (singleStartingBall.HasValue)
			{
				int valueOrDefault = singleStartingBall.GetValueOrDefault();
				if (valueOrDefault > 0)
				{
					return team == SingleBallTeam(__instance, valueOrDefault);
				}
			}
			return true;
		}

		private static TeamType SingleBallTeam(MatchStateController match, int mode)
		{
			//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_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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_000c: 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_006f: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Invalid comparison between Unknown and I4
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (_singleBallFrame == Time.frameCount)
			{
				return _singleBallTeam;
			}
			_singleBallFrame = Time.frameCount;
			bool flag = _singleBallMatch != ((Il2CppObjectBase)match).Pointer;
			_singleBallMatch = ((Il2CppObjectBase)match).Pointer;
			TeamType singleBallTeam = _singleBallTeam;
			TeamType lastScoringTeam = match.LastScoringTeam;
			bool flag2 = lastScoringTeam - 1 <= 1;
			TeamType singleBallTeam2 = (TeamType)((!flag2) ? ((Random.value < 0.5f) ? 1 : 2) : ((int)MatchStateController.GetOppositeTeam(match.LastScoringTeam)));
			if (flag)
			{
				_singleBallTeam = (TeamType)0;
			}
			else
			{
				flag2 = mode == 1;
				if (flag2)
				{
					bool flag3 = singleBallTeam - 1 <= 1;
					flag2 = flag3;
				}
				if (flag2)
				{
					_singleBallTeam = MatchStateController.GetOppositeTeam(singleBallTeam);
				}
				else
				{
					_singleBallTeam = singleBallTeam2;
				}
			}
			Mod.Log.Msg($"[dung] single starting ball: {(((int)_singleBallTeam == 0) ? "neutral spot" : ((object)Unsafe.As<TeamType, TeamType>(ref _singleBallTeam)/*cast due to .constrained prefix*/).ToString())} (mode {mode})");
			return _singleBallTeam;
		}

		private static int StartingSize()
		{
			RuleSet active = Session.Active;
			if (active.StartFullGrown == true)
			{
				return CurrentMaxSize();
			}
			return active.StartingBallSize ?? 1;
		}

		private static Vector3 NeutralSpot(MatchStateController match, int size)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MapInitializer mapInitializer = match.MapInitializer;
				Vector3? val = ((mapInitializer != null) ? new Vector3?(mapInitializer.GetSuddenDeathStartingBallSpawnPoint()) : ((Vector3?)null));
				if (val.HasValue && val.Value != Vector3.zero)
				{
					return val.Value;
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[dung] neutral spot lookup failed: " + ex.Message);
			}
			return (match.GetGoalPosition((TeamType)1) + match.GetGoalPosition((TeamType)2)) * 0.5f + Vector3.up * (2f + ScaleFor(size) * 0.5f);
		}

		private static void SpawnNeutral(MatchStateController match, int size, string what)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = NeutralSpot(match, size);
				_spawningExtras = true;
				_kickoffSpawn = true;
				NetworkPrefabSpawner.Instance.SpawnDungBallAsServer(val, Vector3.zero, size, 0uL, 0f, 0f, 0f);
				Mod.Log.Msg($"[dung] {what} size {size} at {val}");
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[dung] " + what + " failed: " + ex.Message);
			}
			finally
			{
				_spawningExtras = false;
				_kickoffSpawn = false;
			}
		}

		public static void StartingPostfix(MatchStateController __instance)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			_inStartingBalls = false;
			if (!Session.HostRules || _centerBallFrame == Time.frameCount)
			{
				return;
			}
			_centerBallFrame = Time.frameCount;
			RuleSet active = Session.Active;
			int? singleStartingBall = active.SingleStartingBall;
			if (singleStartingBall.HasValue)
			{
				int valueOrDefault = singleStartingBall.GetValueOrDefault();
				if (valueOrDefault > 0 && (int)_singleBallTeam == 0 && _singleBallFrame == Time.frameCount)
				{
					SpawnNeutral(__instance, StartingSize(), "neutral kickoff ball");
				}
			}
			singleStartingBall = active.CenterBallSize;
			if (singleStartingBall.HasValue)
			{
				int valueOrDefault2 = singleStartingBall.GetValueOrDefault();
				if (valueOrDefault2 > 0)
				{
					SpawnNeutral(__instance, valueOrDefault2, "center ball");
				}
			}
		}

		public static void SpawnPrefix(ref int size)
		{
			if (!Session.HostRules || _spawningExtras)
			{
				return;
			}
			RuleSet active = Session.Active;
			if (_inBunny)
			{
				int? dropSize = active.DropSize;
				if (dropSize.HasValue)
				{
					int valueOrDefault = dropSize.GetValueOrDefault();
					size = valueOrDefault;
					return;
				}
			}
			if (_inStartingBalls && active.StartFullGrown == true)
			{
				size = CurrentMaxSize();
			}
			else if (_inStartingBalls)
			{
				int? dropSize = active.StartingBallSize;
				if (dropSize.HasValue)
				{
					int valueOrDefault2 = dropSize.GetValueOrDefault();
					size = valueOrDefault2;
				}
			}
		}

		public static void SpawnPostfix(NetworkPrefabSpawner __instance, DungBall __result, Vector3 pos, Vector3 force, int size, ulong ownerClientId)
		{
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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)
			if (!Session.HostRules)
			{
				return;
			}
			RuleSet active = Session.Active;
			if ((_inStartingBalls || _kickoffSpawn) && active.FreezeKickoffBall == true && (Object)(object)__result != (Object)null)
			{
				KickoffFreeze.Freeze(__result, (_spawningExtras && _inStartingBalls) ? 1.5f : 0f);
			}
			if (_spawningExtras)
			{
				return;
			}
			int num = (_inBunny ? ((active.DungPerDrop ?? 1) - 1) : (_inStartingBalls ? ((active.StartingBallsPerTeam ?? 1) - 1) : 0));
			if (num <= 0)
			{
				return;
			}
			_spawningExtras = true;
			try
			{
				float num2 = ScaleFor(size) * 1.3f + 1f;
				Vector3 val = default(Vector3);
				for (int i = 0; i < num; i++)
				{
					float num3 = (float)(i + 1) * (float)Math.PI * 2f / (float)(num + 1) + Random.Range(-0.3f, 0.3f);
					((Vector3)(ref val))..ctor(Mathf.Cos(num3), 0f, Mathf.Sin(num3));
					Vector3 val2 = force + val * Random.Range(6f, 12f) + Vector3.up * 4f;
					__instance.SpawnDungBallAsServer(pos + val * num2, val2, size, ownerClientId, 0f, 1.5f, 0f);
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[dung] extra spawn failed: " + ex.Message);
			}
			finally
			{
				_spawningExtras = false;
			}
		}

		public static void IncrementSizePrefix(DungBall __instance, ref int increment)
		{
			if (Session.HostRules && Session.Active.IndestructibleDung == true && increment > 0)
			{
				increment = Math.Max(0, Math.Min(increment, CurrentMaxSize() - __instance.Size));
			}
		}

		private static int CurrentMaxSize()
		{
			int? num = Session.Active?.DungMaxSize;
			if (!num.HasValue)
			{
				DungBallDataSO data = Data;
				if (data == null)
				{
					return 5;
				}
				return data.MaxSize;
			}
			return num.GetValueOrDefault();
		}

		private static float ScaleFor(int size)
		{
			DungBallDataSO data = Data;
			if ((Object)(object)data == (Object)null)
			{
				return 1.5f + (float)size;
			}
			int num = Math.Max(2, CurrentMaxSize());
			return Mathf.Lerp(data.MinLocalScale, data.MaxLocalScale, Mathf.Clamp01(((float)size - 1f) / ((float)num - 1f)));
		}
	}
	public static class KickoffFreeze
	{
		private sealed class Entry
		{
			public DungBall Ball;

			public Rigidbody Body;

			public RigidbodyConstraints Original;

			public float ApplyAt;

			public bool Applied;
		}

		private const RigidbodyConstraints Lock = (RigidbodyConstraints)122;

		private static readonly Dictionary<IntPtr, Entry> Balls = new Dictionary<IntPtr, Entry>();

		public static void Register(Patcher p)
		{
			string[] array = new string[8] { "TryTakePossession_ServerRpc", "AddForceAndTryChangeOwnership_ServerRpc", "ChangeOwnership_ServerRpc", "ReportPlayerForceTouch_ServerRpc", "TrySetLastTouchedPlayers", "AddForce", "IRigidbodyForceRpcTarget_TryApplyForce", "OnReleaseCalled_ServerRpc" };
			foreach (string method in array)
			{
				p.Prefix(typeof(DungBall), method, "TouchedPrefix", typeof(KickoffFreeze));
			}
			p.Prefix(typeof(DungBall), "OnCollisionEnter", "CollisionPrefix", typeof(KickoffFreeze));
		}

		public static void Freeze(DungBall ball, float delay)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Rigidbody val = ((Component)ball).GetComponent<Rigidbody>() ?? ((Component)ball).GetComponentInChildren<Rigidbody>();
				if (!((Object)(object)val == (Object)null))
				{
					Balls[((Il2CppObjectBase)ball).Pointer] = new Entry
					{
						Ball = ball,
						Body = val,
						Original = val.constraints,
						ApplyAt = Time.time + delay
					};
				}
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[kickoff] freeze failed: " + ex.Message);
			}
		}

		public static void Tick()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if (Balls.Count == 0)
			{
				return;
			}
			List<IntPtr> list = null;
			foreach (var (item, entry2) in Balls)
			{
				if ((Object)(object)entry2.Ball == (Object)null || ((Il2CppObjectBase)entry2.Ball).WasCollected || (Object)(object)entry2.Body == (Object)null || ((Il2CppObjectBase)entry2.Body).WasCollected)
				{
					(list ?? (list = new List<IntPtr>())).Add(item);
				}
				else if (!entry2.Applied && !(Time.time < entry2.ApplyAt))
				{
					try
					{
						Vector3 linearVelocity = entry2.Body.linearVelocity;
						entry2.Body.linearVelocity = new Vector3(0f, linearVelocity.y, 0f);
						entry2.Body.angularVelocity = Vector3.zero;
						entry2.Body.constraints = (RigidbodyConstraints)(entry2.Original | 0x7A);
						entry2.Applied = true;
					}
					catch
					{
						(list ?? (list = new List<IntPtr>())).Add(item);
					}
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (IntPtr item2 in list)
			{
				Balls.Remove(item2);
			}
		}

		public static void Clear()
		{
			Balls.Clear();
		}

		private static void Release(DungBall ball, string how)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ball == (Object)null || !Balls.Remove(((Il2CppObjectBase)ball).Pointer, out var value))
			{
				return;
			}
			try
			{
				if ((Object)(object)value.Body != (Object)null && !((Il2CppObjectBase)value.Body).WasCollected)
				{
					value.Body.constraints = value.Original;
				}
			}
			catch
			{
			}
			Mod.Log.Msg("[kickoff] ball released (" + how + ")");
		}

		public static void TouchedPrefix(DungBall __instance)
		{
			if (Balls.Count > 0)
			{
				Release(__instance, "player action");
			}
		}

		public static void CollisionPrefix(DungBall __instance, Collision collision)
		{
			if (Balls.Count == 0 || !Balls.ContainsKey(((Il2CppObjectBase)__instance).Pointer) || collision == null)
			{
				return;
			}
			try
			{
				Rigidbody rigidbody = collision.rigidbody;
				GameObject val = (((Object)(object)rigidbody != (Object)null) ? ((Component)rigidbody).gameObject : collision.gameObject);
				if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponentInParent<BeetleActor>() != (Object)null)
				{
					Release(__instance, "bumped by a beetle");
				}
			}
			catch
			{
			}
		}
	}
	public static class MatchPatches
	{
		private static IntPtr _timerSetFor;

		public static void Register(Patcher p)
		{
			p.Prefix(typeof(MatchStateController), "InitializeMatch", "InitializeMatchPrefix", typeof(MatchPatches));
			p.Prefix(typeof(MatchStateController), "StartMatchTimerCountdown", "StartTimerPrefix", typeof(MatchPatches));
			p.Prefix(typeof(MatchStateController), "BallEnteredGoalHandler", "GoalPrefix", typeof(MatchPatches));
		}

		public static void InitializeMatchPrefix(MatchStateController __instance)
		{
			if (Session.HostRules)
			{
				RuleSet active = Session.Active;
				int? goalsToWin = active.GoalsToWin;
				if (goalsToWin.HasValue)
				{
					int valueOrDefault = goalsToWin.GetValueOrDefault();
					__instance.goalsRequired = valueOrDefault;
				}
				float? resetAfterGoalDelay = active.ResetAfterGoalDelay;
				if (resetAfterGoalDelay.HasValue)
				{
					float valueOrDefault2 = resetAfterGoalDelay.GetValueOrDefault();
					__instance.resetAfterGoalDelay = valueOrDefault2;
				}
				Mod.Log.Msg($"[match] start: goalsRequired={__instance.goalsRequired} resetDelay={__instance.resetAfterGoalDelay}");
			}
		}

		public static void StartTimerPrefix(MatchStateController __instance)
		{
			if (!Session.HostRules)
			{
				return;
			}
			int? matchSeconds = Session.Active.MatchSeconds;
			if (matchSeconds.HasValue)
			{
				int valueOrDefault = matchSeconds.GetValueOrDefault();
				if (!(_timerSetFor == ((Il2CppObjectBase)__instance).Pointer))
				{
					_timerSetFor = ((Il2CppObjectBase)__instance).Pointer;
					__instance.MatchSecondsRemaining.Value = valueOrDefault;
					Mod.Log.Msg($"[match] timer set to {valueOrDefault}s");
				}
			}
		}

		public static void GoalPrefix(ref int points)
		{
			if (Session.HostRules)
			{
				int? pointsPerGoal = Session.Active.PointsPerGoal;
				if (pointsPerGoal.HasValue)
				{
					int valueOrDefault = pointsPerGoal.GetValueOrDefault();
					points = valueOrDefault;
				}
			}
		}
	}
	public sealed class WallLayout
	{
		public const float Infinite = 1000f;

		private const float VisibleGlass = 30f;

		private const float FadedGlass = 80f;

		public static readonly string Folder = Path.Combine(MelonEnvironment.UserDataDirectory, "MatchRules", "Walls");

		private static readonly JsonSerializerOptions Json = new JsonSerializerOptions
		{
			WriteIndented = true
		};

		private const float Thickness = 2f;

		private static PhysicsMaterial _slippery;

		private static int? _nonWalkableLayer;

		private static bool _nonWalkableSearched;

		public string Scene { get; set; } = "";

		public int Mirror { get; set; } = 1;

		public float Height { get; set; } = 1000f;

		public List<List<float[]>> Lines { get; set; } = new List<List<float[]>>();

		public bool IsEmpty
		{
			get
			{
				foreach (List<float[]> line in Lines)
				{
					if (line.Count >= 2)
					{
						return false;
					}
				}
				return true;
			}
		}

		private static PhysicsMaterial Slippery
		{
			get
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: 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_0041: 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_0058: Expected O, but got Unknown
				if ((Object)(object)_slippery != (Object)null && !((Il2CppObjectBase)_slippery).WasCollected)
				{
					return _slippery;
				}
				_slippery = new PhysicsMaterial
				{
					dynamicFriction = 0f,
					staticFriction = 0f,
					frictionCombine = (PhysicsMaterialCombine)2,
					bounciness = 0f,
					bounceCombine = (PhysicsMaterialCombine)0
				};
				((Object)_slippery).hideFlags = (HideFlags)32;
				return _slippery;
			}
		}

		public static bool IsInfinite(float height)
		{
			return height >= 1000f;
		}

		public static string HeightText(float height)
		{
			if (!IsInfinite(height))
			{
				return $"{height:0}m";
			}
			return "Infinite";
		}

		public static string PathFor(string scene)
		{
			return Path.Combine(Folder, scene + ".json");
		}

		public static WallLayout Load(string scene)
		{
			try
			{
				string path = PathFor(scene);
				if (File.Exists(path))
				{
					return FromJson(File.ReadAllText(path));
				}
				return BuiltIn(scene);
			}
			catch (Exception ex)
			{
				Mod.Log.Warning("[walls] could not read layout for " + scene + ": " + ex.Message);
				return null;
			}
		}

		private static WallLayout BuiltIn(string scene)
		{
			using Stream stream = typeof(WallLayout).Assembly.GetManifestResourceStream("Walls." + scene + ".json");
			if (stream == null)
			{
				return null;
			}
			using StreamReader streamReader = new StreamReader(stream);
			return FromJson(streamReader.ReadToEnd());
		}

		public void Save()
		{
			Directory.CreateDirectory(Folder);
			File.WriteAllText(PathFor(Scene), ToJson(indented: true));
		}

		public void Delete()
		{
			string path = PathFor(Scene);
			if (File.Exists(path))
			{
				File.Delete(path);
			}
		}

		public string ToJson(bool indented = false)
		{
			return JsonSerializer.Serialize(this, indented ? Json : new JsonSerializerOptions());
		}

		public static WallLayout FromJson(string json)
		{
			if (!string.IsNullOrWhiteSpace(json))
			{
				return JsonSerializer.Deserialize<WallLayout>(json);
			}
			return null;
		}

		public static float[] P(Vector3 v)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			return new float[3]
			{
				(float)Math.Round(v.x, 2),
				(float)Math.Round(v.y, 2),
				(float)Math.Round(v.z, 2)
			};
		}

		public static Vector3 V(float[] p)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(p[0], p[1], p[2]);
		}

		public List<(Vector3 a, Vector3 b)> Segments(MatchStateController match)
		{
			//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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_0077: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			List<(Vector3, Vector3)> list = new List<(Vector3, Vector3)>();
			Func<Vector3, Vector3>[] array = new Func<Vector3, Vector3>[1]
			{
				(Vector3 p) => p
			};
			Vector3 c;
			Vector3 axis;
			Vector3 perp;
			if (Mirror > 0 && (Object)(object)match != (Object)null)
			{
				Vector3 goalPosition = match.GetGoalPosition((TeamType)1);
				Vector3 goalPosition2 = match.GetGoalPosition((TeamType)2);
				c = (goalPosition + goalPosition2) * 0.5f;
				axis = goalPosition2 - goalPosition;
				axis.y = 0f;
				((Vector3)(ref axis)).Normalize();
				perp = new Vector3(0f - axis.z, 0f, axis.x);
				array = ((Mirror != 1) ? new Func<Vector3, Vector3>[4]
				{
					(Vector3 p) => p,
					(Vector3 p) => Flip(p, 1f, -1f),
					(Vector3 p) => Flip(p, -1f, 1f),
					(Vector3 p) => Flip(p, -1f, -1f)
				} : new Func<Vector3, Vector3>[2]
				{
					(Vector3 p) => p,
					(Vector3 p) => Flip(p, 1f, -1f)
				});
			}
			foreach (List<float[]> line in Lines)
			{
				for (int num = 0; num + 1 < line.Count; num++)
				{
					Func<Vector3, Vector3>[] array2 = array;
					foreach (Func<Vector3, Vector3> func in array2)
					{
						list.Add((func(V(line[num])), func(V(line[num + 1]))));
					}
				}
			}
			return list;
			Vector3 Flip(Vector3 p, float sa, float sp)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: 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_0032: 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_0039: 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_004a: Unknown result type (might be due to invalid IL or missing references)
				//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_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = p - c;
				return c + axis * (Vector3.Dot(val, axis) * sa) + perp * (Vector3.Dot(val, perp) * sp) + Vector3.up * val.y;
			}
		}

		public static void AddWall(Transform root, Vector3 a, Vector3 b, float height, int layer, Material glass, Material rim, Material faint, bool collide = true, PhysicsMaterial surface = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_002b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0069: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = b - a;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.2f)
			{
				return;
			}
			float num = Mathf.Min(a.y, b.y);
			float num2 = Mathf.Max(a.y, b.y);
			bool flag = IsInfinite(height);
			float bottom = (flag ? (num - 1000f) : (num - 3f));
			Vector3 mid = (a + b) * 0.5f;
			Quaternion rot = Quaternion.LookRotation(val / magnitude, Vector3.up);
			float length = magnitude + 1f;
			if (collide)
			{
				GameObject val2 = new GameObject("WallCollider")
				{
					layer = layer
				};
				val2.transform.SetParent(root, false);
				Place(val2.transform, mid, rot, bottom, num2 + (flag ? 1000f : height), 2f, length);
				BoxCollider val3 = val2.AddComponent<BoxCollider>();
				if ((Object)(object)surface != (Object)null)
				{
					((Collider)val3).sharedMaterial = surface;
				}
			}
			if (flag)
			{
				Panel(root, "GlassFadeDown", mid, rot, num - 80f, num - 30f, 2f, length, faint);
				Panel(root, "Glass", mid, rot, num - 30f, num2 + 30f, 2f, length, glass);
				Panel(root, "GlassFadeUp", mid, rot, num2 + 30f, num2 + 80f, 2f, length, faint);
			}
			else
			{
				Panel(root, "Glass", mid, rot, bottom, num2 + height, 2f, length, glass);
				Panel(root, "Rim", mid, rot, num2 + height - 0.15f, num2 + height + 0.15f, 2.1f, length, rim);
			}
		}

		private static void Place(Transform t, Vector3 mid, Quaternion rot, float bottom, float top, float thickness, float length)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			t.position = new Vector3(mid.x, (bottom + top) * 0.5f, mid.z);
			t.rotation = rot;
			t.localScale = new Vector3(thickness, top - bottom, length);
		}

		private static void Panel(Transform root, string name, Vector3 mid, Quaternion rot, float bottom, float top, float thickness, float length, Material mat)
		{
			//IL_0036: 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)
			if (!((Object)(object)mat == (Object)null))
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
				((Object)obj).name = name;
				Object.Destroy((Object)(object)obj.GetComponent<Collider>());
				obj.transform.SetParent(root, false);
				Place(obj.transform, mid, rot, bottom, top, thickness, length);
				Style(obj, mat);
			}
		}

		public static void Style(GameObject go, Material mat)
		{
			MeshRenderer component = go.GetComponent<MeshRenderer>();
			if (!((Object)(object)component == (Object)null))
			{
				if ((Object)(object)mat == (Object)null)
				{
					((Renderer)component).enabled = false;
					return;
				}
				((Renderer)component).sharedMaterial = mat;
				((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)component).receiveShadows = false;
			}
		}

		public static Material MakeMaterial(Color color)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0045: Unknown resul