using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FMOD;
using FMOD.Studio;
using FMODUnity;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("GameAssembly")]
[assembly: IgnoresAccessChecksTo("SharedAssembly")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.BETCGaming.BallSwapItem")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+e2919cd6113bc7dbe8ada3ebbffb6ea78be3d52a")]
[assembly: AssemblyProduct("com.github.BETCGaming.BallSwapItem")]
[assembly: AssemblyTitle("BallSwapItem")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BepInEx
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
[Embedded]
internal sealed class BepInAutoPluginAttribute : Attribute
{
public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace BepInEx.Preloader.Core.Patching
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
[Embedded]
internal sealed class PatcherAutoPluginAttribute : Attribute
{
public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace Microsoft.CodeAnalysis
{
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace BallSwapItem
{
internal static class MirrorSerializers
{
public static void Register()
{
Writer<SwitcherooRequestMessage>.write = delegate(NetworkWriter writer, SwitcherooRequestMessage message)
{
writer.Write<uint>(message.Token);
};
Reader<SwitcherooRequestMessage>.read = (NetworkReader reader) => new SwitcherooRequestMessage
{
Token = reader.Read<uint>()
};
Writer<SwitcherooHelloMessage>.write = delegate
{
};
Reader<SwitcherooHelloMessage>.read = (NetworkReader _) => default(SwitcherooHelloMessage);
Writer<SwitcherooArmedMessage>.write = delegate(NetworkWriter writer, SwitcherooArmedMessage message)
{
writer.Write<float>(message.WindUpSeconds);
writer.Write<string>(message.UserName);
};
Reader<SwitcherooArmedMessage>.read = (NetworkReader reader) => new SwitcherooArmedMessage
{
WindUpSeconds = reader.Read<float>(),
UserName = reader.Read<string>()
};
Writer<SwitcherooResultMessage>.write = delegate(NetworkWriter writer, SwitcherooResultMessage message)
{
writer.Write<int>(message.SwappedCount);
};
Reader<SwitcherooResultMessage>.read = (NetworkReader reader) => new SwitcherooResultMessage
{
SwappedCount = reader.Read<int>()
};
Writer<SwitcherooUseReplyMessage>.write = delegate(NetworkWriter writer, SwitcherooUseReplyMessage message)
{
writer.Write<bool>(message.Accepted);
writer.Write<byte>(message.Reason);
writer.Write<uint>(message.Token);
};
Reader<SwitcherooUseReplyMessage>.read = (NetworkReader reader) => new SwitcherooUseReplyMessage
{
Accepted = reader.Read<bool>(),
Reason = reader.Read<byte>(),
Token = reader.Read<uint>()
};
Writer<SwitcherooLockMessage>.write = delegate(NetworkWriter writer, SwitcherooLockMessage message)
{
writer.Write<bool>(message.Locked);
};
Reader<SwitcherooLockMessage>.read = (NetworkReader reader) => new SwitcherooLockMessage
{
Locked = reader.Read<bool>()
};
Plugin.Log.LogInfo((object)"Registered Switcheroo message serializers.");
}
}
internal static class ModGate
{
private const float GraceSeconds = 10f;
private static readonly Dictionary<int, float> FirstSeen = new Dictionary<int, float>();
private static readonly HashSet<int> Modded = new HashSet<int>();
public static void Reset()
{
FirstSeen.Clear();
Modded.Clear();
}
public static void MarkModded(NetworkConnectionToClient conn)
{
if (conn != null && Modded.Add(conn.connectionId))
{
Plugin.Log.LogInfo((object)$"Connection {conn.connectionId} has BallSwapItem installed.");
}
}
public static void Tick()
{
if (!NetworkServer.active || !Plugin.BlockUnmodded.Value)
{
return;
}
float time = Time.time;
List<NetworkConnectionToClient> list = null;
foreach (NetworkConnectionToClient value2 in NetworkServer.connections.Values)
{
if (value2 != null && !Modded.Contains(value2.connectionId) && (object)value2 != NetworkServer.localConnection && ((NetworkConnection)value2).isAuthenticated)
{
if (!FirstSeen.TryGetValue(value2.connectionId, out var value))
{
FirstSeen[value2.connectionId] = time;
}
else if (time - value >= 10f)
{
(list ?? (list = new List<NetworkConnectionToClient>())).Add(value2);
}
}
}
if (list == null)
{
return;
}
foreach (NetworkConnectionToClient item in list)
{
Plugin.Log.LogWarning((object)($"Disconnecting connection {item.connectionId}: BallSwapItem is not installed. " + "Set BlockUnmodded to false to allow unmodded players (the Switcheroo will then be withheld)."));
FirstSeen.Remove(item.connectionId);
((NetworkConnection)item).Disconnect();
}
}
}
internal sealed class ModRunner : MonoBehaviour
{
internal static ModRunner? Instance { get; private set; }
private void Awake()
{
Instance = this;
}
private void Start()
{
SwitcherooAudio.Load();
}
private void Update()
{
SwitcherooNetwork.EnsureHandlers();
SwitcherooNetwork.TrackHeldItems();
SwitcherooUi.Tick();
SwitcherooLocalization.EnsureApplied();
SwitcherooThrownItem.EnsureRegistered();
ModGate.Tick();
if (Plugin.DebugHotkeys.Value && Keyboard.current != null)
{
if (((ButtonControl)Keyboard.current[(Key)102]).wasPressedThisFrame)
{
GiveSwitcheroo();
}
if (((ButtonControl)Keyboard.current[(Key)103]).wasPressedThisFrame)
{
ForceSwap();
}
}
}
private static void GiveSwitcheroo()
{
if (!NetworkServer.active)
{
Plugin.Log.LogWarning((object)"F9 ignored: only the host can hand out items directly.");
return;
}
PlayerInventory localPlayerInventory = GameManager.LocalPlayerInventory;
if ((Object)(object)localPlayerInventory == (Object)null)
{
Plugin.Log.LogWarning((object)"F9 ignored: no local player inventory yet.");
return;
}
bool flag = localPlayerInventory.ServerTryAddItem((ItemType)200, 1);
Plugin.Log.LogInfo((object)(flag ? "Gave the local player a Switcheroo." : "Could not give a Switcheroo (inventory full?)."));
}
private static void ForceSwap()
{
if (!NetworkServer.active)
{
Plugin.Log.LogWarning((object)"F10 ignored: only the host can run a swap.");
return;
}
string failureReason;
int count = SwapService.TrySwap(out failureReason).Count;
Plugin.Log.LogInfo((object)((count > 0) ? $"Swapped {count} balls." : ("Swap did not run: " + failureReason + ".")));
}
}
[BepInPlugin("com.github.BETCGaming.BallSwapItem", "BallSwapItem", "1.0.1")]
public class Plugin : BaseUnityPlugin
{
public const string Id = "com.github.BETCGaming.BallSwapItem";
internal static ManualLogSource Log { get; private set; }
internal static ConfigEntry<bool> Enabled { get; private set; }
internal static ConfigEntry<float> WindUpSeconds { get; private set; }
internal static ConfigEntry<bool> BlockUnmodded { get; private set; }
internal static ConfigEntry<float> SoundVolume { get; private set; }
internal static ConfigEntry<float> DenialVolume { get; private set; }
internal static ConfigEntry<bool> DebugHotkeys { get; private set; }
internal static ConfigEntry<bool> VerboseLogging { get; private set; }
public static string Name => "BallSwapItem";
public static string Version => "1.0.1";
private void Awake()
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Expected O, but got Unknown
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Expected O, but got Unknown
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Expected O, but got Unknown
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the Switcheroo item. When off, the item is not registered and never spawns.");
WindUpSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "WindUpSeconds", 3f, new ConfigDescription("Seconds between using the Switcheroo and the swap landing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
BlockUnmodded = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "BlockUnmodded", true, "Disconnect players who do not have this mod installed. They cannot handle the Switcheroo if the host hands them one. Host setting; ignored on clients.");
SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SoundVolume", 0.8f, new ConfigDescription("Volume of the sound played once a swap resolves. This plays outside the game's FMOD mix, so the in-game volume sliders do not affect it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
DenialVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DenialVolume", 0.25f, new ConfigDescription("Volume of the sound played when a Switcheroo use is refused because the swap has already been used this round.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
DebugHotkeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugHotkeys", false, "F9 gives the local player a Switcheroo, F10 forces a swap. Host only, for testing.");
MirrorSerializers.Register();
SwitcherooLocalization.Initialize();
VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Log every step of using the item and running a swap. For diagnosing a stuck or repeating use.");
new Harmony("com.github.BETCGaming.BallSwapItem").PatchAll();
((Component)this).gameObject.AddComponent<ModRunner>();
Log.LogInfo((object)("Plugin " + Name + " v" + Version + " is loaded!"));
}
}
internal static class SwapService
{
private static readonly Random Rng = new Random();
private static readonly Action<GolfBall> UpdateNameTag = AccessTools.MethodDelegate<Action<GolfBall>>(AccessTools.Method(typeof(GolfBall), "UpdateNameTag", (Type[])null, (Type[])null), (object)null, true);
public static List<PlayerGolfer> TrySwap(out string failureReason)
{
failureReason = string.Empty;
if (!NetworkServer.active)
{
failureReason = "swap attempted off the server";
return new List<PlayerGolfer>();
}
List<PlayerGolfer> list = CollectEligiblePlayers();
if (list.Count < 2)
{
failureReason = $"only {list.Count} eligible ball(s) in play";
return new List<PlayerGolfer>();
}
GolfBall[] array = (GolfBall[])(object)new GolfBall[list.Count];
for (int i = 0; i < list.Count; i++)
{
array[i] = list[i].NetworkownBall;
}
Derange(array);
for (int j = 0; j < list.Count; j++)
{
list[j].NetworkownBall = array[j];
array[j].Networkowner = list[j];
UpdateNameTag(array[j]);
}
return list;
}
public static int CountEligible()
{
return CollectEligiblePlayers().Count;
}
private static List<PlayerGolfer> CollectEligiblePlayers()
{
//IL_0033: 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)
List<PlayerGolfer> list = new List<PlayerGolfer>();
foreach (PlayerGolfer matchParticipant in CourseManager.MatchParticipants)
{
if (!((Object)(object)matchParticipant == (Object)null) && !((Object)(object)matchParticipant.NetworkownBall == (Object)null) && (int)matchParticipant.MatchResolution == 0)
{
GolfBall networkownBall = matchParticipant.NetworkownBall;
if (!networkownBall.isInHole && (int)networkownBall.OutOfBoundsReturnState == 0 && HasTeedOff(matchParticipant))
{
list.Add(matchParticipant);
}
}
}
return list;
}
private static bool HasTeedOff(PlayerGolfer golfer)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
PlayerInfo playerInfo = golfer.PlayerInfo;
if ((Object)(object)playerInfo == (Object)null)
{
return false;
}
PlayerState val = default(PlayerState);
if (CourseManager.TryGetPlayerState(playerInfo.PlayerId.Guid, ref val))
{
return val.matchStrokes > 0;
}
return false;
}
private static void Derange<T>(T[] items)
{
T[] array = (T[])items.Clone();
for (int i = 0; i < 100; i++)
{
for (int num = items.Length - 1; num > 0; num--)
{
int num2 = Rng.Next(num + 1);
int num3 = num;
int num4 = num2;
T val = items[num2];
T val2 = items[num];
items[num3] = val;
items[num4] = val2;
}
bool flag = false;
for (int j = 0; j < items.Length; j++)
{
if ((object)items[j] == (object)array[j])
{
flag = true;
break;
}
}
if (!flag)
{
return;
}
}
Array.Copy(array, items, array.Length);
T val3 = items[^1];
Array.Copy(array, 0, items, 1, array.Length - 1);
items[0] = val3;
}
}
internal static class Switcheroo
{
public const ItemType Type = (ItemType)200;
public const string DisplayName = "Switcheroo";
public const Rule OncePerHoleRule = (Rule)200;
internal static readonly Color DeviceColor = new Color(1f, 0.4117647f, 0.7058824f, 1f);
private const uint NetworkAssetId = 3047489537u;
private static ItemData? itemData;
private static bool failedOnce;
private static GameObject? prefabHolder;
private static GameObject PrefabHolder
{
get
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
if ((Object)(object)prefabHolder == (Object)null)
{
prefabHolder = new GameObject("BallSwapItemPrefabs");
prefabHolder.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)prefabHolder);
}
return prefabHolder;
}
}
public static void Register(ItemCollection collection)
{
if (!Plugin.Enabled.Value || failedOnce)
{
return;
}
try
{
if (itemData == null)
{
itemData = BuildItemData(collection);
}
if (itemData != null)
{
if (Array.IndexOf(collection.items, itemData) < 0)
{
ItemData[] array = collection.items;
Array.Resize(ref array, array.Length + 1);
array[^1] = itemData;
collection.items = array;
}
collection.allItemData[(ItemType)200] = itemData;
}
}
catch (Exception arg)
{
failedOnce = true;
Plugin.Log.LogError((object)$"Failed to register the Switcheroo item, it will not appear: {arg}");
}
}
private static ItemData? BuildItemData(ItemCollection collection)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
ItemData val = default(ItemData);
if (!collection.TryGetItemData((ItemType)10, ref val))
{
Plugin.Log.LogError((object)"Orbital Laser item data not found; cannot build the Switcheroo from it.");
return null;
}
if ((Object)(object)val.Prefab == (Object)null)
{
return null;
}
ItemData val2 = new ItemData();
FieldInfo[] fields = typeof(ItemData).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
fieldInfo.SetValue(val2, fieldInfo.GetValue(val));
}
val2.Type = (ItemType)200;
val2.Icon = BuildIcon();
val2.Prefab = BuildPrefab(val.Prefab);
val2.MaxUses = 1;
val2.NonAimUse = (ItemNonAimingUse)2;
val2.CanUsageAffectBalls = false;
val2.CanUsageAffectTeammateBalls = false;
val2.IsExplosive = false;
val2.CanBreakBreakableIce = false;
val2.CanHitProjectiles = false;
val2.HitInfoFeedMessageIcon = (InfoFeedIconType)25;
val2.name = null;
val2.Initialize();
Plugin.Log.LogInfo((object)$"Built Switcheroo item data as ItemType {200}.");
return val2;
}
private static GameObject BuildPrefab(GameObject donorPrefab)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
bool activeSelf = donorPrefab.activeSelf;
donorPrefab.SetActive(false);
GameObject val;
try
{
val = Object.Instantiate<GameObject>(donorPrefab);
}
finally
{
donorPrefab.SetActive(activeSelf);
}
((Object)val).name = "SwitcherooItem";
PhysicalItem val2 = default(PhysicalItem);
if (val.TryGetComponent<PhysicalItem>(ref val2))
{
val2.itemType = (ItemType)200;
}
else
{
Plugin.Log.LogWarning((object)"Switcheroo pickup has no PhysicalItem component.");
}
val.transform.SetParent(PrefabHolder.transform, false);
val.SetActive(true);
Recolour(val);
RegisterNetworkPrefab(val);
return val;
}
private static void RegisterNetworkPrefab(GameObject prefab)
{
NetworkIdentity val = default(NetworkIdentity);
if (!prefab.TryGetComponent<NetworkIdentity>(ref val))
{
Plugin.Log.LogWarning((object)"Switcheroo pickup has no NetworkIdentity; it will not spawn when dropped.");
return;
}
FieldInfo fieldInfo = AccessTools.Field(typeof(NetworkIdentity), "_assetId");
if ((object)fieldInfo == null)
{
Plugin.Log.LogWarning((object)"Mirror's assetId field was not found; dropped Switcheroos may appear as Orbital Lasers.");
return;
}
fieldInfo.SetValue(val, 0u);
NetworkClient.RegisterPrefab(prefab, 3047489537u);
Plugin.Log.LogInfo((object)$"Registered the Switcheroo pickup as network asset {val.assetId}.");
}
public static void EnsureNetworkPrefabRegistered()
{
ItemData? obj = itemData;
if (!((Object)(object)((obj != null) ? obj.Prefab : null) == (Object)null))
{
NetworkClient.RegisterPrefab(itemData.Prefab, 3047489537u);
}
}
internal static void Recolour(GameObject target)
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
Renderer[] componentsInChildren = target.GetComponentsInChildren<Renderer>(true);
foreach (Renderer val in componentsInChildren)
{
Material[] materials = val.materials;
foreach (Material val2 in materials)
{
if (val2.HasProperty("_BaseColor"))
{
val2.SetColor("_BaseColor", DeviceColor);
}
if (val2.HasProperty("_Color"))
{
val2.SetColor("_Color", DeviceColor);
}
}
}
}
private static Sprite? BuildIcon()
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
//IL_009e: 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)
using Stream stream = typeof(Switcheroo).Assembly.GetManifestResourceStream("BallSwapItem.Assets.switcheroo-icon.png");
if (stream == null)
{
Plugin.Log.LogWarning((object)"Embedded Switcheroo icon missing; the item will show no icon.");
return null;
}
byte[] array = new byte[stream.Length];
stream.Read(array, 0, array.Length);
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
if (!ImageConversion.LoadImage(val, array))
{
Plugin.Log.LogWarning((object)"Switcheroo icon failed to decode; the item will show no icon.");
return null;
}
((Object)val).name = "SwitcherooIcon";
Object.DontDestroyOnLoad((Object)(object)val);
Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
((Object)val2).name = "SwitcherooIcon";
Object.DontDestroyOnLoad((Object)(object)val2);
return val2;
}
}
[HarmonyPatch(typeof(ItemCollection), "Initialize")]
internal static class ItemCollectionInitializePatch
{
private static void Postfix(ItemCollection __instance)
{
Switcheroo.Register(__instance);
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class ItemDataNamePatch
{
private static bool Prefix(ItemData __instance, ref string __result)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
if ((int)__instance.Type != 200)
{
return true;
}
__result = "Switcheroo";
return false;
}
}
internal static class SwitcherooAudio
{
private const string ResourceName = "BallSwapItem.Assets.bomboclat.mp3";
private static Sound sound;
private static bool loaded;
private static bool failed;
public static void Load()
{
EnsureSound();
}
public static void PlayDenial()
{
//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_000f: 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_0029: 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)
try
{
EventInstance val = RuntimeManager.CreateInstance(GameManager.AudioSettings.CosmeticsButtonSelectDisabled);
((EventInstance)(ref val)).setVolume(Mathf.Clamp01(Plugin.DenialVolume.Value));
((EventInstance)(ref val)).start();
((EventInstance)(ref val)).release();
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not play the denial sound: " + ex.Message));
}
}
public static void PlayAnticipation()
{
//IL_0005: 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_0012: Unknown result type (might be due to invalid IL or missing references)
try
{
RuntimeManager.PlayOneShot(GameManager.AudioSettings.OrbitalLaserAnticipationEvent, default(Vector3));
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not play the wind-up cue: " + ex.Message));
}
}
public static void PlayPayoff()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: 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_001d: 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_0026: 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_0056: 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)
if (EnsureSound())
{
System coreSystem = RuntimeManager.CoreSystem;
Channel val2 = default(Channel);
RESULT val = ((System)(ref coreSystem)).playSound(sound, default(ChannelGroup), false, ref val2);
if ((int)val != 0)
{
Plugin.Log.LogWarning((object)$"Could not play the swap sound: {val}");
}
else
{
((Channel)(ref val2)).setVolume(Mathf.Clamp01(Plugin.SoundVolume.Value));
}
}
}
private static bool EnsureSound()
{
//IL_0039: 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_0064: 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_007a: 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_008e: Unknown result type (might be due to invalid IL or missing references)
if (loaded)
{
return true;
}
if (failed)
{
return false;
}
try
{
if (!RuntimeManager.IsInitialized)
{
return false;
}
byte[] array = ReadResource();
if (array == null)
{
failed = true;
return false;
}
CREATESOUNDEXINFO val = new CREATESOUNDEXINFO
{
cbsize = Marshal.SizeOf(typeof(CREATESOUNDEXINFO)),
length = (uint)array.Length
};
System coreSystem = RuntimeManager.CoreSystem;
RESULT val2 = ((System)(ref coreSystem)).createSound(array, (MODE)2305, ref val, ref sound);
if ((int)val2 != 0)
{
failed = true;
Plugin.Log.LogWarning((object)$"Could not decode the swap sound, it will not play: {val2}");
return false;
}
loaded = true;
Plugin.Log.LogInfo((object)"Swap sound ready.");
return true;
}
catch (Exception ex)
{
failed = true;
Plugin.Log.LogWarning((object)("Could not prepare the swap sound, it will not play: " + ex.Message));
return false;
}
}
private static byte[]? ReadResource()
{
using Stream stream = typeof(SwitcherooAudio).Assembly.GetManifestResourceStream("BallSwapItem.Assets.bomboclat.mp3");
if (stream == null)
{
Plugin.Log.LogWarning((object)"Swap sound missing from the plugin; it will not play.");
return null;
}
using MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
internal static class SwitcherooEquipment
{
public const EquipmentType Type = (EquipmentType)200;
private static EquipmentSettings? settings;
private static bool failedOnce;
public static void EnsureRegistered()
{
if (SingletonBehaviour<EquipmentManager>.HasInstance)
{
EquipmentCollection equipmentCollection = SingletonBehaviour<EquipmentManager>.Instance.equipmentCollection;
if ((Object)(object)equipmentCollection != (Object)null)
{
Register(equipmentCollection);
}
}
}
public static void Register(EquipmentCollection collection)
{
if (!Plugin.Enabled.Value || failedOnce)
{
return;
}
try
{
if (settings == null)
{
settings = Build(collection);
}
if (settings != null)
{
if (Array.IndexOf(collection.equipment, settings) < 0)
{
EquipmentSettings[] array = collection.equipment;
Array.Resize(ref array, array.Length + 1);
array[^1] = settings;
collection.equipment = array;
}
collection.equipmentDictionary[(EquipmentType)200] = settings;
}
}
catch (Exception arg)
{
failedOnce = true;
Plugin.Log.LogError((object)$"Could not register the Switcheroo's held model: {arg}");
}
}
private static EquipmentSettings? Build(EquipmentCollection collection)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Expected O, but got Unknown
EquipmentSettings val = default(EquipmentSettings);
if (!collection.TryGetEquipmentSettings((EquipmentType)12, ref val) || (Object)(object)val.Prefab == (Object)null)
{
return null;
}
GameObject gameObject = ((Component)val.Prefab).gameObject;
bool activeSelf = gameObject.activeSelf;
gameObject.SetActive(false);
GameObject val2;
try
{
val2 = Object.Instantiate<GameObject>(gameObject);
}
finally
{
gameObject.SetActive(activeSelf);
}
((Object)val2).name = "SwitcherooModel";
Switcheroo.Recolour(val2);
GameObject val3 = new GameObject("SwitcherooEquipment");
val3.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)val3);
val2.transform.SetParent(val3.transform, false);
val2.SetActive(true);
val2.transform.localPosition = Vector3.zero;
val2.transform.localRotation = Quaternion.identity;
Equipment val4 = val3.AddComponent<Equipment>();
val4.Type = (EquipmentType)200;
Equipment val5 = default(Equipment);
if (val2.TryGetComponent<Equipment>(ref val5))
{
val5.Type = (EquipmentType)200;
}
EquipmentSettings val6 = new EquipmentSettings();
val6.Type = (EquipmentType)200;
val6.Prefab = val4;
Plugin.Log.LogInfo((object)$"Built the Switcheroo's held model as EquipmentType {200}.");
return val6;
}
}
[HarmonyPatch(typeof(EquipmentCollection), "Initialize")]
internal static class EquipmentCollectionInitializePatch
{
private static void Postfix(EquipmentCollection __instance)
{
SwitcherooEquipment.Register(__instance);
}
}
[HarmonyPatch(typeof(PlayerInventory), "LocalPlayerUpdateEquipmentSwitchers")]
internal static class EquipmentSwitcherPatch
{
private static readonly MethodInfo? CanHoldEquipment = FindCanHoldEquipment();
private static bool Prefix(PlayerInventory __instance)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Invalid comparison between Unknown and I4
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
if ((int)__instance.GetEffectivelyEquippedItem(false) != 200)
{
return true;
}
SwitcherooEquipment.EnsureRegistered();
if ((object)CanHoldEquipment == null)
{
return true;
}
bool flag = (bool)CanHoldEquipment.Invoke(__instance, null);
bool flag2 = !((Enum)__instance.thrownItem).HasFlag((Enum)(object)(ThrownItemHand)2);
__instance.PlayerInfo.RightHandEquipmentSwitcher.SetEquipment((EquipmentType)((flag && flag2) ? 200 : 0));
__instance.PlayerInfo.LeftHandEquipmentSwitcher.SetEquipment((EquipmentType)0);
return false;
}
private static MethodInfo? FindCanHoldEquipment()
{
MethodInfo methodInfo = AccessTools.GetDeclaredMethods(typeof(PlayerInventory)).FirstOrDefault((MethodInfo m) => m.Name.StartsWith("<LocalPlayerUpdateEquipmentSwitchers>g__CanHoldEquipment", StringComparison.Ordinal) && m.ReturnType == typeof(bool) && m.GetParameters().Length == 0);
if ((object)methodInfo == null)
{
Plugin.Log.LogWarning((object)"Could not find PlayerInventory's CanHoldEquipment; the Switcheroo will not show in hand.");
}
return methodInfo;
}
}
internal static class SwitcherooLocalization
{
private static bool applied;
public static void Initialize()
{
LocalizationManager.LanguageChanged += delegate
{
applied = false;
};
}
public static void EnsureApplied()
{
//IL_0016: 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)
if (applied)
{
return;
}
try
{
StringTable val = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase)?.GetTable(TableReference.op_Implicit(((object)(StringTable)1/*cast due to .constrained prefix*/).ToString()), (Locale)null);
if (!((Object)(object)val == (Object)null))
{
string text = $"ITEM_{200}";
((DetailedLocalizationTable<StringTableEntry>)(object)val).AddEntry(text, "Switcheroo");
applied = true;
Plugin.Log.LogInfo((object)("Registered the name 'Switcheroo' as " + text + "."));
}
}
catch (Exception ex)
{
applied = true;
Plugin.Log.LogWarning((object)("Could not name the Switcheroo, its name may show as a key: " + ex.Message));
}
}
}
[HarmonyPatch(typeof(PlayerAnimatorIo), "SetEquippedItem")]
internal static class AnimatorEquippedItemPatch
{
private static void Prefix(ref ItemType equippedItem)
{
if ((int)equippedItem == 200)
{
equippedItem = (ItemType)10;
}
}
}
internal enum SwapRequestState
{
None,
Waiting,
Accepted,
Denied
}
internal struct SwitcherooRequestMessage : NetworkMessage
{
public uint Token;
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
internal struct SwitcherooHelloMessage : NetworkMessage
{
}
internal struct SwitcherooArmedMessage : NetworkMessage
{
public float WindUpSeconds;
public string UserName;
}
internal enum SwitcherooDenialReason : byte
{
None,
SwapInProgress,
AlreadyUsedThisRound,
NotHolding,
TooSoon,
NotEnoughBalls
}
internal struct SwitcherooUseReplyMessage : NetworkMessage
{
public bool Accepted;
public byte Reason;
public uint Token;
}
internal struct SwitcherooResultMessage : NetworkMessage
{
public int SwappedCount;
}
internal struct SwitcherooLockMessage : NetworkMessage
{
public bool Locked;
}
internal static class SwitcherooNetwork
{
private const double MinSecondsBetweenRequests = 1.0;
private static readonly Dictionary<int, double> LastRequestPerConnection = new Dictionary<int, double>();
private const float BusyGraceSeconds = 1.5f;
public const float ReplyTimeoutSeconds = 2f;
private static double clientBusyUntil;
private static uint pendingToken;
private static bool serverLocked;
private static bool holeHookInstalled;
private static bool serverHandlerRegistered;
private static bool clientHandlerRegistered;
private static bool helloSent;
private static bool swapPending;
private const float HeldMemorySeconds = 5f;
private static readonly Dictionary<int, float> LastHeldSwitcheroo = new Dictionary<int, float>();
public static bool LockedThisRound { get; private set; }
public static bool SwapInProgress => Time.timeAsDouble < clientBusyUntil;
public static SwapRequestState RequestState { get; private set; } = SwapRequestState.None;
public static string DenialText { get; private set; } = "SWAP UNAVAILABLE";
public static void EnsureHandlers()
{
if (NetworkServer.active)
{
if (!serverHandlerRegistered)
{
NetworkServer.RegisterHandler<SwitcherooRequestMessage>((Action<NetworkConnectionToClient, SwitcherooRequestMessage>)OnServerRequest, true);
NetworkServer.RegisterHandler<SwitcherooHelloMessage>((Action<NetworkConnectionToClient, SwitcherooHelloMessage>)OnServerHello, false);
serverHandlerRegistered = true;
Plugin.Log.LogInfo((object)"Registered Switcheroo server handlers.");
}
}
else if (serverHandlerRegistered)
{
serverHandlerRegistered = false;
swapPending = false;
serverLocked = false;
LastRequestPerConnection.Clear();
LastHeldSwitcheroo.Clear();
ModGate.Reset();
}
if (NetworkClient.active)
{
if (!clientHandlerRegistered)
{
NetworkClient.RegisterHandler<SwitcherooArmedMessage>((Action<SwitcherooArmedMessage>)OnClientArmed, true);
NetworkClient.RegisterHandler<SwitcherooResultMessage>((Action<SwitcherooResultMessage>)OnClientResult, true);
NetworkClient.RegisterHandler<SwitcherooLockMessage>((Action<SwitcherooLockMessage>)OnClientLock, true);
NetworkClient.RegisterHandler<SwitcherooUseReplyMessage>((Action<SwitcherooUseReplyMessage>)OnClientUseReply, true);
clientHandlerRegistered = true;
Switcheroo.EnsureNetworkPrefabRegistered();
Plugin.Log.LogInfo((object)"Registered Switcheroo client handlers.");
}
if (!helloSent && NetworkClient.isConnected)
{
NetworkConnectionToServer connection = NetworkClient.connection;
if (connection != null && ((NetworkConnection)connection).isAuthenticated)
{
NetworkClient.Send<SwitcherooHelloMessage>(default(SwitcherooHelloMessage), 0);
helloSent = true;
}
}
}
else
{
clientHandlerRegistered = false;
helloSent = false;
LockedThisRound = false;
clientBusyUntil = 0.0;
RequestState = SwapRequestState.None;
}
if (!holeHookInstalled)
{
CourseManager.CurrentHoleGlobalIndexChanged += OnHoleChanged;
holeHookInstalled = true;
}
}
private static void OnHoleChanged()
{
LockedThisRound = false;
if (NetworkServer.active)
{
serverLocked = false;
NetworkServer.SendToAll<SwitcherooLockMessage>(new SwitcherooLockMessage
{
Locked = false
}, 0, false);
}
}
public static void RequestSwap()
{
if (!NetworkClient.active)
{
Plugin.Log.LogWarning((object)"Switcheroo used while not connected; ignoring.");
RequestState = SwapRequestState.Denied;
DenialText = "NOT CONNECTED";
}
else
{
RequestState = SwapRequestState.Waiting;
pendingToken++;
NetworkClient.Send<SwitcherooRequestMessage>(new SwitcherooRequestMessage
{
Token = pendingToken
}, 0);
}
}
public static void TimeOutRequest()
{
RequestState = SwapRequestState.Denied;
DenialText = "NO RESPONSE";
}
private static void OnClientUseReply(SwitcherooUseReplyMessage message)
{
if (message.Token == pendingToken && RequestState == SwapRequestState.Waiting)
{
if (message.Accepted)
{
RequestState = SwapRequestState.Accepted;
return;
}
SwitcherooDenialReason reason = (SwitcherooDenialReason)message.Reason;
RequestState = SwapRequestState.Denied;
DenialText = reason switch
{
SwitcherooDenialReason.SwapInProgress => "SWAP IN PROGRESS",
SwitcherooDenialReason.AlreadyUsedThisRound => "ONCE PER ROUND",
SwitcherooDenialReason.NotEnoughBalls => "NO BALLS TO SWAP",
SwitcherooDenialReason.NotHolding => "NO SWITCHEROO",
SwitcherooDenialReason.TooSoon => "TOO SOON",
_ => "SWAP UNAVAILABLE",
};
Trace.Log($"client: use denied by the host ({reason})");
}
}
private static void OnServerHello(NetworkConnectionToClient conn, SwitcherooHelloMessage message)
{
ModGate.MarkModded(conn);
((NetworkConnection)conn).Send<SwitcherooLockMessage>(new SwitcherooLockMessage
{
Locked = serverLocked
}, 0);
}
private static void OnServerRequest(NetworkConnectionToClient conn, SwitcherooRequestMessage message)
{
if (conn == null)
{
return;
}
double timeAsDouble = Time.timeAsDouble;
if (LastRequestPerConnection.TryGetValue(conn.connectionId, out var value) && timeAsDouble - value < 1.0)
{
Plugin.Log.LogWarning((object)$"Ignoring rapid Switcheroo request from connection {conn.connectionId}.");
Deny(conn, message.Token, SwitcherooDenialReason.TooSoon);
return;
}
LastRequestPerConnection[conn.connectionId] = timeAsDouble;
if (swapPending)
{
Plugin.Log.LogInfo((object)"Switcheroo request ignored: a swap is already counting down.");
Deny(conn, message.Token, SwitcherooDenialReason.SwapInProgress);
return;
}
if (serverLocked)
{
Plugin.Log.LogInfo((object)"Switcheroo request ignored: already used this round.");
Deny(conn, message.Token, SwitcherooDenialReason.AlreadyUsedThisRound);
return;
}
if (!SenderHoldsSwitcheroo(conn))
{
Plugin.Log.LogWarning((object)$"Ignoring Switcheroo request from connection {conn.connectionId}: no Switcheroo in their inventory.");
Deny(conn, message.Token, SwitcherooDenialReason.NotHolding);
return;
}
int num = SwapService.CountEligible();
if (num < 2)
{
Plugin.Log.LogInfo((object)$"Switcheroo request refused: only {num} eligible ball(s) in play.");
Deny(conn, message.Token, SwitcherooDenialReason.NotEnoughBalls);
return;
}
PlayerInfo initiator = (((Object)(object)((NetworkConnection)conn).identity == (Object)null) ? null : ((Component)((NetworkConnection)conn).identity).GetComponent<PlayerInfo>());
Trace.Log($"server: request accepted from connection {conn.connectionId}");
((NetworkConnection)conn).Send<SwitcherooUseReplyMessage>(new SwitcherooUseReplyMessage
{
Accepted = true,
Reason = 0,
Token = message.Token
}, 0);
ModRunner? instance = ModRunner.Instance;
if (instance != null)
{
((MonoBehaviour)instance).StartCoroutine(RunSwap(initiator));
}
}
private static void Deny(NetworkConnectionToClient conn, uint token, SwitcherooDenialReason reason)
{
((NetworkConnection)conn).Send<SwitcherooUseReplyMessage>(new SwitcherooUseReplyMessage
{
Accepted = false,
Reason = (byte)reason,
Token = token
}, 0);
}
private static IEnumerator RunSwap(PlayerInfo? initiator)
{
swapPending = true;
float num = Mathf.Max(0f, Plugin.WindUpSeconds.Value);
NetworkServer.SendToAll<SwitcherooArmedMessage>(new SwitcherooArmedMessage
{
WindUpSeconds = num,
UserName = NameOf(initiator)
}, 0, false);
Trace.Log($"server: armed, waiting {num:0.0}s");
yield return (object)new WaitForSeconds(num);
Trace.Log("server: wind-up elapsed");
if (!NetworkServer.active)
{
Plugin.Log.LogWarning((object)"Swap abandoned: no longer the server when the wind-up elapsed.");
swapPending = false;
yield break;
}
string failureReason;
List<PlayerGolfer> list = SwapService.TrySwap(out failureReason);
if (list.Count == 0)
{
Plugin.Log.LogInfo((object)("Switcheroo used but no swap ran: " + failureReason + "."));
}
else
{
Plugin.Log.LogInfo((object)$"Switcheroo swapped {list.Count} balls.");
NetworkServer.SendToAll<SwitcherooResultMessage>(new SwitcherooResultMessage
{
SwappedCount = list.Count
}, 0, false);
AnnounceInFeed(initiator, list);
if (MatchSetupRules.GetValueAsBool((Rule)200))
{
serverLocked = true;
NetworkServer.SendToAll<SwitcherooLockMessage>(new SwitcherooLockMessage
{
Locked = true
}, 0, false);
}
}
swapPending = false;
}
public static void TrackHeldItems()
{
if (!NetworkServer.active)
{
return;
}
float time = Time.time;
foreach (NetworkConnectionToClient value in NetworkServer.connections.Values)
{
if (value != null && HoldsSwitcheroo(value))
{
LastHeldSwitcheroo[value.connectionId] = time;
}
}
}
private static bool SenderHoldsSwitcheroo(NetworkConnectionToClient conn)
{
if (HoldsSwitcheroo(conn))
{
return true;
}
if (LastHeldSwitcheroo.TryGetValue(conn.connectionId, out var value))
{
return Time.time - value <= 5f;
}
return false;
}
private static bool HoldsSwitcheroo(NetworkConnectionToClient conn)
{
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: 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_0054: Invalid comparison between Unknown and I4
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)((NetworkConnection)conn).identity == (Object)null)
{
return false;
}
PlayerInfo component = ((Component)((NetworkConnection)conn).identity).GetComponent<PlayerInfo>();
PlayerInventory val = ((component != null) ? component.Inventory : null);
if ((Object)(object)val == (Object)null)
{
return false;
}
Enumerator<InventorySlot> enumerator = val.slots.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
InventorySlot current = enumerator.Current;
if ((int)current.itemType == 200 && current.remainingUses > 0)
{
return true;
}
}
}
finally
{
((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
return false;
}
private static string NameOf(PlayerInfo? player)
{
if ((Object)(object)player == (Object)null)
{
return string.Empty;
}
PlayerId playerId = player.PlayerId;
string text;
if (!((Object)(object)playerId == (Object)null))
{
text = playerId.PlayerNameNoRichText;
if (text == null)
{
return string.Empty;
}
}
else
{
text = string.Empty;
}
return text;
}
private static void AnnounceInFeed(PlayerInfo? initiator, List<PlayerGolfer> swapped)
{
if ((Object)(object)initiator == (Object)null)
{
return;
}
try
{
foreach (PlayerGolfer item in swapped)
{
PlayerInfo playerInfo = item.PlayerInfo;
if ((Object)(object)playerInfo != (Object)null && (Object)(object)playerInfo != (Object)(object)initiator)
{
InfoFeed.ShowItemHitMessage(initiator, playerInfo, (ItemType)200);
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not post the swap to the info feed: " + ex.Message));
}
}
private static void OnClientLock(SwitcherooLockMessage message)
{
LockedThisRound = message.Locked;
}
private static void OnClientArmed(SwitcherooArmedMessage message)
{
clientBusyUntil = Time.timeAsDouble + (double)message.WindUpSeconds + 1.5;
SwitcherooUi.BeginCountdown(message.WindUpSeconds, message.UserName);
SwitcherooAudio.PlayAnticipation();
}
private static void OnClientResult(SwitcherooResultMessage message)
{
clientBusyUntil = 0.0;
Plugin.Log.LogInfo((object)$"Switcheroo swapped {message.SwappedCount} balls.");
SwitcherooAudio.PlayPayoff();
}
}
internal static class SwitcherooPool
{
private static ItemSpawnerSettings? managed;
private static readonly HashSet<int> ManagedPools = new HashSet<int>();
public static bool FallbackActive { get; private set; }
public static void Remember(ItemSpawnerSettings settings)
{
managed = settings;
}
public static bool IsManaged(ItemSpawnerSettings settings)
{
return (Object)(object)managed == (Object)(object)settings;
}
public static bool IsManagedPool(ItemPool pool)
{
return ManagedPools.Contains(((Object)pool).GetInstanceID());
}
public static void EnsureInjected()
{
//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_009c: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.Enabled.Value || (Object)(object)managed == (Object)null || FallbackActive)
{
return;
}
try
{
ManagedPools.Clear();
Inject(managed.AheadOfBallItemPoolDefaults);
Inject(managed.AheadOfBallItemPool);
foreach (ItemPoolData itemPoolsDefault in managed.ItemPoolsDefaults)
{
Inject(itemPoolsDefault.pool);
}
foreach (ItemPoolData itemPool in managed.ItemPools)
{
Inject(itemPool.pool);
}
}
catch (Exception arg)
{
UseFallback($"the Switcheroo could not be added to the item pools: {arg}");
}
}
private static void Inject(ItemPool? pool)
{
//IL_0074: 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_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)pool == (Object)null)
{
return;
}
ManagedPools.Add(((Object)pool).GetInstanceID());
if (!pool.ContainsItemType((ItemType)200))
{
float num = RankWeight(pool, warnIfMissing: true);
if (num <= 0f)
{
Plugin.Log.LogWarning((object)("Pool '" + ((Object)pool).name + "' has no weights to rank against; leaving it alone."));
return;
}
ItemSpawnChance[] array = pool.spawnChances;
Array.Resize(ref array, array.Length + 1);
array[^1] = new ItemSpawnChance
{
item = (ItemType)200,
spawnChanceWeight = num
};
pool.spawnChances = array;
pool.UpdateTotalWeight();
Plugin.Log.LogInfo((object)$"Added the Switcheroo to pool '{((Object)pool).name}' at weight {num:0.###}.");
}
}
internal static float RankWeight(ItemPool pool, bool warnIfMissing)
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: 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: Invalid comparison between Unknown and I4
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
float spawnChanceWeight = pool.GetSpawnChanceWeight((ItemType)10);
float spawnChanceWeight2 = pool.GetSpawnChanceWeight((ItemType)15);
if (spawnChanceWeight > 0f && spawnChanceWeight2 > 0f)
{
return (spawnChanceWeight + spawnChanceWeight2) / 2f;
}
if (spawnChanceWeight > 0f || spawnChanceWeight2 > 0f)
{
return Mathf.Max(spawnChanceWeight, spawnChanceWeight2);
}
float num = 0f;
ItemSpawnChance[] spawnChances = pool.SpawnChances;
foreach (ItemSpawnChance val in spawnChances)
{
if ((int)val.item != 200 && !(val.spawnChanceWeight <= 0f) && (num == 0f || val.spawnChanceWeight < num))
{
num = val.spawnChanceWeight;
}
}
if (warnIfMissing)
{
Plugin.Log.LogInfo((object)("Pool '" + ((Object)pool).name + "' has neither the Orbital Laser nor the Thunderstorm; " + $"ranking the Switcheroo against its rarest item at weight {num:0.###}."));
}
return num;
}
public static void UseFallback(string reason)
{
if (!FallbackActive)
{
FallbackActive = true;
Plugin.Log.LogError((object)("Switcheroo item probabilities are unavailable: " + reason + " Falling back to picking the item as items are drawn, so it still spawns, but it has no slider in the match setup."));
Withdraw();
}
}
private static void Withdraw()
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: 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_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)managed == (Object)null)
{
return;
}
try
{
RemoveFrom(managed.AheadOfBallItemPoolDefaults);
RemoveFrom(managed.AheadOfBallItemPool);
foreach (ItemPoolData itemPoolsDefault in managed.ItemPoolsDefaults)
{
RemoveFrom(itemPoolsDefault.pool);
}
foreach (ItemPoolData itemPool in managed.ItemPools)
{
RemoveFrom(itemPool.pool);
}
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"Could not take the Switcheroo back out of the item pools: {arg}");
}
}
private static void RemoveFrom(ItemPool? pool)
{
//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_0038: 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_0043: Invalid comparison between Unknown and I4
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)pool == (Object)null || !pool.ContainsItemType((ItemType)200))
{
return;
}
List<ItemSpawnChance> list = new List<ItemSpawnChance>(pool.spawnChances.Length);
ItemSpawnChance[] spawnChances = pool.spawnChances;
foreach (ItemSpawnChance val in spawnChances)
{
if ((int)val.item != 200)
{
list.Add(val);
}
}
pool.spawnChances = list.ToArray();
pool.UpdateTotalWeight();
}
}
[HarmonyPatch(typeof(ItemSpawnerSettings), "ResetRuntimeData")]
internal static class ItemSpawnerRuntimePoolPatch
{
private static void Postfix(ItemSpawnerSettings __instance)
{
if (SwitcherooPool.IsManaged(__instance))
{
SwitcherooPool.EnsureInjected();
}
}
}
[HarmonyPatch(typeof(ItemPool), "GetWeightedRandomItem")]
internal static class ItemPoolDrawPatch
{
private static bool Prefix(ItemPool __instance, ref ItemType __result)
{
if (!Plugin.Enabled.Value || !SwitcherooPool.FallbackActive)
{
return true;
}
if (!SwitcherooPool.IsManagedPool(__instance))
{
return true;
}
float num = SwitcherooPool.RankWeight(__instance, warnIfMissing: false);
float totalSpawnChanceWeight = __instance.TotalSpawnChanceWeight;
if (num <= 0f || totalSpawnChanceWeight <= 0f)
{
return true;
}
if (Random.value >= num / (totalSpawnChanceWeight + num))
{
return true;
}
__result = (ItemType)200;
return false;
}
}
[HarmonyPatch(typeof(MatchSetupRules), "Initialize")]
internal static class MatchSetupRuleRowPatch
{
private const string LabelKey = "RULE_SWITCHEROO_ONCE_PER_HOLE";
private const string LabelText = "One Switcheroo per hole";
private static DropdownOption? row;
private static int ownerId;
private static TableReference labelTable;
private static bool labelTableKnown;
private static bool languageHookInstalled;
private static void Postfix(MatchSetupRules __instance)
{
if (!Plugin.Enabled.Value)
{
return;
}
try
{
Build(__instance);
}
catch (Exception arg)
{
Plugin.Log.LogError((object)($"Could not add the once-per-hole row to the match setup: {arg} The rule stays off " + "and the Switcheroo can be used as often as it is found."));
}
}
private static void Build(MatchSetupRules rules)
{
MatchSetupRules.CategoryPerRule[(Rule)200] = (RuleCategory)3;
if ((!((Object)(object)row == (Object)null) && ownerId == ((Object)rules).GetInstanceID()) || Clone(rules))
{
AccessTools.Method(typeof(MatchSetupRules), "InitDropdownOnOff", (Type[])null, (Type[])null).Invoke(rules, new object[3]
{
row,
(object)(Rule)200,
null
});
}
}
private static bool Clone(MatchSetupRules rules)
{
DropdownOption hitOtherPlayersBalls = rules.hitOtherPlayersBalls;
if ((Object)(object)hitOtherPlayersBalls == (Object)null)
{
Plugin.Log.LogWarning((object)"No battle row to copy; the once-per-hole rule has no control.");
return false;
}
GameObject val = Object.Instantiate<GameObject>(((Component)hitOtherPlayersBalls).gameObject, ((Component)hitOtherPlayersBalls).transform.parent);
((Object)val).name = "SwitcherooOncePerHole";
val.transform.SetSiblingIndex(((Component)hitOtherPlayersBalls).transform.GetSiblingIndex() + 1);
DropdownOption component = val.GetComponent<DropdownOption>();
if ((Object)(object)component == (Object)null)
{
Object.Destroy((Object)(object)val);
Plugin.Log.LogWarning((object)"The copied battle row has no DropdownOption; leaving the rule out of the UI.");
return false;
}
Label(val);
row = component;
ownerId = ((Object)rules).GetInstanceID();
Plugin.Log.LogInfo((object)"Added the once-per-hole rule to the match setup's Battle section.");
return true;
}
private static void Label(GameObject clone)
{
//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_0049: Unknown result type (might be due to invalid IL or missing references)
LocalizeStringEvent componentInChildren = clone.GetComponentInChildren<LocalizeStringEvent>(true);
if ((Object)(object)componentInChildren == (Object)null)
{
Plugin.Log.LogWarning((object)"The copied row has no localized label; it will read as the row it was copied from.");
return;
}
labelTable = ((LocalizedReference)componentInChildren.StringReference).TableReference;
labelTableKnown = true;
if (AddEntry())
{
((LocalizedReference)componentInChildren.StringReference).TableEntryReference = TableEntryReference.op_Implicit("RULE_SWITCHEROO_ONCE_PER_HOLE");
componentInChildren.RefreshString();
InstallLanguageHook();
return;
}
TMP_Text component = ((Component)componentInChildren).GetComponent<TMP_Text>();
Object.Destroy((Object)(object)componentInChildren);
if ((Object)(object)component != (Object)null)
{
component.text = "One Switcheroo per hole";
Plugin.Log.LogWarning((object)"Localization was not ready; the once-per-hole row is labelled in English only.");
}
}
private static bool AddEntry()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if (!labelTableKnown)
{
return false;
}
try
{
StringTable val = ((LocalizedDatabase<StringTable, StringTableEntry>)(object)LocalizationSettings.StringDatabase)?.GetTable(labelTable, (Locale)null);
if ((Object)(object)val == (Object)null)
{
return false;
}
((DetailedLocalizationTable<StringTableEntry>)(object)val).AddEntry("RULE_SWITCHEROO_ONCE_PER_HOLE", "One Switcheroo per hole");
return true;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not name the once-per-hole rule: " + ex.Message));
return false;
}
}
private static void InstallLanguageHook()
{
if (!languageHookInstalled)
{
LocalizationManager.LanguageChanged += delegate
{
AddEntry();
};
languageHookInstalled = true;
}
}
}
[HarmonyPatch(typeof(MatchSetupRules), "Initialize")]
internal static class MatchSetupRulesPatch
{
private static void Prefix(MatchSetupRules __instance)
{
if (Plugin.Enabled.Value && !SwitcherooPool.FallbackActive)
{
try
{
Extend(__instance);
}
catch (Exception arg)
{
SwitcherooPool.UseFallback($"the match setup screen could not be extended: {arg}");
return;
}
SwitcherooPool.Remember(__instance.itemSpawnerSettings);
SwitcherooPool.EnsureInjected();
}
}
private static void Extend(MatchSetupRules rules)
{
ItemType[] array = rules.itemOrder;
if (Array.IndexOf(array, (ItemType)200) < 0)
{
ItemType[] array2 = (ItemType[])(object)new ItemType[array.Length + 1];
Array.Copy(array, array2, array.Length);
array2[^1] = (ItemType)200;
array = array2;
}
int[] array3 = new int[Math.Max(200, array.Length)];
for (int i = 0; i < array3.Length; i++)
{
array3[i] = Array.IndexOf(array, (ItemType)(i + 1));
}
rules.itemOrder = array;
rules.itemOrderLookup = array3;
}
}
internal static class SwitcherooThrownItem
{
public const ThrownUsedItemType Type = (ThrownUsedItemType)200;
private static bool registered;
private static bool failedOnce;
public static void EnsureRegistered()
{
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
if (registered || failedOnce || !Plugin.Enabled.Value || !SingletonBehaviour<ThrownUsedItemManager>.HasInstance)
{
return;
}
try
{
ThrownUsedItem value;
if (ThrownUsedItemManager.prefabPerType.ContainsKey((ThrownUsedItemType)200))
{
registered = true;
}
else if (ThrownUsedItemManager.prefabPerType.TryGetValue((ThrownUsedItemType)6, out value) && !((Object)(object)value == (Object)null))
{
GameObject gameObject = ((Component)value).gameObject;
bool activeSelf = gameObject.activeSelf;
gameObject.SetActive(false);
GameObject val;
try
{
val = Object.Instantiate<GameObject>(gameObject);
}
finally
{
gameObject.SetActive(activeSelf);
}
((Object)val).name = "SwitcherooThrownItem";
Object.DontDestroyOnLoad((Object)(object)val);
Switcheroo.Recolour(val);
ThrownUsedItem component = val.GetComponent<ThrownUsedItem>();
component.type = (ThrownUsedItemType)200;
ThrownUsedItemManager.prefabPerType[(ThrownUsedItemType)200] = component;
registered = true;
Plugin.Log.LogInfo((object)$"Registered the discarded Switcheroo as ThrownUsedItemType {200}.");
}
}
catch (Exception arg)
{
failedOnce = true;
Plugin.Log.LogError((object)$"Could not register the discarded Switcheroo: {arg}");
}
}
}
[HarmonyPatch(typeof(PlayerInventory), "ThrowUsedItemInternal")]
internal static class ThrowUsedItemPatch
{
private static bool Prefix(PlayerInventory __instance, ThrownUsedItemType thrownItemType, bool forcePlayerPosition, Vector3 forcedPlayerPosition)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
if ((int)thrownItemType != 200)
{
return true;
}
try
{
SwitcherooThrownItem.EnsureRegistered();
Throw(__instance, forcePlayerPosition, forcedPlayerPosition);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not throw the spent Switcheroo: " + ex.Message));
}
return false;
}
private static void Throw(PlayerInventory inventory, bool forcePlayerPosition, Vector3 forcedPlayerPosition)
{
//IL_0021: 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_002c: 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)
//IL_0069: 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_0081: 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_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: 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_0049: 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_0052: 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_0061: Unknown result type (might be due to invalid IL or missing references)
ThrownUsedItem unusedThrownItem = ThrownUsedItemManager.GetUnusedThrownItem((ThrownUsedItemType)200);
if (!((Object)(object)unusedThrownItem == (Object)null))
{
PlayerInfo playerInfo = inventory.PlayerInfo;
Quaternion orbitalLaserThrowDirectionLocalRotation = GameManager.ItemSettings.OrbitalLaserThrowDirectionLocalRotation;
Vector3 orbitalLaserThrowLocalAngularVelocity = GameManager.ItemSettings.OrbitalLaserThrowLocalAngularVelocity;
Vector3 val = default(Vector3);
Quaternion val2 = default(Quaternion);
((Component)playerInfo.RightHandEquipmentSwitcher).transform.GetPositionAndRotation(ref val, ref val2);
if (forcePlayerPosition)
{
val += forcedPlayerPosition - ((Component)inventory).transform.position;
}
Vector3 val3 = ((Component)inventory).transform.TransformDirection(orbitalLaserThrowDirectionLocalRotation * Vector3.forward);
Vector3 val4 = ((Component)inventory).transform.TransformDirection(orbitalLaserThrowDirectionLocalRotation * orbitalLaserThrowLocalAngularVelocity);
Vector3 val5 = playerInfo.Rigidbody.linearVelocity + val3 * GameManager.ItemSettings.OrbitalLaserThrowSpeed;
Vector3 val6 = playerInfo.Rigidbody.angularVelocity + val4;
unusedThrownItem.Initialize(val, val2, val5, val6, playerInfo.GetEffectiveTeam());
PhysicsManager.TemporarilyIgnoreCollisionsBetween(playerInfo.AsEntity, unusedThrownItem.AsEntity, 0.5f, false);
}
}
}
internal static class SwitcherooUi
{
private static readonly Color32 GradientBottom = new Color32(byte.MaxValue, (byte)252, (byte)212, byte.MaxValue);
private const float DenialSeconds = 1.6f;
private const float DenialFlashHz = 4f;
private const float DenialAloneY = -180f;
private const float DenialBelowCountdownY = -360f;
private static TextMeshProUGUI? label;
private static TextMeshProUGUI? userLabel;
private static TextMeshProUGUI? denialLabel;
private static CanvasGroup? group;
private static float countdownEndTime;
private static float denialEndTime;
private static string denialText = string.Empty;
private static string countdownUser = string.Empty;
public static void BeginCountdown(float seconds, string userName)
{
countdownEndTime = Time.time + seconds;
countdownUser = userName ?? string.Empty;
}
public static void ShowDenial(string message)
{
denialText = message;
denialEndTime = Time.time + 1.6f;
}
public static void Tick()
{
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
float num = countdownEndTime - Time.time;
float num2 = denialEndTime - Time.time;
if (num <= 0f && num2 <= 0f)
{
if ((Object)(object)group != (Object)null && group.alpha != 0f)
{
group.alpha = 0f;
}
}
else
{
if (!EnsureLabel())
{
return;
}
group.alpha = 1f;
if (num > 0f)
{
((Behaviour)label).enabled = true;
((TMP_Text)label).text = $"SWITCHEROO IN {Mathf.CeilToInt(num)}";
((Behaviour)userLabel).enabled = countdownUser.Length > 0;
if (((Behaviour)userLabel).enabled)
{
((TMP_Text)userLabel).text = "USED BY " + countdownUser.ToUpperInvariant();
}
}
else
{
((Behaviour)label).enabled = false;
((Behaviour)userLabel).enabled = false;
}
if (num2 > 0f)
{
((Behaviour)denialLabel).enabled = true;
((TMP_Text)denialLabel).text = denialText;
((TMP_Text)denialLabel).rectTransform.anchoredPosition = new Vector2(0f, (num > 0f) ? (-360f) : (-180f));
bool flag = Mathf.Repeat(num2 * 4f, 1f) > 0.5f;
((TMP_Text)denialLabel).alpha = (flag ? 1f : 0.15f);
}
else
{
((Behaviour)denialLabel).enabled = false;
}
}
}
private static bool EnsureLabel()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_0063: 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_00bb: Expected O, but got Unknown
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01fd: 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)label != (Object)null)
{
return true;
}
TMP_FontAsset val = FindGameFont();
if ((Object)(object)val == (Object)null)
{
return false;
}
GameObject val2 = new GameObject("BallSwapItemCountdown");
Object.DontDestroyOnLoad((Object)(object)val2);
Canvas val3 = val2.AddComponent<Canvas>();
val3.renderMode = (RenderMode)0;
val3.sortingOrder = 500;
CanvasScaler val4 = val2.AddComponent<CanvasScaler>();
val4.uiScaleMode = (ScaleMode)1;
val4.referenceResolution = new Vector2(1920f, 1080f);
val4.screenMatchMode = (ScreenMatchMode)0;
val4.matchWidthOrHeight = 1f;
group = val2.AddComponent<CanvasGroup>();
group.alpha = 0f;
group.interactable = false;
group.blocksRaycasts = false;
GameObject val5 = new GameObject("Label");
val5.transform.SetParent(val2.transform, false);
label = val5.AddComponent<TextMeshProUGUI>();
((TMP_Text)label).font = val;
((TMP_Text)label).fontSize = 76f;
((TMP_Text)label).alignment = (TextAlignmentOptions)514;
((TMP_Text)label).textWrappingMode = (TextWrappingModes)0;
((Graphic)label).raycastTarget = false;
((TMP_Text)label).enableVertexGradient = true;
((TMP_Text)label).colorGradient = new VertexGradient(Color.white, Color.white, Color32.op_Implicit(GradientBottom), Color32.op_Implicit(GradientBottom));
((TMP_Text)label).outlineWidth = 0.2f;
((TMP_Text)label).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
RectTransform rectTransform = ((TMP_Text)label).rectTransform;
rectTransform.anchorMin = new Vector2(0.5f, 1f);
rectTransform.anchorMax = new Vector2(0.5f, 1f);
rectTransform.pivot = new Vector2(0.5f, 1f);
rectTransform.anchoredPosition = new Vector2(0f, -180f);
rectTransform.sizeDelta = new Vector2(1400f, 120f);
userLabel = BuildSecondaryLabel(val2, val, "User", 40f, GradientBottom, -292f, 60f);
denialLabel = BuildSecondaryLabel(val2, val, "Denial", 58f, new Color32(byte.MaxValue, (byte)59, (byte)48, byte.MaxValue), -180f, 120f);
Plugin.Log.LogInfo((object)("Countdown label built using the game font '" + ((Object)val).name + "'."));
return true;
}
private static TextMeshProUGUI BuildSecondaryLabel(GameObject root, TMP_FontAsset font, string name, float fontSize, Color32 color, float y, float height)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_0048: 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_0068: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
val.transform.SetParent(root.transform, false);
TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)val2).font = font;
((TMP_Text)val2).fontSize = fontSize;
((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0;
((Graphic)val2).raycastTarget = false;
((Graphic)val2).color = Color32.op_Implicit(color);
((TMP_Text)val2).outlineWidth = 0.2f;
((TMP_Text)val2).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
((Behaviour)val2).enabled = false;
RectTransform rectTransform = ((TMP_Text)val2).rectTransform;
rectTransform.anchorMin = new Vector2(0.5f, 1f);
rectTransform.anchorMax = new Vector2(0.5f, 1f);
rectTransform.pivot = new Vector2(0.5f, 1f);
rectTransform.anchoredPosition = new Vector2(0f, y);
rectTransform.sizeDelta = new Vector2(1400f, height);
return val2;
}
private static TMP_FontAsset? FindGameFont()
{
TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
if (array.Length == 0)
{
return null;
}
return (from text in array
select text.font into font
where (Object)(object)font != (Object)null
group font by font into @group
orderby @group.Count() descending
select @group.Key).FirstOrDefault();
}
}
[HarmonyPatch(typeof(PlayerInventory), "TryUseItem")]
internal static class SwitcherooUsePatch
{
private static bool Prefix(PlayerInventory __instance, bool isAirhornReaction, ref bool shouldEatInput, ref bool __result)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Invalid comparison between Unknown and I4
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
shouldEatInput = true;
if (!((NetworkBehaviour)__instance).isLocalPlayer)
{
return true;
}
if ((int)__instance.GetEffectivelyEquippedItem(false) != 200)
{
return true;
}
if (SwitcherooNetwork.LockedThisRound)
{
Refuse("ONCE PER ROUND");
__result = false;
return false;
}
if (SwitcherooNetwork.SwapInProgress)
{
Trace.Log("use refused: a swap is already counting down");
Refuse("SWAP IN PROGRESS");
__result = false;
return false;
}
int num = SwapService.CountEligible();
if (num < 2)
{
Trace.Log($"use refused: only {num} eligible ball(s)");
Refuse("NO BALLS TO SWAP");
__result = false;
return false;
}
InventorySlot val = default(InventorySlot);
ItemData val2 = default(ItemData);
bool flag = default(bool);
if (!__instance.CanUseEquippedItem(false, isAirhornReaction, ref val, ref val2, ref shouldEatInput, ref flag))
{
__result = false;
return false;
}
Trace.Log($"use accepted, currentItemUse={__instance.CurrentItemUse}, slot={__instance.EquippedItemIndex}");
__instance.ItemUseTimestamp = Time.timeAsDouble;
__instance.CancelItemUse();
__instance.itemUseRoutine = ((MonoBehaviour)__instance).StartCoroutine(SwitcherooRoutine(__instance));
__instance.PlayerInfo.CancelEmote(false);
__instance.CancelItemFlourish();
__result = true;
return false;
}
private static void Refuse(string message)
{
SwitcherooUi.ShowDenial(message);
SwitcherooAudio.PlayDenial();
}
private static IEnumerator SwitcherooRoutine(PlayerInventory inventory)
{
Trace.Log("routine: started");
inventory.SetCurrentItemUse((ItemUseType)1);
yield return (object)new WaitForSeconds(GameManager.ItemSettings.OrbitalLaserActivationTime);
Trace.Log("routine: activation wait done, sending request");
SwitcherooNetwork.RequestSwap();
float waited = 0f;
while (SwitcherooNetwork.RequestState == SwapRequestState.Waiting)
{
if (waited >= 2f)
{
SwitcherooNetwork.TimeOutRequest();
break;
}
yield return null;
waited += Time.deltaTime;
}
if (SwitcherooNetwork.RequestState != SwapRequestState.Accepted)
{
Trace.Log("routine: use denied (" + SwitcherooNetwork.DenialText + "), keeping the item");
Refuse(SwitcherooNetwork.DenialText);
inventory.SetCurrentItemUse((ItemUseType)0);
yield break;
}
Trace.Log("routine: host accepted, spending the item");
int index = inventory.EquippedItemIndex;
inventory.DecrementUseFromSlotAt(index);
bool thrown = false;
for (float timeSince = BMath.GetTimeSince(inventory.ItemUseTimestamp); timeSince < GameManager.ItemSettings.OrbitalLaserActivationTotalDuration; timeSince = BMath.GetTimeSince(inventory.ItemUseTimestamp))
{
if (!thrown && timeSince >= GameManager.ItemSettings.OrbitalLaserThrowTime)
{
try
{
SwitcherooThrownItem.EnsureRegistered();
inventory.ThrowUsedItemForAllClients((ThrownUsedItemType)200, false, default(Vector3), false);
inventory.LocalPlayerMarkThrownItem((ThrownItemHand)2);
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"Could not throw the spent Switcheroo: {arg}");
}
thrown = true;
Trace.Log($"routine: threw spent device at {timeSince:0.00}s");
}
yield return null;
}
Trace.Log("routine: finished, clearing use state");
inventory.SetCurrentItemUse((ItemUseType)0);
inventory.RemoveIfOutOfUses(index, true);
}
}
internal static class Trace
{
public static void Log(string message)
{
if (Plugin.VerboseLogging.Value)
{
Plugin.Log.LogInfo((object)("[trace] " + message));
}
}
}
}
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class ConstantExpectedAttribute : Attribute
{
public object? Min { get; set; }
public object? Max { get; set; }
}
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class ExperimentalAttribute : Attribute
{
public string DiagnosticId { get; }
public string? UrlFormat { get; set; }
public ExperimentalAttribute(string diagnosticId)
{
DiagnosticId = diagnosticId;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class MemberNotNullAttribute : Attribute
{
public string[] Members { get; }
public MemberNotNullAttribute(string member)
{
Members = new string[1] { member };
}
public MemberNotNullAttribute(params string[] members)
{
Members = members;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public string[] Members { get; }
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new string[1] { member };
}
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
}
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class SetsRequiredMembersAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class StringSyntaxAttribute : Attribute
{
public const string CompositeFormat = "CompositeFormat";
public const string DateOnlyFormat = "DateOnlyFormat";
public const string DateTimeFormat = "DateTimeFormat";
public const string EnumFormat = "EnumFormat";
public const string GuidFormat = "GuidFormat";
public const string Json = "Json";
public const string NumericFormat = "NumericFormat";
public const string Regex = "Regex";
public const string TimeOnlyFormat = "TimeOnlyFormat";
public const string TimeSpanFormat = "TimeSpanFormat";
public const string Uri = "Uri";
public const string Xml = "Xml";
public string Syntax { get; }
public object?[] Arguments { get; }
public StringSyntaxAttribute(string syntax)
{
Syntax = syntax;
Arguments = new object[0];
}
public StringSyntaxAttribute(string syntax, params object?[] arguments)
{
Syntax = syntax;
Arguments = arguments;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class UnscopedRefAttribute : Attribute
{
}
}
namespace System.Runtime.Versioning
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class RequiresPreviewFeaturesAttribute : Attribute
{
public string? Message { get; }
public string? Url { get; set; }
public RequiresPreviewFeaturesAttribute()
{
}
public RequiresPreviewFeaturesAttribute(string? message)
{
Message = message;
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CallerArgumentExpressionAttribute : Attribute
{
public string ParameterName { get; }
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CollectionBuilderAttribute : Attribute
{
public Type BuilderType { get; }
public string MethodName { get; }
public CollectionBuilderAttribute(Type builderType, string methodName)
{
BuilderType = builderType;
MethodName = methodName;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public const string RefStructs = "RefStructs";
public const string RequiredMembers = "RequiredMembers";
public string FeatureName { get; }
public bool IsOptional { get; set; }
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
{
public string[] Arguments { get; }
public InterpolatedStringHandlerArgumentAttribute(string argument)
{
Arguments = new string[1] { argument };
}
public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
{
Arguments = arguments;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class InterpolatedStringHandlerAttribute : Attribute
{
}
[EditorBrowsable(EditorBrowsableState.Never)]
[ExcludeFromCodeCoverage]
internal static class IsExternalInit
{
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class ModuleInitializerAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class OverloadResolutionPriorityAttribute : Attribute
{
public int Priority { get; }
public OverloadResolutionPriorityAttribute(int priority)
{
Priority = priority;
}
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
[ExcludeFromCodeCoverage]
internal sealed class ParamCollectionAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class RequiredMemberAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[ExcludeFromCodeCoverage]
internal sealed class RequiresLocationAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class SkipLocalsInitAttribute : Attribute
{
}
}