Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShopGamble v1.0.0
ShopGamble.dll
Decompiled 4 days agousing 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"); } } }