using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DnDUtil.Core;
using DnDUtil.Core.Commands;
using DnDUtil.Patches;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PurrNet;
using UnityEngine;
using UnityEngine.EventSystems;
[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("AndrewLin.DnDUtil")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Dungeons and Dragons mod for On-Together.")]
[assembly: AssemblyFileVersion("0.0.5.0")]
[assembly: AssemblyInformationalVersion("0.0.5+cf998f8f6bf87cfb7b80c18d4a122a93e0075215")]
[assembly: AssemblyProduct("AndrewLin.DnDUtil")]
[assembly: AssemblyTitle("AndrewLin.DnDUtil")]
[assembly: AssemblyVersion("0.0.5.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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;
}
}
}
public static class ChatUtils
{
public static void AddGlobalNotification(string text)
{
NetworkSingleton<TextChannelManager>.I.AddNotification(text);
}
public static string GetUserName()
{
return NetworkSingleton<TextChannelManager>.I.UserName;
}
public static void SendMessageAsync(string userName, string text, bool Islocal = false)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
Transform mainPlayer = i.MainPlayer;
byte[] bytes = Encoding.Unicode.GetBytes(text.Substring(0, Math.Min(text.Length, 250)));
byte[] bytes2 = Encoding.Unicode.GetBytes(userName);
string text2 = Traverse.Create((object)i).Field<string>("_playerId").Value ?? "0";
i.SendMessageAsync(bytes, bytes2, Islocal, mainPlayer.position, text2, default(RPCInfo));
}
public static void CleanCommand()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
LockState lockState = (LockState)(NetworkSingleton<MusicManager>.I.IsActive ? 5 : 0);
MonoSingleton<TaskManager>.I.SetLockState(lockState);
EventSystem.current.SetSelectedGameObject((GameObject)null);
string text = MonoSingleton<UIManager>.I.MessageInput.text;
if (!text.StartsWith("/help") || text == "/help dnd")
{
MonoSingleton<UIManager>.I.MessageInput.text = "";
}
}
}
namespace DnDUtil
{
public static class BuildInfo
{
public const string Version = "0.0.5";
}
[BepInPlugin("com.andrewlin.ontogether.dndmod", "DnDUtil", "0.0.5")]
public class Plugin : BaseUnityPlugin
{
public const string DefaultAnnouncerChatName = "DnDSystem";
public const string ModGUID = "com.andrewlin.ontogether.dndmod";
public const string ModName = "DnDUtil";
public const string ModVersion = "0.0.5";
public static ConfigEntry<bool>? EnableFeature { get; private set; }
public static ConfigEntry<bool>? ShowCommand { get; private set; }
public static ConfigEntry<string>? AnnouncerArea { get; private set; }
public static ConfigEntry<string>? AnnouncerChatName { get; private set; }
public static string? PlayerId { get; private set; }
public static CommandManager? CommandProcessor { get; private set; }
private void Awake()
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
((BaseUnityPlugin)this).Logger.LogInfo((object)"DnDUtil v0.0.5 is loaded!");
new Harmony("com.andrewlin.ontogether.dndmod").PatchAll(typeof(TextChannelManagerPatch));
InitConfig();
CommandProcessor = new CommandManager();
}
private void InitConfig()
{
EnableFeature = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFeature", true, "Enable or disable the DnD utility features.");
ShowCommand = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCommand", false, "Show the command in chat when used.");
AnnouncerChatName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "AnnouncerChatName", "DnDSystem", "The chat name to use when announcing rolls. Default is 'DnDSystem'.");
AnnouncerArea = ((BaseUnityPlugin)this).Config.Bind<string>("General", "AnnouncerArea", "self", "The area to use when announcing rolls [self|local|global]. Default is 'self'.");
}
}
}
namespace DnDUtil.Patches
{
[HarmonyPatch(typeof(TextChannelManager))]
public class TextChannelManagerPatch
{
[HarmonyPatch("OnEnterPressed")]
[HarmonyPrefix]
public static void OnEnterPressedPrefix()
{
string text = MonoSingleton<UIManager>.I.MessageInput.text;
if (!string.IsNullOrEmpty(text) && text.StartsWith('/') && Plugin.EnableFeature != null && (Plugin.EnableFeature.Value || text.Contains("usedndfeature")))
{
bool flag = Plugin.CommandProcessor?.ProcessInput(text) ?? false;
ConfigEntry<bool>? showCommand = Plugin.ShowCommand;
if (showCommand != null && !showCommand.Value && flag)
{
ChatUtils.CleanCommand();
}
}
}
}
}
namespace DnDUtil.Core
{
public class CommandArgs
{
public static readonly CommandArgs EMPTY = new CommandArgs("", new string[0]);
public string Name { get; }
public string[] Args { get; }
public CommandArgs(string name, string[] args)
{
Name = name;
Args = args;
}
public static bool TryParse(string input, out CommandArgs result)
{
if (string.IsNullOrWhiteSpace(input) || !input.StartsWith('/'))
{
result = EMPTY;
return false;
}
string text = input.Trim();
string[] array = text.Substring(1, text.Length - 1).Split(' ', StringSplitOptions.RemoveEmptyEntries);
string name = array[0].ToLower();
string[] args = array.Skip(1).ToArray();
result = new CommandArgs(name, args);
return true;
}
public override string ToString()
{
return "/" + Name + " " + string.Join(' ', Args);
}
}
public class CommandManager
{
private readonly ManualLogSource log = Logger.CreateLogSource("DnDUtil.CommandManager");
private readonly Dictionary<string, IChatCommand> commands;
public CommandManager()
{
IEnumerable<Type> enumerable = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IChatCommand).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract
select t;
commands = new Dictionary<string, IChatCommand>();
foreach (Type item in enumerable)
{
if (Activator.CreateInstance(item) is IChatCommand chatCommand)
{
commands[chatCommand.Name] = chatCommand;
commands[chatCommand.ShortName] = chatCommand;
log.LogInfo((object)("Loaded /" + chatCommand.Name + " (/" + chatCommand.ShortName + ")"));
}
}
InitializeHelpCommand(commands);
}
private static void InitializeHelpCommand(Dictionary<string, IChatCommand> commands)
{
if (commands.TryGetValue("help", out IChatCommand value))
{
(value as HelpCommand)?.Initialize(commands.Values);
}
}
public bool ProcessInput(string input)
{
if (!CommandArgs.TryParse(input, out CommandArgs result))
{
return false;
}
if (commands.TryGetValue(result.Name, out IChatCommand value))
{
try
{
value.Execute(result.Args);
}
catch (Exception ex)
{
ChatUtils.AddGlobalNotification($"Error executing '{result}': {ex.Message}");
}
return true;
}
return false;
}
}
}
namespace DnDUtil.Core.Commands
{
public class HelpCommand : IChatCommand, IComparable<IChatCommand>
{
public const string CMD = "help";
private SortedSet<IChatCommand>? commands;
public string Name => "help";
public string ShortName => "h";
public string Description => "Lists all available commands.";
public void Initialize(IEnumerable<IChatCommand> values)
{
commands = new SortedSet<IChatCommand>(values);
}
public void Execute(string[] args)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("/help dnd for DnD commands");
}
else
{
if (!(args[0] == "dnd"))
{
return;
}
if (commands != null)
{
ChatUtils.AddGlobalNotification("DnDUtil Version (0.0.5).");
ChatUtils.AddGlobalNotification("thunderstore.io/c/on-together/p/AndrewLin/AndrewLin_DnDUtil");
ChatUtils.AddGlobalNotification("Available commands:");
{
foreach (IChatCommand command in commands)
{
ChatUtils.AddGlobalNotification("/" + command.Name + " (/" + command.ShortName + ") :: " + command.Description);
}
return;
}
}
ChatUtils.AddGlobalNotification("No commands available!");
}
}
}
public interface IChatCommand : IComparable<IChatCommand>
{
string Name { get; }
string ShortName => "";
string Description { get; }
void Execute(string[] args);
new string ToString()
{
return Name;
}
int IComparable<IChatCommand>.CompareTo(IChatCommand? other)
{
if (other == null)
{
return 1;
}
return string.Compare(Name, other.Name, StringComparison.Ordinal);
}
}
public class RollCommand : IChatCommand, IComparable<IChatCommand>
{
public string Name => "roll";
public string ShortName => "r";
public string Description => "Rolls a dice. E.g. '/roll 2d20 1d6' rolls 2 20-sided dice and 1 6-sided die.";
public void Execute(string[] args)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /roll [XdY] - Rolls X dice with Y sides. Example: /roll 2d20");
return;
}
foreach (string text in args)
{
try
{
List<int> values = DiceTokenToNumber(text);
string text2 = string.Join(", ", values);
string userName = ChatUtils.GetUserName();
string text3 = userName + " rolled " + text + ": " + text2;
string userName2 = Plugin.AnnouncerChatName?.Value ?? "DnDSystem";
if (Plugin.AnnouncerArea?.Value == "self")
{
ChatUtils.AddGlobalNotification(text3);
}
else if (Plugin.AnnouncerArea?.Value == "local")
{
ChatUtils.SendMessageAsync(userName2, text3, Islocal: true);
}
else if (Plugin.AnnouncerArea?.Value == "global")
{
ChatUtils.SendMessageAsync(userName2, text3);
}
}
catch (ArgumentException ex)
{
ChatUtils.AddGlobalNotification(ex.Message);
}
}
}
public static List<int> DiceTokenToNumber(string token)
{
if (!token.Contains('d'))
{
throw new ArgumentException("Invalid format '" + token + "'. Use XdY, e.g. 2d20.");
}
if (token.StartsWith('d'))
{
token = "1" + token;
}
string[] array = token.Split('d');
if (array.Length != 2 || !int.TryParse(array[0], out var result) || !int.TryParse(array[1], out var result2))
{
throw new ArgumentException("Invalid format '" + token + "'. Use XdY, e.g. 2d20.");
}
Random random = new Random();
List<int> list = new List<int>();
for (int i = 0; i < result; i++)
{
list.Add(random.Next(1, result2 + 1));
}
return list;
}
}
public class SetAnnouncerAreaCommand : IChatCommand, IComparable<IChatCommand>
{
public static readonly HashSet<string> ValidAreas = new HashSet<string> { "self", "local", "global" };
public static readonly string ValidAreasText = string.Join("|", ValidAreas);
public const string CMD = "setannouncerarea";
public string Name => "setannouncerarea";
public string ShortName => "saa";
public string Description => "Set the area to use when announcing rolls: [" + ValidAreasText + "]. Current: " + (Plugin.AnnouncerArea?.Value ?? "self");
public void Execute(string[] args)
{
if (Plugin.AnnouncerArea == null)
{
return;
}
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /setannouncerarea [" + ValidAreasText + "] - Sets the area to use when announcing rolls.");
return;
}
string text = args[0].ToLower();
if (!ValidAreas.Contains(text))
{
ChatUtils.AddGlobalNotification("Invalid announcer area. Valid areas are: [" + ValidAreasText + "].");
return;
}
Plugin.AnnouncerArea.Value = text;
ChatUtils.AddGlobalNotification("Announcer area is now set to " + Plugin.AnnouncerArea.Value + ".");
}
}
public class SetAnnouncerNameCommand : IChatCommand, IComparable<IChatCommand>
{
public const string CMD = "setannouncername";
public string Name => "setannouncername";
public string ShortName => "san";
public string Description => "Set the name to use when sending messages to chat. Current: " + (Plugin.AnnouncerChatName?.Value ?? "DnDSystem");
public void Execute(string[] args)
{
if (Plugin.AnnouncerChatName != null)
{
if (args.Length == 0)
{
ChatUtils.AddGlobalNotification("Usage: /setchatname [name] - Sets the name to use when sending messages to chat.");
return;
}
Plugin.AnnouncerChatName.Value = args[0];
ChatUtils.AddGlobalNotification("Chat name is now set to " + Plugin.AnnouncerChatName.Value + ".");
}
}
}
public class ShowDndCommand : IChatCommand, IComparable<IChatCommand>
{
public const string CMD = "showdndcommand";
public string Name => "showdndcommand";
public string ShortName => "sdc";
public string Description
{
get
{
ConfigEntry<bool>? showCommand = Plugin.ShowCommand;
return "Toggle DnDUtil show/hide DnD command in chat.If enabled, user command such as '/roll' will be shown in chat. Current: " + ((showCommand != null && showCommand.Value) ? "shown" : "hidden");
}
}
public void Execute(string[] args)
{
if (Plugin.ShowCommand != null)
{
Plugin.ShowCommand.Value = !Plugin.ShowCommand.Value;
ChatUtils.AddGlobalNotification("DnD user command is now " + (Plugin.ShowCommand.Value ? "shown" : "hidden") + ".");
}
}
}
public class UseDndFeatureCommand : IChatCommand, IComparable<IChatCommand>
{
public const string CMD = "usedndfeature";
public string Name => "usedndfeature";
public string ShortName => "udf";
public string Description => "Toggle DnDUtil feature on/off. ";
public void Execute(string[] args)
{
if (Plugin.EnableFeature != null)
{
Plugin.EnableFeature.Value = !Plugin.EnableFeature.Value;
ChatUtils.AddGlobalNotification("DnD feature is now " + (Plugin.EnableFeature.Value ? "enabled" : "disabled") + ".");
}
}
}
}