Decompiled source of ShopGamble v1.0.0

ShopGamble.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ShopGamble")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShopGamble")]
[assembly: AssemblyTitle("ShopGamble")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 ShopGamble
{
	internal static class GambleCommand
	{
		public static void Execute(bool isDebugConsole, string[] args)
		{
			if (SemiFunc.IsMainMenu() || (Object)(object)StatsManager.instance == (Object)null)
			{
				GambleMessages.ShowError(GambleResultCode.NotInShop, 0, 0);
				return;
			}
			if (args == null || args.Length == 0)
			{
				GambleMessages.ShowUsage();
				return;
			}
			string text = args[0].Trim().ToLowerInvariant();
			int betK;
			switch (text)
			{
			case "all":
			case "allin":
			case "max":
				betK = SemiFunc.StatGetRunCurrency();
				break;
			default:
				if (!TryParseBetK(text, out betK))
				{
					GambleMessages.ShowUsage();
					return;
				}
				break;
			}
			GambleNetwork.SendRequest(betK);
		}

		internal static bool TryParseBetK(string raw, out int betK)
		{
			betK = 0;
			string text = raw.Replace("$", "").Replace("_", "").Replace(" ", "");
			if (text.Length == 0)
			{
				return false;
			}
			double num = 1.0;
			bool flag = false;
			switch (text[text.Length - 1])
			{
			case 'k':
				num = 1000.0;
				flag = true;
				text = text.Substring(0, text.Length - 1);
				break;
			case 'm':
				num = 1000000.0;
				flag = true;
				text = text.Substring(0, text.Length - 1);
				break;
			}
			text = ((!flag) ? text.Replace(",", "").Replace(".", "") : text.Replace(',', '.'));
			if (!double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			if (result <= 0.0 || double.IsNaN(result) || double.IsInfinity(result))
			{
				return false;
			}
			double num2 = Math.Floor((flag ? (result * num) : ((result < 1000.0) ? (result * 1000.0) : result)) / 1000.0);
			if (num2 < 1.0 || num2 > 2147483647.0)
			{
				return false;
			}
			betK = (int)num2;
			return true;
		}
	}
	public enum MessageLanguage
	{
		English,
		German
	}
	internal sealed class GambleConfig
	{
		public ConfigEntry<int> MinBet { get; }

		public ConfigEntry<int> MaxBet { get; }

		public ConfigEntry<float> WinChancePercent { get; }

		public ConfigEntry<float> WinMultiplier { get; }

		public ConfigEntry<bool> OnlyInShop { get; }

		public ConfigEntry<bool> AllowClients { get; }

		public ConfigEntry<float> CooldownSeconds { get; }

		public ConfigEntry<bool> AnnounceToEveryone { get; }

		public ConfigEntry<MessageLanguage> Language { get; }

		public GambleConfig(ConfigFile cfg)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			MinBet = cfg.Bind<int>("Gamble", "MinBet", 1000, new ConfigDescription("Minimum bet in credits (1000 = $1K in game). Bets are counted in steps of 1000.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1000, 100000000), Array.Empty<object>()));
			MaxBet = cfg.Bind<int>("Gamble", "MaxBet", 0, new ConfigDescription("Maximum bet in credits. 0 = no limit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000000), Array.Empty<object>()));
			WinChancePercent = cfg.Bind<float>("Gamble", "WinChancePercent", 50f, new ConfigDescription("Chance to win in percent (50 = coin flip, 45 = house edge).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			WinMultiplier = cfg.Bind<float>("Gamble", "WinMultiplier", 2f, new ConfigDescription("Payout multiplier on a win. 2 = you get your bet back doubled (bet 5K, win 5K profit).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			OnlyInShop = cfg.Bind<bool>("Rules", "OnlyInShop", true, "If true, /gamble only works in the shop between levels.");
			AllowClients = cfg.Bind<bool>("Rules", "AllowClients", true, "If true, non-host players may gamble too (host setting decides).");
			CooldownSeconds = cfg.Bind<float>("Rules", "CooldownSeconds", 2f, new ConfigDescription("Seconds a player has to wait between two bets.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			AnnounceToEveryone = cfg.Bind<bool>("Messages", "AnnounceToEveryone", true, "If true, all players see a short message when someone wins or loses.");
			Language = cfg.Bind<MessageLanguage>("Messages", "Language", MessageLanguage.English, "Language of the on-screen messages (local setting).");
		}
	}
	internal static class GambleHost
	{
		private static readonly Dictionary<int, float> LastBetTime = new Dictionary<int, float>();

		public static void HandleRequest(int actor, string playerName, int betK)
		{
			GambleConfig settings = Plugin.Settings;
			int num = SemiFunc.StatGetRunCurrency();
			GambleResult result = new GambleResult
			{
				Actor = actor,
				PlayerName = playerName,
				BetK = betK,
				BalanceK = num
			};
			int limitK;
			GambleResultCode? gambleResultCode = Validate(actor, betK, num, settings, out limitK);
			if (gambleResultCode.HasValue)
			{
				result.Code = gambleResultCode.Value;
				result.LimitK = limitK;
				GambleNetwork.SendTo(actor, result);
				return;
			}
			LastBetTime[actor] = Time.realtimeSinceStartup;
			float value = settings.WinChancePercent.Value;
			bool flag = value >= 100f || Random.Range(0f, 100f) < value;
			long val;
			if (flag)
			{
				long num2 = (long)Math.Round((double)betK * (double)settings.WinMultiplier.Value, MidpointRounding.AwayFromZero);
				result.DeltaK = (int)Math.Min(num2 - betK, 2147483647L);
				val = (long)num + (long)result.DeltaK;
				result.Code = GambleResultCode.Won;
			}
			else
			{
				result.DeltaK = -betK;
				val = (long)num - (long)betK;
				result.Code = GambleResultCode.Lost;
			}
			result.BalanceK = (int)Math.Max(0L, Math.Min(val, 2147483647L));
			SemiFunc.StatSetRunCurrency(result.BalanceK);
			Plugin.Log.LogInfo((object)string.Format("{0} bet ${1}K -> {2} ({3:+#;-#;0}K), team money now ${4}K", playerName, betK, flag ? "WON" : "LOST", result.DeltaK, result.BalanceK));
			if (settings.AnnounceToEveryone.Value)
			{
				GambleNetwork.Broadcast(result);
			}
			else
			{
				GambleNetwork.SendTo(actor, result);
			}
		}

		private static GambleResultCode? Validate(int actor, int betK, int balanceK, GambleConfig cfg, out int limitK)
		{
			limitK = 0;
			if (cfg.OnlyInShop.Value && !SemiFunc.RunIsShop())
			{
				return GambleResultCode.NotInShop;
			}
			if (!cfg.AllowClients.Value && actor != GambleNetwork.LocalActor)
			{
				return GambleResultCode.ClientsDisabled;
			}
			if (LastBetTime.TryGetValue(actor, out var value) && Time.realtimeSinceStartup - value < cfg.CooldownSeconds.Value)
			{
				return GambleResultCode.Cooldown;
			}
			int num = Math.Max(1, (int)Math.Ceiling((double)cfg.MinBet.Value / 1000.0));
			if (betK < num)
			{
				limitK = num;
				return GambleResultCode.BelowMin;
			}
			int num2 = cfg.MaxBet.Value / 1000;
			if (cfg.MaxBet.Value > 0 && betK > num2)
			{
				limitK = num2;
				return GambleResultCode.AboveMax;
			}
			if (betK > balanceK)
			{
				return GambleResultCode.NotEnoughMoney;
			}
			return null;
		}
	}
	internal static class GambleMessages
	{
		private static bool German => Plugin.Settings.Language.Value == MessageLanguage.German;

		private static string Money(int k)
		{
			return "$" + SemiFunc.DollarGetString(k) + "K";
		}

		public static void ShowResult(GambleResult r, bool isMine)
		{
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (r.Code == GambleResultCode.Won || r.Code == GambleResultCode.Lost)
			{
				bool flag = r.Code == GambleResultCode.Won;
				if (isMine)
				{
					string obj = (flag ? ((German ? "GEWONNEN! +" : "YOU WON! +") + Money(r.DeltaK)) : ((German ? "VERLOREN! -" : "YOU LOST! -") + Money(r.BetK)));
					Color val = (flag ? Color.green : Color.red);
					SemiFunc.UIBigMessage(obj, flag ? "{check}" : "{:O}", 25f, val, Color.white);
					SemiFunc.UIFocusText((German ? "Teamgeld: " : "Team money: ") + Money(r.BalanceK), Color.white, val, 4f);
					Effect(flag);
				}
				else
				{
					SemiFunc.UIFocusText(flag ? (r.PlayerName + (German ? (" hat " + Money(r.DeltaK) + " gewonnen!") : (" won " + Money(r.DeltaK) + "!"))) : (r.PlayerName + (German ? (" hat " + Money(r.BetK) + " verzockt!") : (" lost " + Money(r.BetK) + "!"))), Color.white, flag ? Color.green : Color.red, 3f);
				}
			}
			else if (isMine)
			{
				ShowError(r.Code, r.BalanceK, r.LimitK);
			}
		}

		public static void ShowError(GambleResultCode code, int balanceK, int limitK)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			SemiFunc.UIFocusText(code switch
			{
				GambleResultCode.NotInShop => German ? "Gambling geht nur im Shop!" : "You can only gamble in the shop!", 
				GambleResultCode.BelowMin => (German ? "Mindesteinsatz: " : "Minimum bet: ") + Money(limitK), 
				GambleResultCode.AboveMax => (German ? "Maximaleinsatz: " : "Maximum bet: ") + Money(limitK), 
				GambleResultCode.NotEnoughMoney => (German ? "Nicht genug Geld! Teamgeld: " : "Not enough money! Team money: ") + Money(balanceK), 
				GambleResultCode.Cooldown => German ? "Kurz warten..." : "Slow down...", 
				GambleResultCode.ClientsDisabled => German ? "Der Host hat Gambling für Spieler deaktiviert." : "The host disabled gambling for players.", 
				_ => "Gamble error", 
			}, Color.white, Color.red, 3f);
			Effect(success: false);
		}

		public static void ShowUsage()
		{
			//IL_0013: 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)
			SemiFunc.UIFocusText(German ? "Nutzung: /gamble <Betrag|all>  z.B. /gamble 5000 oder /gamble 5k" : "Usage: /gamble <amount|all>  e.g. /gamble 5000 or /gamble 5k", Color.white, Color.yellow, 4f);
			Effect(success: false);
		}

		private static void Effect(bool success)
		{
			DebugCommandHandler instance = DebugCommandHandler.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if (success)
				{
					instance.CommandSuccessEffect();
				}
				else
				{
					instance.CommandFailedEffect();
				}
			}
		}
	}
	internal enum GambleResultCode
	{
		Won = 0,
		Lost = 1,
		NotInShop = 10,
		BelowMin = 11,
		AboveMax = 12,
		NotEnoughMoney = 13,
		Cooldown = 14,
		ClientsDisabled = 15
	}
	internal struct GambleResult
	{
		public int Actor;

		public string PlayerName;

		public GambleResultCode Code;

		public int BetK;

		public int DeltaK;

		public int BalanceK;

		public int LimitK;

		public object[] ToPayload()
		{
			return new object[7]
			{
				Actor,
				PlayerName ?? "",
				(int)Code,
				BetK,
				DeltaK,
				BalanceK,
				LimitK
			};
		}

		public static bool TryFromPayload(object data, out GambleResult r)
		{
			r = default(GambleResult);
			if (!(data is object[] array) || array.Length < 7)
			{
				return false;
			}
			r.Actor = (int)array[0];
			r.PlayerName = array[1] as string;
			r.Code = (GambleResultCode)(int)array[2];
			r.BetK = (int)array[3];
			r.DeltaK = (int)array[4];
			r.BalanceK = (int)array[5];
			r.LimitK = (int)array[6];
			return true;
		}
	}
	internal static class GambleNetwork
	{
		private static NetworkedEvent _requestEvent;

		private static NetworkedEvent _resultEvent;

		public static bool IsOnline
		{
			get
			{
				if (SemiFunc.IsMultiplayer())
				{
					return PhotonNetwork.InRoom;
				}
				return false;
			}
		}

		public static int LocalActor
		{
			get
			{
				if (!IsOnline)
				{
					return 0;
				}
				return PhotonNetwork.LocalPlayer.ActorNumber;
			}
		}

		public static void Register()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			_requestEvent = new NetworkedEvent("ShopGamble_Request", (Action<EventData>)OnRequestReceived);
			_resultEvent = new NetworkedEvent("ShopGamble_Result", (Action<EventData>)OnResultReceived);
		}

		public static void SendRequest(int betK)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0049: Expected O, but got Unknown
			if (!IsOnline || PhotonNetwork.IsMasterClient)
			{
				GambleHost.HandleRequest(LocalActor, LocalPlayerName(), betK);
				return;
			}
			_requestEvent.RaiseEvent((object)new object[1] { betK }, new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)2
			}, SendOptions.SendReliable);
		}

		private static void OnRequestReceived(EventData e)
		{
			if (SemiFunc.IsMasterClientOrSingleplayer() && e.CustomData is object[] array && array.Length >= 1 && array[0] is int betK)
			{
				string playerName = "Player";
				Room currentRoom = PhotonNetwork.CurrentRoom;
				Player val = ((currentRoom != null) ? currentRoom.GetPlayer(e.Sender, false) : null);
				if (val != null && !string.IsNullOrEmpty(val.NickName))
				{
					playerName = val.NickName;
				}
				GambleHost.HandleRequest(e.Sender, playerName, betK);
			}
		}

		public static void SendTo(int actor, GambleResult result)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOnline || actor == LocalActor)
			{
				GambleMessages.ShowResult(result, isMine: true);
				return;
			}
			NetworkedEvent resultEvent = _resultEvent;
			object[] array = result.ToPayload();
			RaiseEventOptions val = new RaiseEventOptions();
			val.TargetActors = new int[1] { actor };
			resultEvent.RaiseEvent((object)array, val, SendOptions.SendReliable);
		}

		public static void Broadcast(GambleResult result)
		{
			//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_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_003d: Expected O, but got Unknown
			GambleMessages.ShowResult(result, result.Actor == LocalActor);
			if (IsOnline)
			{
				_resultEvent.RaiseEvent((object)result.ToPayload(), new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)0
				}, SendOptions.SendReliable);
			}
		}

		private static void OnResultReceived(EventData e)
		{
			if (GambleResult.TryFromPayload(e.CustomData, out var r))
			{
				GambleMessages.ShowResult(r, r.Actor == LocalActor);
			}
		}

		private static string LocalPlayerName()
		{
			if (IsOnline && !string.IsNullOrEmpty(PhotonNetwork.LocalPlayer.NickName))
			{
				return PhotonNetwork.LocalPlayer.NickName;
			}
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if (!((Object)(object)val != (Object)null))
			{
				return "Player";
			}
			return SemiFunc.PlayerGetName(val);
		}
	}
	[BepInPlugin("ThomasPlays.ShopGamble", "ShopGamble", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ThomasPlays.ShopGamble";

		public const string PluginName = "ShopGamble";

		public const string PluginVersion = "1.0.0";

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static GambleConfig Settings { get; private set; }

		private void Awake()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new GambleConfig(((BaseUnityPlugin)this).Config);
			GambleNetwork.Register();
			string[] array = new string[2] { "gamble", "gambling" };
			foreach (string text in array)
			{
				Commands.RegisterCommand(new ChatCommand(text, "Gamble team credits in the shop: /" + text + " <amount|all>  (e.g. /" + text + " 5000 or /" + text + " 5k)", (Action<bool, string[]>)GambleCommand.Execute, (Func<bool, string, string[], List<string>>)null, (Func<bool>)(() => true), false));
			}
			Log.LogInfo((object)"ShopGamble 1.0.0 loaded. Commands: /gamble, /gambling");
		}
	}
}