Decompiled source of CrimsonDice v3.1.0

CrimsonDice.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CrimsonDice.Commands;
using CrimsonDice.Services;
using CrimsonDice.Structs;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ProjectM.Network;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Transforms;
using VAMP;
using VAMP.Utilities;
using VampireCommandFramework;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("skytech6")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Roll dice in local chat to resolve disputes!")]
[assembly: AssemblyFileVersion("3.1.0.0")]
[assembly: AssemblyInformationalVersion("3.1.0+Branch.master.Sha.b704f7de30757dba7cb9e950899ee90508319d4c.b704f7de30757dba7cb9e950899ee90508319d4c")]
[assembly: AssemblyProduct("CrimsonDice")]
[assembly: AssemblyTitle("CrimsonDice")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CrimsonDice
{
	[BepInPlugin("CrimsonDice", "CrimsonDice", "3.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public static Plugin Instance { get; private set; }

		public static Harmony Harmony => Instance._harmony;

		public static ManualLogSource LogInstance => ((BasePlugin)Instance).Log;

		public static Settings Settings { get; private set; }

		public static DiceService DiceService { get; private set; }

		public override void Load()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Instance = this;
			Settings = default(Settings);
			if (Settings.InitConfig())
			{
				_harmony = new Harmony("CrimsonDice");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				CommandRegistry.RegisterCommandType(typeof(DiceCommands));
				if (Settings.PigEnabled.Value)
				{
					CommandRegistry.RegisterCommandType(typeof(PigCommands));
				}
				Events.OnCoreLoaded = (Action)Delegate.Combine(Events.OnCoreLoaded, new Action(Loaded));
			}
		}

		private void Loaded()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			DiceService = new DiceService();
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CrimsonDice");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("3.1.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val);
		}

		public override bool Unload()
		{
			CommandRegistry.UnregisterAssembly();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "CrimsonDice";

		public const string PLUGIN_NAME = "CrimsonDice";

		public const string PLUGIN_VERSION = "3.1.0";
	}
}
namespace CrimsonDice.Structs
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public readonly struct Settings
	{
		private static readonly List<string> OrderedSections = new List<string> { "Config", "Pig" };

		public static ConfigEntry<bool> ToggleMod { get; private set; }

		public static ConfigEntry<bool> AllowInGlobal { get; private set; }

		public static ConfigEntry<string> ResultColor { get; private set; }

		public static ConfigEntry<bool> PigEnabled { get; private set; }

		public static ConfigEntry<int> PigMinPlayers { get; private set; }

		public static ConfigEntry<int> PigMaxPlayers { get; private set; }

		public static ConfigEntry<int> PigMinScore { get; private set; }

		public static ConfigEntry<int> PigMaxScore { get; private set; }

		public static bool InitConfig()
		{
			ToggleMod = InitConfigEntry(OrderedSections[0], "ToggleMod", defaultValue: true, "Enable or disable the mod.");
			ResultColor = InitConfigEntry(OrderedSections[0], "ResultColor", "#34C6EB", "The color displayed for the player's roll sum.");
			AllowInGlobal = InitConfigEntry(OrderedSections[0], "AllowInGlobal", defaultValue: false, "If set to true, people will be able to roll dice in Global chat.");
			PigEnabled = InitConfigEntry(OrderedSections[1], "PigEnabled", defaultValue: true, "Enable or disable the Pig game.");
			PigMinPlayers = InitConfigEntry(OrderedSections[1], "PigMinPlayers", 1, "The minimum number of players required to start a Pig game.");
			PigMaxPlayers = InitConfigEntry(OrderedSections[1], "PigMaxPlayers", 6, "The maximum number of players allowed in a Pig game.");
			PigMinScore = InitConfigEntry(OrderedSections[1], "PigMinScore", 50, "The minimum target score allowed to win a Pig game.");
			PigMaxScore = InitConfigEntry(OrderedSections[1], "PigMaxScore", 500, "The maximum target score allowed in a Pig game.");
			ReorderConfigSections();
			return ToggleMod.Value;
		}

		private static ConfigEntry<T> InitConfigEntry<T>(string section, string key, T defaultValue, string description)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<T> val = ((BasePlugin)Plugin.Instance).Config.Bind<T>(section, key, defaultValue, description);
			string text = Path.Combine(Paths.ConfigPath, "CrimsonDice.cfg");
			ConfigEntry<T> val2 = default(ConfigEntry<T>);
			if (File.Exists(text) && new ConfigFile(text, true).TryGetEntry<T>(section, key, ref val2))
			{
				val.Value = val2.Value;
			}
			return val;
		}

		private static void ReorderConfigSections()
		{
			string path = Path.Combine(Paths.ConfigPath, "CrimsonDice.cfg");
			if (!File.Exists(path))
			{
				return;
			}
			List<string> list = File.ReadAllLines(path).ToList();
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			string text = "";
			foreach (string item in list)
			{
				if (item.StartsWith("["))
				{
					text = item.Trim('[', ']');
					dictionary[text] = new List<string> { item };
				}
				else if (!string.IsNullOrWhiteSpace(text))
				{
					dictionary[text].Add(item);
				}
			}
			using StreamWriter streamWriter = new StreamWriter(path, append: false);
			foreach (string orderedSection in OrderedSections)
			{
				if (!dictionary.ContainsKey(orderedSection))
				{
					continue;
				}
				foreach (string item2 in dictionary[orderedSection])
				{
					streamWriter.WriteLine(item2);
				}
				streamWriter.WriteLine();
			}
		}
	}
}
namespace CrimsonDice.Services
{
	public class DiceService
	{
		public static List<int> ValidDice;

		public DiceService()
		{
			ValidDice = new List<int> { 4, 6, 8, 10, 12, 20, 100 };
		}

		public static bool IsValidDie(int die)
		{
			return ValidDice.Contains(die);
		}

		public static int RollDie(int die)
		{
			return new Random().Next(1, die + 1);
		}

		public static int RollDice(int die, int count)
		{
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				num += RollDie(die);
			}
			return num;
		}

		public static bool ValidateHandOfDice(string hand, out int die, out int amount)
		{
			die = 0;
			amount = 0;
			if (string.IsNullOrEmpty(hand))
			{
				return false;
			}
			if (!hand.Contains('d'))
			{
				return false;
			}
			string[] array = hand.ToLower().Split('d');
			if (array.Length != 2)
			{
				return false;
			}
			if (!int.TryParse(array[0], out amount) || !int.TryParse(array[1], out die))
			{
				return false;
			}
			if (amount <= 0)
			{
				return false;
			}
			return IsValidDie(die);
		}
	}
	public class PigGameService
	{
		private static Dictionary<string, PigGame> _activeGames = new Dictionary<string, PigGame>();

		private static Dictionary<ulong, string> _playerToGameMap = new Dictionary<ulong, string>();

		public static string CreateGame(User host, int targetScore = 100)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (_playerToGameMap.ContainsKey(host.PlatformId))
			{
				return null;
			}
			string text = Guid.NewGuid().ToString("N").Substring(0, 5);
			PigGame value = new PigGame(text, host, targetScore);
			_activeGames[text] = value;
			_playerToGameMap[host.PlatformId] = text;
			return text;
		}

		public static bool JoinGame(string gameId, User player)
		{
			//IL_0005: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			if (_playerToGameMap.ContainsKey(player.PlatformId))
			{
				return false;
			}
			if (!_activeGames.TryGetValue(gameId, out var value))
			{
				return false;
			}
			if (!value.AddPlayer(player))
			{
				return false;
			}
			_playerToGameMap[player.PlatformId] = gameId;
			return true;
		}

		public static PigGame GetGameByPlayer(ulong playerId)
		{
			if (!_playerToGameMap.TryGetValue(playerId, out var value))
			{
				return null;
			}
			return _activeGames.GetValueOrDefault(value);
		}

		public static PigGame GetGameById(string gameId)
		{
			return _activeGames.GetValueOrDefault(gameId);
		}

		public static bool LeaveGame(ulong playerId)
		{
			if (!_playerToGameMap.TryGetValue(playerId, out var value))
			{
				return false;
			}
			if (!_activeGames.TryGetValue(value, out var value2))
			{
				return false;
			}
			value2.RemovePlayer(playerId);
			_playerToGameMap.Remove(playerId);
			if (value2.Players.Count <= 1)
			{
				EndGame(value);
			}
			return true;
		}

		public static bool EndGame(string gameId)
		{
			if (!_activeGames.TryGetValue(gameId, out var value))
			{
				return false;
			}
			foreach (PigPlayer player in value.Players)
			{
				_playerToGameMap.Remove(player.PlayerId);
			}
			return _activeGames.Remove(gameId);
		}

		public static PigRollResult Roll(ulong playerId)
		{
			PigGame gameByPlayer = GetGameByPlayer(playerId);
			if (gameByPlayer == null)
			{
				return new PigRollResult
				{
					IsValidMove = false,
					ErrorMessage = "No active game found."
				};
			}
			if (!gameByPlayer.IsPlayerTurn(playerId))
			{
				return new PigRollResult
				{
					IsValidMove = false,
					ErrorMessage = "It's not your turn!"
				};
			}
			int diceValue = DiceService.RollDie(6);
			return gameByPlayer.Roll(diceValue);
		}

		public static PigHoldResult Hold(ulong playerId)
		{
			PigGame gameByPlayer = GetGameByPlayer(playerId);
			if (gameByPlayer == null)
			{
				return new PigHoldResult
				{
					IsValidMove = false,
					ErrorMessage = "No active game found."
				};
			}
			if (!gameByPlayer.IsPlayerTurn(playerId))
			{
				return new PigHoldResult
				{
					IsValidMove = false,
					ErrorMessage = "It's not your turn!"
				};
			}
			return gameByPlayer.Hold();
		}

		public static List<PigGame> GetAllGames()
		{
			return _activeGames.Values.ToList();
		}
	}
	public class PigGame
	{
		public string GameId { get; }

		public List<PigPlayer> Players { get; private set; }

		public int CurrentPlayerIndex { get; private set; }

		public int TurnScore { get; private set; }

		public int TargetScore { get; }

		public bool IsGameStarted { get; private set; }

		public bool IsGameOver { get; private set; }

		public PigPlayer Winner { get; private set; }

		public DateTime CreatedAt { get; }

		public PigPlayer CurrentPlayer
		{
			get
			{
				if (!IsGameStarted || Players.Count <= 0)
				{
					return null;
				}
				return Players[CurrentPlayerIndex];
			}
		}

		public PigGame(string gameId, User host, int targetScore)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GameId = gameId;
			Players = new List<PigPlayer>();
			TargetScore = targetScore;
			CurrentPlayerIndex = 0;
			TurnScore = 0;
			IsGameStarted = false;
			IsGameOver = false;
			CreatedAt = DateTime.Now;
			AddPlayer(host);
		}

		public bool AddPlayer(User user)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (IsGameStarted || IsGameOver)
			{
				return false;
			}
			if (Players.Count >= Settings.PigMaxPlayers.Value)
			{
				return false;
			}
			if (Players.Any((PigPlayer p) => p.PlayerId == user.PlatformId))
			{
				return false;
			}
			Players.Add(new PigPlayer(user));
			return true;
		}

		public bool RemovePlayer(ulong playerId)
		{
			PigPlayer pigPlayer = Players.FirstOrDefault((PigPlayer p) => p.PlayerId == playerId);
			if (pigPlayer == null)
			{
				return false;
			}
			int num = Players.IndexOf(pigPlayer);
			Players.Remove(pigPlayer);
			if (IsGameStarted && num <= CurrentPlayerIndex && CurrentPlayerIndex > 0)
			{
				CurrentPlayerIndex--;
			}
			if (Players.Count > 0)
			{
				CurrentPlayerIndex %= Players.Count;
			}
			return true;
		}

		public bool StartGame()
		{
			if (IsGameStarted || Players.Count < Settings.PigMinPlayers.Value)
			{
				return false;
			}
			IsGameStarted = true;
			CurrentPlayerIndex = 0;
			TurnScore = 0;
			return true;
		}

		public bool IsPlayerTurn(ulong playerId)
		{
			if (IsGameStarted && !IsGameOver)
			{
				PigPlayer currentPlayer = CurrentPlayer;
				if (currentPlayer == null)
				{
					return false;
				}
				return currentPlayer.PlayerId == playerId;
			}
			return false;
		}

		public PigRollResult Roll(int diceValue)
		{
			if (!IsGameStarted || IsGameOver || CurrentPlayer == null)
			{
				return new PigRollResult
				{
					IsValidMove = false,
					ErrorMessage = "Game not in valid state."
				};
			}
			if (diceValue == 1)
			{
				TurnScore = 0;
				NextTurn();
				return new PigRollResult
				{
					IsValidMove = true,
					RollValue = 1,
					IsPig = true,
					TurnScore = 0,
					CurrentPlayer = CurrentPlayer,
					AllPlayers = Players.ToList(),
					IsGameOver = IsGameOver
				};
			}
			TurnScore += diceValue;
			return new PigRollResult
			{
				IsValidMove = true,
				RollValue = diceValue,
				IsPig = false,
				TurnScore = TurnScore,
				CurrentPlayer = CurrentPlayer,
				AllPlayers = Players.ToList(),
				IsGameOver = IsGameOver
			};
		}

		public PigHoldResult Hold()
		{
			if (!IsGameStarted || IsGameOver || CurrentPlayer == null)
			{
				return new PigHoldResult
				{
					IsValidMove = false,
					ErrorMessage = "Game not in valid state."
				};
			}
			if (TurnScore == 0)
			{
				return new PigHoldResult
				{
					IsValidMove = false,
					ErrorMessage = "No points to hold!"
				};
			}
			CurrentPlayer.TotalScore += TurnScore;
			int turnScore = TurnScore;
			TurnScore = 0;
			if (CurrentPlayer.TotalScore >= TargetScore)
			{
				IsGameOver = true;
				Winner = CurrentPlayer;
			}
			else
			{
				NextTurn();
			}
			return new PigHoldResult
			{
				IsValidMove = true,
				HeldPoints = turnScore,
				CurrentPlayer = CurrentPlayer,
				AllPlayers = Players.ToList(),
				IsGameOver = IsGameOver,
				Winner = Winner
			};
		}

		private void NextTurn()
		{
			if (Players.Count > 0)
			{
				CurrentPlayerIndex = (CurrentPlayerIndex + 1) % Players.Count;
			}
		}

		public User[] GetUsers()
		{
			return Players.Select((PigPlayer p) => p.user).ToArray();
		}
	}
	public class PigPlayer
	{
		public User user { get; }

		public ulong PlayerId { get; }

		public string PlayerName { get; }

		public int TotalScore { get; set; }

		public PigPlayer(User user)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			this.user = user;
			PlayerId = user.PlatformId;
			PlayerName = ((FixedString64Bytes)(ref user.CharacterName)).Value;
			TotalScore = 0;
		}
	}
	public class PigRollResult
	{
		public bool IsValidMove { get; set; }

		public string ErrorMessage { get; set; }

		public int RollValue { get; set; }

		public bool IsPig { get; set; }

		public int TurnScore { get; set; }

		public PigPlayer CurrentPlayer { get; set; }

		public List<PigPlayer> AllPlayers { get; set; }

		public bool IsGameOver { get; set; }
	}
	public class PigHoldResult
	{
		public bool IsValidMove { get; set; }

		public string ErrorMessage { get; set; }

		public int HeldPoints { get; set; }

		public PigPlayer CurrentPlayer { get; set; }

		public List<PigPlayer> AllPlayers { get; set; }

		public bool IsGameOver { get; set; }

		public PigPlayer Winner { get; set; }
	}
}
namespace CrimsonDice.Commands
{
	[CommandGroup("dice", null)]
	internal static class DiceCommands
	{
		[Command("Roll", "r", null, "Roll dice", null, false)]
		public static void Roll(ChatCommandContext ctx, string dies = "1d20")
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Invalid comparison between Unknown and I4
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Invalid comparison between Unknown and I4
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			ChatMessageType type = ctx.Event.Type;
			if (((object)(ChatMessageType)(ref type)).Equals((object)(ChatMessageType)3))
			{
				ctx.Reply("Dice rolling is not allowed in Whispers.");
				return;
			}
			if (((object)(ChatMessageType)(ref type)).Equals((object)(ChatMessageType)0) && !Settings.AllowInGlobal.Value)
			{
				ctx.Reply("Dice rolling is disabled in Global chat.");
				return;
			}
			if (!DiceService.ValidateHandOfDice(dies, out var die, out var amount))
			{
				ctx.Reply("Invalid dice format. Use the format '{count}d{dieSides}' from the follow options: d4, d6, d8, d10, d12, d20, d100");
				return;
			}
			int value = DiceService.RollDice(die, amount);
			User user = ctx.User;
			string text = $"{user.CharacterName} rolled {amount}d{die} = <color={Settings.ResultColor.Value}>{value}</color>.";
			if ((int)type != 0)
			{
				text = "[{channel.ToString()}] " + text;
				if ((int)type != 2)
				{
					if ((int)type == 4)
					{
						LocalToWorld val = EntityUtil.Read<LocalToWorld>(ctx.Event.SenderCharacterEntity);
						float3 position = ((LocalToWorld)(ref val)).Position;
						ChatUtil.SystemSendLocal(user, position, text);
					}
				}
				else
				{
					ChatUtil.SystemSendTeam(user, text);
				}
				ChatUtil.SystemSendUser(user, $"You rolled <color={Settings.ResultColor.Value}>{value}</color>.");
			}
			else
			{
				ChatUtil.SystemSendAll(text);
			}
			ctx.Event.Cancel();
		}
	}
	[CommandGroup("pig", null)]
	internal static class PigCommands
	{
		[Command("Create", null, null, "Create a new multiplayer Pig dice game", null, false)]
		public static void CreatePig(ChatCommandContext ctx, int targetScore = 100)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			ChatMessageType type = ctx.Event.Type;
			if (((object)(ChatMessageType)(ref type)).Equals((object)(ChatMessageType)3))
			{
				ctx.Reply("Pig game is not allowed in Whispers.");
				return;
			}
			if (targetScore < Settings.PigMinScore.Value || targetScore > Settings.PigMaxScore.Value)
			{
				ctx.Reply("Target score must be between 50 and 500.");
				return;
			}
			string text = PigGameService.CreateGame(ctx.User, targetScore);
			if (text == null)
			{
				ctx.Reply("You're already in a Pig game. Use '.pig leave' to leave it first.");
				return;
			}
			ctx.Reply($"Created Pig game <color={Settings.ResultColor.Value}>{text}</color>! Target: {targetScore}. Others can join with '.pig join {text}'. Start with '.pig start' when ready.");
			ctx.Event.Cancel();
		}

		[Command("Join", null, null, "Join an existing Pig game", null, false)]
		public static void JoinPig(ChatCommandContext ctx, string gameId)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			ChatMessageType type = ctx.Event.Type;
			if (((object)(ChatMessageType)(ref type)).Equals((object)(ChatMessageType)3))
			{
				ctx.Reply("Pig game is not allowed in Whispers.");
				return;
			}
			if (string.IsNullOrEmpty(gameId))
			{
				ctx.Reply("Please specify a game ID. Usage: .pig join <gameId>");
				return;
			}
			User user = ctx.User;
			if (!PigGameService.JoinGame(gameId, user))
			{
				ctx.Reply("Could not join game. Game might be full, already started, or you're already in a game.");
				return;
			}
			PigGame gameById = PigGameService.GetGameById(gameId);
			if (gameById != null)
			{
				string value = string.Join(", ", gameById.Players.Select((PigPlayer p) => p.PlayerName));
				SendToGamePlayers(gameById, $"{user.CharacterName} joined the game! Players ({gameById.Players.Count}/6): {value}");
			}
			ctx.Event.Cancel();
		}

		[Command("Start", null, null, "Start the Pig game (host only)", null, false)]
		public static void StartPig(ChatCommandContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			User user = ctx.User;
			PigGame gameByPlayer = PigGameService.GetGameByPlayer(user.PlatformId);
			if (gameByPlayer == null)
			{
				ctx.Reply("You're not in a Pig game. Use '.pig create' to create one.");
				return;
			}
			if (gameByPlayer.Players[0].PlayerId != user.PlatformId)
			{
				ctx.Reply("Only the game host can start the game.");
				return;
			}
			if (gameByPlayer.Players.Count < Settings.PigMinPlayers.Value)
			{
				ctx.Reply($"Need at least {Settings.PigMinPlayers.Value} players to start the game.");
				return;
			}
			if (!gameByPlayer.StartGame())
			{
				ctx.Reply("Could not start game. It may already be started.");
				return;
			}
			string value = string.Join(", ", gameByPlayer.Players.Select((PigPlayer p) => p.PlayerName));
			SendToGamePlayers(gameByPlayer, $"Pig game started! Players: {value}. Target: <color={Settings.ResultColor.Value}>{gameByPlayer.TargetScore}</color>");
			SendToGamePlayers(gameByPlayer, $"It's <color={Settings.ResultColor.Value}>{gameByPlayer.CurrentPlayer.PlayerName}</color>'s turn! Use '.pig roll' to roll or '.pig hold' to bank points.");
			ctx.Event.Cancel();
		}

		[Command("Roll", "r", null, "Roll the dice in your Pig game", null, false)]
		public static void RollPig(ChatCommandContext ctx)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			ChatMessageType type = ctx.Event.Type;
			if (((object)(ChatMessageType)(ref type)).Equals((object)(ChatMessageType)3))
			{
				ctx.Reply("Pig game is not allowed in Whispers.");
				return;
			}
			User user = ctx.User;
			PigRollResult pigRollResult = PigGameService.Roll(user.PlatformId);
			if (!pigRollResult.IsValidMove)
			{
				ctx.Reply(pigRollResult.ErrorMessage ?? "Could not roll dice.");
				return;
			}
			PigGame gameByPlayer = PigGameService.GetGameByPlayer(user.PlatformId);
			if (gameByPlayer == null)
			{
				return;
			}
			string text;
			if (pigRollResult.IsPig)
			{
				text = $"{user.CharacterName} rolled a <color=#FF0000>1</color> - PIG! Turn ends with 0 points.";
				if (!pigRollResult.IsGameOver && pigRollResult.CurrentPlayer != null)
				{
					text += $"\n\nIt's <color={Settings.ResultColor.Value}>{pigRollResult.CurrentPlayer.PlayerName}</color>'s turn!";
				}
			}
			else
			{
				text = $"{user.CharacterName} rolled <color={Settings.ResultColor.Value}>{pigRollResult.RollValue}</color>! Turn total: <color={Settings.ResultColor.Value}>{pigRollResult.TurnScore}</color>";
			}
			SendToGamePlayers(gameByPlayer, text);
			ctx.Event.Cancel();
		}

		[Command("Hold", "h", null, "Hold and bank your turn score", null, false)]
		public static void HoldPig(ChatCommandContext ctx)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			ChatMessageType type = ctx.Event.Type;
			if (((object)(ChatMessageType)(ref type)).Equals((object)(ChatMessageType)3))
			{
				ctx.Reply("Pig game is not allowed in Whispers.");
				return;
			}
			User user = ctx.User;
			PigHoldResult pigHoldResult = PigGameService.Hold(user.PlatformId);
			if (!pigHoldResult.IsValidMove)
			{
				ctx.Reply(pigHoldResult.ErrorMessage ?? "Could not hold points.");
				return;
			}
			PigGame gameByPlayer = PigGameService.GetGameByPlayer(user.PlatformId);
			if (gameByPlayer == null)
			{
				return;
			}
			if (pigHoldResult.IsGameOver && pigHoldResult.Winner != null)
			{
				string message = $"{user.CharacterName} held <color={Settings.ResultColor.Value}>{pigHoldResult.HeldPoints}</color> points and WON with <color={Settings.ResultColor.Value}>{pigHoldResult.Winner.TotalScore}</color> points!";
				SendToGamePlayers(gameByPlayer, message);
				PigGameService.EndGame(gameByPlayer.GameId);
			}
			else
			{
				PigPlayer pigPlayer = pigHoldResult.AllPlayers?.FirstOrDefault((PigPlayer p) => p.PlayerId == user.PlatformId);
				string message = $"{user.CharacterName} held <color={Settings.ResultColor.Value}>{pigHoldResult.HeldPoints}</color> points! Total: <color={Settings.ResultColor.Value}>{pigPlayer?.TotalScore ?? 0}</color>";
				if (pigHoldResult.CurrentPlayer != null)
				{
					message += $"\n\nIt's <color={Settings.ResultColor.Value}>{pigHoldResult.CurrentPlayer.PlayerName}</color>'s turn!";
				}
				SendToGamePlayers(gameByPlayer, message);
			}
			ctx.Event.Cancel();
		}

		[Command("Status", "s", null, "Check current Pig game status", null, false)]
		public static void StatusPig(ChatCommandContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			PigGame gameByPlayer = PigGameService.GetGameByPlayer(ctx.User.PlatformId);
			if (gameByPlayer == null)
			{
				ctx.Reply("You're not in a Pig game. Use '.pig create' to create one or '.pig join <gameId>' to join.");
				return;
			}
			if (!gameByPlayer.IsGameStarted)
			{
				string value = string.Join(", ", gameByPlayer.Players.Select((PigPlayer p) => p.PlayerName));
				ctx.Reply($"Game <color={Settings.ResultColor.Value}>{gameByPlayer.GameId}</color> waiting to start. Players ({gameByPlayer.Players.Count}/6): {value}");
				return;
			}
			string text = "<b>Pig Game Status</b>\n";
			text += $"Game ID: <color={Settings.ResultColor.Value}>{gameByPlayer.GameId}</color> | Target: <color={Settings.ResultColor.Value}>{gameByPlayer.TargetScore}</color>\n";
			if (gameByPlayer.CurrentPlayer != null)
			{
				text += $"Current Turn: <color={Settings.ResultColor.Value}>{gameByPlayer.CurrentPlayer.PlayerName}</color> (Turn Points: {gameByPlayer.TurnScore})\n\n";
			}
			text += "<b><u>Scores:</u></b>\n";
			foreach (PigPlayer player in gameByPlayer.Players)
			{
				string text2 = $"\n• {player.PlayerName}: <color={Settings.ResultColor.Value}>{player.TotalScore}</color>";
				if (gameByPlayer.CurrentPlayer?.PlayerId == player.PlayerId)
				{
					text2 += " ← Current Turn";
				}
				text += text2;
			}
			SendToGamePlayers(gameByPlayer, text);
			ctx.Event.Cancel();
		}

		[Command("Leave", null, null, "Leave your current Pig game", null, false)]
		public static void LeavePig(ChatCommandContext ctx)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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)
			User user = ctx.User;
			PigGame gameByPlayer = PigGameService.GetGameByPlayer(user.PlatformId);
			if (gameByPlayer == null)
			{
				ctx.Reply("You're not in a Pig game.");
				return;
			}
			string gameId = gameByPlayer.GameId;
			bool flag = gameByPlayer.CurrentPlayer?.PlayerId == user.PlatformId;
			if (!PigGameService.LeaveGame(user.PlatformId))
			{
				ctx.Reply("Could not leave the game.");
				return;
			}
			PigGame gameById = PigGameService.GetGameById(gameId);
			if (gameById != null)
			{
				string text = $"{user.CharacterName} left the game.";
				if (flag && gameById.CurrentPlayer != null)
				{
					text += $" It's now <color={Settings.ResultColor.Value}>{gameById.CurrentPlayer.PlayerName}</color>'s turn!";
				}
				SendToGamePlayers(gameById, text);
			}
			ctx.Reply("You left the Pig game.");
			ctx.Event.Cancel();
		}

		[Command("List", null, null, "List all active Pig games", null, false)]
		public static void ListPig(ChatCommandContext ctx)
		{
			List<PigGame> list = (from g in PigGameService.GetAllGames()
				where !g.IsGameStarted && !g.IsGameOver
				select g).ToList();
			if (!list.Any())
			{
				ctx.Reply("No open Pig games available. Use '.pig create' to start one!");
				return;
			}
			string text = "<b>Open Pig Games:</b>\n";
			foreach (PigGame item in list)
			{
				string value = string.Join(", ", item.Players.Select((PigPlayer p) => p.PlayerName));
				text += $"\n• <color={Settings.ResultColor.Value}>{item.GameId}</color> - {item.Players.Count}/6 players ({value}) - Target: {item.TargetScore}";
			}
			text += "\n\nUse '.pig join <gameId>' to join a game!";
			ctx.Reply(text);
			ctx.Event.Cancel();
		}

		private static void SendToGamePlayers(PigGame game, string message)
		{
			User[] users = game.GetUsers();
			if (users.Length != 0)
			{
				ChatUtil.SystemSendUsers(users, "[Pig] " + message);
			}
		}
	}
}