Иконка ресурса

FREE PoundBot : 2.0.0 2.0.0

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Oxide.Plugins
{
  [Info("Pound Bot", "MrPoundsign", "2.0.0")]
  [Description("Connector for the Discord bot PoundBot.")]

  class PoundBot : CovalencePlugin
  {
    const string EntityDeathURI = "/entity_death";
    const string ApiMessageBaseURI = "/messages";
    const string ApiRolesURI = "/roles";
    const string ApiChatURI = "/chat";
    const string ApiRegisteredPlayersURI = "/players/registered";
    const string ApiDiscordAuthURI = "/discord_auth";
    const string ApiClansURI = "/clans";

    private string ApiBaseURI;

    enum DebugLevels { TRACE, INFO };

    protected string DebugURI = "";
    protected int DebugLevel = (int)DebugLevels.INFO;
    protected int ApiRetrySeconds = 1;
    protected int ApiRetryNotify = 30;

    protected string RegisteredUsersGroup;
    protected bool ApiInError;
    protected bool ApiRetry;
    protected uint ApiRetryAttempts;
    protected DateTime ApiErrorTime;
    protected DateTime LastApiAttempt;
    private Dictionary<string, string> RequestHeaders;
    protected bool RegisteredUsersInFlight;
    private ChannelList KnownChannelList;

    class ApiErrorResponse
    {
      public string Error;
    }

    class ApiRequest
    {
      public RequestMethod Method;
      public string URI;
      public string Body;
      public Plugin Plugin;
      public string RequestUUID;

      public ApiRequest(RequestMethod method, string uri, string body, Plugin plugin)
      {
        Method = method;
        URI = uri;
        Body = body;
        Plugin = plugin;
        RequestUUID = Guid.NewGuid().ToString();
      }
    }

    #region PoundBot messages
    class Channel
    {
      public string ID;
      public string Name;
      public bool CanSend;
      public bool CanStyle;

      public bool IsAvailable()
      {
        return CanSend || CanStyle;
      }
    }

    class ChannelList
    {
      public Channel[] Channels;

      public bool CanSendTo(string channel)
      {
        foreach (Channel chan in Channels)
        {
          if (chan.Name == channel || chan.ID == channel)
          {
            return chan.CanSend;
          }
        }
        return false;
      }

      public bool CanStyleTo(string channel)
      {
        foreach (Channel chan in Channels)
        {
          if (chan.Name == channel || chan.ID == channel)
          {
            return chan.CanStyle;
          }
        }
        return false;
      }
    }

    class DiscordAuth
    {
      public string PlayerID;
      public string DisplayName;
      public string ClanTag;
      public string DiscordName;
      public int Pin;
      public DateTime CreatedAt;

      public DiscordAuth(string displayName, string discordName, string playerid)
      {
        Pin = new System.Random().Next(1, 9999);
        DisplayName = displayName;
        DiscordName = discordName;
        PlayerID = playerid;
        CreatedAt = DateTime.UtcNow;
      }
    }

    public class GameMessageEmbedStyle
    {
      public string Color { get; set; }
    }

    class GameMessagePart
    {
      public string Content { get; set; }
      public bool Escape { get; set; }
    }

    class GameMessage
    {
      public GameMessagePart[] MessageParts { get; set; }
      public int Type { get; set; } // 0 = plain, 1 = embedded
      public GameMessageEmbedStyle EmbedStyle { get; set; }
    }

    class RoleSyncRequest
    {
      public string GuildID;
      public string[] PlayerIDs;
    }

    class EntityDeath
    {
      public string Name;
      public string GridPos;
      public string[] OwnerIDs;
      public DateTime CreatedAt;

      public EntityDeath(string name, string gridpos, string[] ownerIDs)
      {
        Name = name;
        GridPos = gridpos;
        OwnerIDs = ownerIDs;
        CreatedAt = DateTime.UtcNow;
      }
    }
    #endregion

    #region Configuration
    protected override void LoadDefaultConfig()
    {
      Config["api.url"] = "https://api.poundbot.com/";
      Config["api.key"] = "API KEY HERE";
      Config["config.version"] = 2;
      Config["players.registered.group"] = "poundbot.registered";
    }

    void UpgradeConfig()
    {
      string configVersion = "config.version";
      bool dirty = false;

      if (Config[configVersion] == null)
      {
        Config[configVersion] = 1;
      }
      else
      {
        try
        {
          var foo = (string)Config[configVersion];
          Config[configVersion] = 2;
          dirty = true;
        }
        catch (InvalidCastException) { } // testing if it can be converted to a string or not. No need to change it because it's not a string.
      }

      if ((int)Config[configVersion] < 2)
      {
        LogWarning(string.Format(lang.GetMessage("config.upgrading", this), "1.1.2"));

        // Update the API endpoint
        string api_url = (string)Config["api_url"];
        if (api_url == "http://poundbot.mrpoundsign.com/" || api_url == "http://api.poundbot.com/")
        {
          Config["api.url"] = "https://api.poundbot.com/";
        }
        else
        {
          Config["api.url"] = (string)Config["api_url"];
        }
        Config["api.key"] = (string)Config["api_key"];
        Config.Remove("api_url");
        Config.Remove("api_key");
        Config["players.registered.group"] = "poundbot.registered";
        Config[configVersion] = 2;
        dirty = true;
      }

      if (dirty)
      {
        SaveConfig();
      }
    }
    #endregion

    #region Language
    protected override void LoadDefaultMessages()
    {
      lang.RegisterMessages(new Dictionary<string, string>
      {
        ["config.upgrading"] = "Upgrading config to v{0}",
        ["config.api_key_updated"] = "Your API key has been updated. Check config/PoundBot.json.",
        ["command.poundbot_register"] = "pbreg",
        ["connector.reconnected"] = "Reconnected with PoundBot",
        ["connector.time_in_error"] = "Total time in error: {0}",
        ["connector.error"] = "Error communicating with PoundBot: {0}:{1}",
        ["connector.error_with_rid"] = "Error communicating with PoundBot: [{0}] {1}:{2}",
        ["connector.user_error"] = "Cannot connect to PoundBot right now. Please alert the admins.",
        ["discord.pin"] = "Enter the following PIN to the bot in discord: {0}.",
        ["discord.connected"] = "You are registered.",
        ["discord.already_connected"] = "You are already registered.",
        ["discord.not_connected"] = "Registration not found.",
        ["discord.channels_updated"] = "Channel cache updated.",
        ["discord.channel_cannot_send"] = "Cannot send to channel {0}. Please check that the bot can send to this channel. Run pb.updatechannels after making Discord changes to update the cache.",
        ["discord.channel_cannot_style"] = "Cannot send to channel {0}. Please check that the bot can embed links to this channel. Run pb.updatechannels after making Discord changes to update the cache.",
        ["usage.pbreg"] = "Usage: /pbreg \"<discord name>\"\n Example: /discord \"Fancy Guy#8080\"",
        ["usage.set_api_key"] = "Usage:\n\tpb.set_api_key <api key>",
        ["discord.console.registration_attempt"] = "Player {0}({1}) attempting to register as {2}",
      }, this);
    }

    #endregion

    #region Oxide API
    void Init()
    {
      UpgradeConfig();
      ApiBaseURI = $"{Config["api.url"]}api";
      ApplyConfig();

      RegisteredUsersGroup = (string)Config["players.registered.group"];
      permission.RegisterPermission(RegisteredUsersGroup, this);
      if (!permission.GroupExists(RegisteredUsersGroup))
      {
        permission.CreateGroup(RegisteredUsersGroup, "PoundBot Registered Users", 0);
      }

      AddLocalizedCommand("command.poundbot_register", "CommandPoundBotRegister");

      Connected();

      timer.Every(5f, () =>
      {
        if (RegisteredUsersInFlight) return;
        RegisteredUsersInFlight = true;
        Request(new ApiRequest(RequestMethod.GET, ApiRegisteredPlayersURI, null, this),
        (code, response) =>
        {
          RegisteredUsersInFlight = false;
          if (code == 200)
          {
            string[] groupPlayerIDs = permission.GetUsersInGroup(RegisteredUsersGroup);
            string[] playerIDs = JsonConvert.DeserializeObject<string[]>(response);

            for (int i = 0; i < groupPlayerIDs.Length; i++)
            {
              groupPlayerIDs[i] = groupPlayerIDs[i].Substring(0, groupPlayerIDs[i].IndexOf(' '));
            }

            // hot group diff action
            string[] playersToRemove = groupPlayerIDs.Except(playerIDs).ToArray();
            string[] playersToAdd = playerIDs.Except(groupPlayerIDs).ToArray();

            if (playersToAdd.Length + playersToRemove.Length == 0)
            {
              return true;
            }

            foreach (string id in playersToRemove)
            {
              Puts($"Removing user {id} from {RegisteredUsersGroup}");
              permission.RemoveUserGroup(id, RegisteredUsersGroup);
            }

            foreach (string id in playersToAdd)
            {
              Puts($"Adding user {id} to {RegisteredUsersGroup}");
              permission.AddUserGroup(id, RegisteredUsersGroup);
            }
            return true;
          }

          Puts("Unuccessful registered players get");
          Puts(response);
          return false;
        });
      });
    }
    #endregion

    private void ApplyConfig()
    {
      RequestHeaders = new Dictionary<string, string>
      {
        ["Content-type"] = "application/json",
        ["Authorization"] = $"Token {Config["api.key"]}",
        ["X-PoundBotConnector-Version"] = Version.ToString(),
        ["User-Agent"] = $"PoundBotConnector/{Version.ToString()}",
        ["X-PoundBot-Game"] = covalence.Game.ToLower()
      };
    }

    #region API

    // private Dictionary<string, string> Headers() => RequestHeaders;

    private string API_RegisteredUsersGroup() => RegisteredUsersGroup;

    private string ApiBase() => ApiBaseURI;

    private bool ApiRequestOk()
    {
      if (ApiInError && !ApiRetry && (LastApiAttempt.AddSeconds(ApiRetrySeconds) < DateTime.Now))
      {
        ApiRetryAttempts++;
        if (ApiRetryAttempts == 1 || ApiRetryAttempts % ApiRetryNotify == 0)
        {
          Puts(string.Format(lang.GetMessage("connector.time_in_error", this), DateTime.Now.Subtract(ApiErrorTime)));
        }
        ApiRetry = true;
      }
      return (!ApiInError || ApiRetry);
    }

    private void ApiError(int code, string response, string requestID = null)
    {
      string error;
      if (ApiInError)
      {
        if (ApiRetry)
        {
          LastApiAttempt = DateTime.Now;
          ApiRetry = false;
        }

        if (ApiRetryAttempts % ApiRetryNotify != 0) return;
      }
      else
      {
        ApiErrorTime = DateTime.Now;
        LastApiAttempt = DateTime.Now;
        ApiInError = true;
        ApiRetry = false;
      }

      if (code == 0)
      {
        error = "Connection Failure!";
      }
      else
      {
        try
        {
          var air = JsonConvert.DeserializeObject<ApiErrorResponse>(response);
          error = air.Error;
        }
        catch
        {
          error = response;
        }
      }
      if (code == 0)
      {
        Puts(string.Format(lang.GetMessage("connector.error", this), code, error));
        return;
      }
      Puts(string.Format(lang.GetMessage("connector.error_with_rid", this), requestID, code, error));

    }

    private bool ApiSuccess(bool success)
    {
      // Reset retry variables if we're successful
      if (ApiInError && success)
      {
        Puts(lang.GetMessage("connector.reconnected", this));
        Puts(string.Format(lang.GetMessage("connector.time_in_error", this), DateTime.Now.Subtract(ApiErrorTime)));
        ApiRetryAttempts = 0;
        ApiInError = false;
        ApiRetry = true;
        Connected();
      }
      return success;
    }

    #region Requests

    private bool Request(ApiRequest api_request, Func<int, string, bool> callback)
    {
      if (!ApiRequestOk()) return false;

      if (DebugURI != "" && api_request.URI.StartsWith(DebugURI))
      {
        Puts($"Request from {api_request.Plugin.Name} to {api_request.URI} with RequestUUID {api_request.RequestUUID}");
      }

      if (api_request.Plugin == null)
      {
        api_request.Plugin = this;
      }

      Dictionary<string, string> rHeaders = new Dictionary<string, string>(RequestHeaders);
      rHeaders["X-Request-ID"] = api_request.RequestUUID;

      webrequest.Enqueue($"{ApiBaseURI}{api_request.URI}", api_request.Body,
      (code, response) =>
      {
        if (!ApiSuccess(callback(code, response)))
        {
          ApiError(code, response, rHeaders["X-Request-ID"]);
        }
      },
      api_request.Plugin, api_request.Method, rHeaders, 12000f);

      return true;
    }
    // Returns true if request was sent, false otherwise.
    private bool API_Request(string uri, string body, Func<int, string, bool> callback, Plugin owner, RequestMethod method = RequestMethod.GET, Dictionary<string, string> headers = null)
    {
      return Request(new ApiRequest(method, uri, body, this), callback);
    }
    #endregion

    #region Messages API
    private bool API_SendChannelMessage(Plugin owner, string channel, KeyValuePair<string, bool>[] message_parts, string embed_color = null, Func<int, string, bool> callback = null, Dictionary<string, string> headers = null, string type = "plain")
    {
      List<GameMessagePart> parts = new List<GameMessagePart>();

      foreach (KeyValuePair<string, bool> part in message_parts)
      {
        parts.Add(
          new GameMessagePart
          {
            Content = part.Key,
            Escape = part.Value
          }
        );
      }

      GameMessage sm = new GameMessage
      {
        MessageParts = parts.ToArray()
      };

      if (embed_color != null)
      {
        if (!KnownChannelList.CanStyleTo(channel))
        {
          Puts(string.Format(lang.GetMessage("discord.channel_cannot_style", this), channel));
          return false;
        }
        sm.Type = 1;
        sm.EmbedStyle = new GameMessageEmbedStyle
        {
          Color = embed_color
        };
      }
      else
      {
        if (!KnownChannelList.CanSendTo(channel))
        {
          Puts(string.Format(lang.GetMessage("discord.channel_cannot_send", this), channel));
          return false;
        }
      }

      if (channel[0] == '#')
      {
        channel = channel.Substring(1);
      }

      if (callback == null)
      {
        callback = (int code, string response) => (code == 200);
      }

      string body = JsonConvert.SerializeObject(sm);
      return Request(new ApiRequest(RequestMethod.POST, $"{ApiMessageBaseURI}/{channel}", body, owner), callback);
    }

    private bool API_GetChannelMessage(Plugin owner, string channel, Func<int, string, bool> callback = null)
    {
      return Request(new ApiRequest(RequestMethod.GET, ApiChatURI, null, owner), callback);
    }
    #endregion

    #region Roles API
    private bool API_SendRole(Plugin owner, string[] groupPlayerIDs, string role, Func<int, string, bool> callback)
    {
      RoleSyncRequest rsr = new RoleSyncRequest
      {
        PlayerIDs = groupPlayerIDs,
      };

      return Request(new ApiRequest(RequestMethod.POST, $"{ApiRolesURI}/{role}", JsonConvert.SerializeObject(rsr), owner), callback);
    }
    #endregion

    private bool API_SendEntityDeath(Plugin owner, string name, string gridPos, string[] owners, Func<int, string, bool> callback)
    {
      EntityDeath di = new EntityDeath(name, gridPos, owners);

      return Request(new ApiRequest(RequestMethod.PUT, EntityDeathURI, JsonConvert.SerializeObject(di), owner), callback);
    }

    private bool API_SendClans(Plugin owner, List<JObject> clans, Func<int, string, bool> callback)
    {
      return Request(new ApiRequest(RequestMethod.PUT, ApiClansURI, JsonConvert.SerializeObject(clans), owner), callback);
    }

    private bool API_SendClan(Plugin owner, string tag, JObject clan, Func<int, string, bool> callback)
    {
      return Request(new ApiRequest(RequestMethod.PUT, $"{ApiClansURI}/{tag}", JsonConvert.SerializeObject(clan), owner), callback);
    }

    private bool API_DeleteClan(Plugin owner, string tag, Func<int, string, bool> callback)
    {
      return Request(new ApiRequest(RequestMethod.DELETE, $"{ApiClansURI}/{tag}", null, owner), callback);
    }

    private void Connected()
    {
      UpdateChannels();
      Interface.Call("OnPoundBotConnected");
    }
    #endregion

    private void UpdateChannels()
    {
      Request(new ApiRequest(RequestMethod.GET, ApiMessageBaseURI, null, this),
          (code, response) =>
          {
            if (code == 200)
            {
              KnownChannelList = JsonConvert.DeserializeObject<ChannelList>(response);
              Puts(lang.GetMessage("discord.channels_updated", this));
              return true;
            }

            return false;
          });
    }

    public void PrintChannels(bool all = false)
    {
      foreach (Channel c in KnownChannelList.Channels)
      {
        if (all || c.IsAvailable())
        {
          Puts($"ID: {c.ID}, Name: {c.Name}, CanSend: {c.CanSend}, CanStyle: {c.CanStyle}");
        }
      }
    }

    #region Helpers
    private void AddLocalizedCommand(string key, string command)
    {
      foreach (var language in lang.GetLanguages(this))
      {
        var messages = lang.GetMessages(language, this);
        foreach (var message in messages.Where(m => m.Key.Equals(key)))
          if (!string.IsNullOrEmpty(message.Value)) AddCovalenceCommand(message.Value, command);
      }
    }
    #endregion

    #region Commands
    private void CommandPoundBotRegister(IPlayer player, string command, string[] args)
    {
      if (args.Length != 1)
      {
        player.Message(lang.GetMessage("usage.pbreg", this, player.Id));
        return;
      }

      if (args[0] == "check")
      {
        Request(new ApiRequest(RequestMethod.GET, $"{ApiDiscordAuthURI}/check/{player.Id}", null, this),
        (code, response) =>
        {
          if (code == 200)
          {
            player.Message(lang.GetMessage("discord.connected", this, player.Id));
            return true;
          }

          if (code == 404) // Method not allowed means we're already connected
          {
            player.Message(lang.GetMessage("discord.not_connected", this, player.Id));
            return true;
          }

          return false;
        });

        return;
      }

      Regex r = new Regex(@"^[^#]+#[0-9]+$");
      if (!r.Match(args[0]).Success)
      {
        player.Message(lang.GetMessage("usage.pbreg", this, player.Id));
        return;
      }

      string.Format(lang.GetMessage("discord.console.registration_attempt", this), player.Name, player.Id, args[0]);

      var da = new DiscordAuth(player.Name, args[0], player.Id);

      Request(new ApiRequest(RequestMethod.PUT, ApiDiscordAuthURI, JsonConvert.SerializeObject(da), this),
        (code, response) =>
        {
          if (code == 200)
          {
            player.Message(string.Format(lang.GetMessage("discord.pin", this, player.Id), da.Pin.ToString("D4")));
            return true;
          }

          if (code == 409) // Conflict means we're already connected
          {
            player.Message(lang.GetMessage("discord.already_connected", this, player.Id));
            return true;
          }

          return false;
        });
    }

    [Command("pb.update_channels")]
    private void ConsoleCommandUpdateChannels(IPlayer player, string command, string[] args)
    {
      UpdateChannels();
    }

    [Command("pb.channels")]
    private void ConsoleCommandChannels(IPlayer player, string command, string[] args)
    {
      PrintChannels((args.Length != 0));
    }

    [Command("pb.set_api_key")]
    private void ConsoleCommandSetAPIKey(IPlayer player, string command, string[] args)
    {
      if (args.Count() != 1)
      {
        Puts(lang.GetMessage("usage.set_api_key", this));
        return;
      }

      Puts(lang.GetMessage("config.api_key_updated", this));
      Config["api.key"] = args[0];
      SaveConfig();
      ApplyConfig();
    }

    [Command("pb.set_debug_uri")]
    private void ConsoleCommandSetDebugURI(IPlayer player, string command, string[] args)
    {
      if (args.Count() != 1)
      {
        Puts(lang.GetMessage("usage.set_debug_uri", this));
        return;
      }

      DebugURI = args[0];
    }
    #endregion
  }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху