C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// #define TESTING
#if TESTING
// #define RUST
// #define SEVENDAYSTODIE
#endif
using System;
using System.Collections;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;
using UnityEngine.Networking;
using Time = UnityEngine.Time;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace Oxide.Plugins
{
[Info("VyHub", "VyHub", "1.3.11")]
[Description(
"VyHub plugin to manage and monetize your Rust / 7 Days to Die server.You can create your webstore for free with VyHub!")]
public class VyHub : CovalencePlugin
{
#region Fields
private string _serverBundleID = string.Empty;
private const string
GameType = "STEAM",
CMD_EDIT_CONFIG = "vh_config",
CMD_SETUP_CONFIG = "vh_setup",
CMD_WARN = "warn";
private readonly List<UnityWebRequest> _activeRequests = new List<UnityWebRequest>();
private readonly List<Coroutine> _coroutines = new List<Coroutine>();
private HashSet<string> _warnedUsers = new HashSet<string>();
#endregion
#region Config
private Configuration _config;
private class Configuration
{
[JsonProperty("Advert Settings")]
public AdvertSettings AdvertSettings = new AdvertSettings
{
Prefix = "[★] ",
Interval = 180f
};
[JsonProperty("API Settings")]
public APISettings API = new APISettings
{
URL = "https://api.vyhub.app/<name>/v1",
Key = "Admin -> Settings -> Server -> Setup",
ServerID = "Admin -> Settings -> Server -> Setup"
};
[JsonProperty("Notify chat when a user has been blocked?")]
public bool NotifyChatOnUserBlocked = true;
}
private class AdvertSettings
{
[JsonProperty("Prefix")]
public string Prefix;
[JsonProperty("Interval")]
public float Interval;
}
private class APISettings
{
[JsonProperty("URL")] public string URL;
[JsonProperty("Key")] public string Key;
[JsonProperty("Server ID")]
public string ServerID;
[JsonIgnore]
public Dictionary<string, string> Headers;
[JsonIgnore]
public string
ServerEndpoint,
FetchAdvertsEndpoint,
UserEndpoint,
UserActivityEndpoint,
PlaytimeDefinitionEndpoint,
PlaytimeEndpoint,
ServerBundleEndpoint,
BansEndpoint,
WarningsEndpoint,
GroupEndpoint,
UserRewardsEndpoint,
SendRewardsEndpoint;
public void InitOrUpdate()
{
Headers = new Dictionary<string, string>
{
["Content-Type"] = "application/json",
["Authorization"] = $"Bearer {Key}",
["Accept"] = "application/json"
};
ServerEndpoint = $"{URL}/server/{ServerID}";
FetchAdvertsEndpoint = $"{URL}/advert/?active=true";
UserEndpoint = $"{URL}/user/";
UserActivityEndpoint = $"{URL}/server/{ServerID}/user-activity";
PlaytimeDefinitionEndpoint = $"{URL}/user/attribute/definition";
PlaytimeEndpoint = $"{URL}/user/attribute/";
ServerBundleEndpoint = $"{URL}/server/bundle/";
BansEndpoint = $"{URL}/ban/";
WarningsEndpoint = $"{URL}/warning/";
GroupEndpoint = $"{URL}/group/";
UserRewardsEndpoint =
$"{URL}/packet/reward/applied/user?active=true&foreign_ids=true&status=OPEN&for_server_id={ServerID}";
SendRewardsEndpoint = $"{URL}/packet/reward/applied/";
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch
{
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig()
{
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig()
{
_config = new Configuration();
}
#endregion
#region Data
#region Users
private Dictionary<string, VyHubUser> _vyHubUsers = new Dictionary<string, VyHubUser>();
public VyHubUser GetVyHubUser(string targetID)
{
VyHubUser user;
return _vyHubUsers.TryGetValue(targetID, out user) ? user : null;
}
private void LoadPlayerData(string targetID, Action<VyHubUser> callback = null)
{
GetOrCreateUser(targetID, user => callback?.Invoke(user));
}
private void UnloadPlayerData(string targetID)
{
_vyHubUsers.Remove(targetID);
}
#endregion
#region Rewards
private void SaveExecutedRewards()
{
SaveObjectToData("ExecutedRewards", _executedRewards);
}
private void LoadExecutedRewards()
{
try
{
_executedRewards = Interface.Oxide.DataFileSystem.ReadObject<List<string>>($"{Name}/ExecutedRewards");
}
catch (Exception e)
{
PrintError(e.ToString());
}
if (_executedRewards == null) _executedRewards = new List<string>();
}
#endregion
#endregion
#region Hooks
private void Init()
{
LoadExecutedRewards();
LoadCachedBans();
#if SEVENDAYSTODIE
LoadCrossIDs();
#endif
}
private void OnServerInitialized()
{
RegisterPermissions();
RegisterCommands();
_config.API.InitOrUpdate();
#if RUST
InitColors();
#else
InitWebEngine();
#endif
GetServerInformation(() =>
{
GetPlaytimeDefinition(() =>
{
StartTimers();
InitAdverts();
LoadPlayers();
});
});
}
private void Unload()
{
StopCoroutines();
#if RUST
UnloadDashboardUIs();
#endif
DisposeActiveRequests();
DestroyTimers();
SendPlayerTime(true);
StopAdverts();
SaveCachedBans();
#if !RUST
DestroyWebEngine();
#endif
#if SEVENDAYSTODIE
SaveCrossIDs();
#endif
_config = null;
}
#region Players
private void OnUserConnected(IPlayer player)
{
if (player == null) return;
var playerID = player.Id;
if (string.IsNullOrEmpty(playerID)) return;
TryAddToPlayTimes(playerID);
#if SEVENDAYSTODIE
TryToUpdateCrossID(playerID);
#endif
GetOrCreateUser(playerID, user =>
{
if (user == null) return;
GetUserRewards(user.ID, rewards =>
{
var reward = rewards.FirstOrDefault();
if (reward.Value != null && reward.Value.Count > 0)
_rewards[playerID] = reward.Value;
ExecuteReward(new List<string>
{
"CONNECT",
"SPAWN"
}, playerID);
});
SyncGroups(user);
});
#if RUST
GetAvatar(player.Id,
avatar => ImageLibrary?.Call("AddImage", avatar, $"avatar_{player.Id}"));
#endif
}
private void OnUserDisconnected(IPlayer player)
{
if (player == null) return;
SendPlayerTime(player.Id, true);
UnloadPlayerData(player.Id);
ExecuteReward(new List<string>
{
"DISCONNECT"
}, player.Id);
}
private void OnUserRespawned(IPlayer player)
{
if (player == null) return;
ExecuteReward(new List<string>
{
"SPAWN"
}, player.Id);
}
#if RUST
private void OnPlayerDeath(BasePlayer player, HitInfo info)
{
if (player == null || player.IsNpc) return;
ExecuteReward(new List<string>
{
"DEATH"
}, player.UserIDString);
}
#endif
#if SEVENDAYSTODIE
private void OnEntityDeath(EntityPlayer player, DamageResponse response)
{
if (player == null) return;
var playerDataFromEntityID = global::GameManager.Instance.persistentPlayers.GetPlayerDataFromEntityID(player.entityId);
if (playerDataFromEntityID == null) return;
var userID = playerDataFromEntityID.PrimaryId?.ReadablePlatformUserIdentifier;
if (string.IsNullOrEmpty(userID)) return;
userID = userID.Replace("Steam_", string.Empty);
ExecuteReward(new List<string>
{
"DEATH"
}, userID);
}
#endif
#endregion
#region Permissions
private void OnUserGroupAdded(string id, string groupName)
{
var user = GetVyHubUser(id);
if (user == null) return;
var remove = _groupsBackLog.Remove(GetGroupBacklogKey(id, groupName, GroupOperation.add));
if (remove == false)
AddUserToVyHubGroup(user, groupName,
membership =>
{
Log(LogType.INFO,
$"Added VyHub group membership in group {groupName} for player {user.Username}.");
});
}
private void OnUserGroupRemoved(string id, string groupName)
{
var user = GetVyHubUser(id);
if (user == null) return;
var remove = _groupsBackLog.Remove(GetGroupBacklogKey(id, groupName, GroupOperation.remove));
if (remove == false)
RemoveUserFromVyHubGroup(user, groupName,
membership =>
{
Log(LogType.INFO,
$"Ended VyHub group membership in group {groupName} for player {user.Username}.");
});
}
#endregion
#endregion
#region Commands
private readonly string
MSG_EDIT_CONFIG_ERR_SYNTAX = $"Error syntax! Use: /{CMD_EDIT_CONFIG} <api_key/api_url/server_id> <value>",
MSG_SETUP_CONFIG_ERR_SYNTAX = $"Error syntax! Use: /{CMD_EDIT_CONFIG} <api_key> <api_url> <server_id>",
MSG_WARN_ERR_SYNTAX = $"Error syntax! Use: /{CMD_WARN} <steam id> <reason>",
MSG_WARN_NO_PERMISSIONS = "You do not have permission to warn other players!",
MSG_BAN_NO_PERMISSIONS = "You do not have permission to ban other players!",
MSG_UNBAN_NO_PERMISSIONS = "You do not have permission to unban other players!";
private void CmdEditConfig(IPlayer player, string command, string[] args)
{
if (!player.IsServer) return;
if (args.Length < 2)
{
player.Reply(MSG_EDIT_CONFIG_ERR_SYNTAX);
return;
}
var value = string.Join(" ", args.Skip(1));
if (string.IsNullOrWhiteSpace(value))
{
player.Reply(MSG_EDIT_CONFIG_ERR_SYNTAX);
return;
}
var param = args[0];
switch (param)
{
case "api_key":
{
_config.API.Key = value;
break;
}
case "api_url":
{
_config.API.URL = value;
break;
}
case "server_id":
{
_config.API.ServerID = value;
break;
}
default:
{
player.Reply(MSG_EDIT_CONFIG_ERR_SYNTAX);
return;
}
}
player.Reply($"You have successfully set the \"{param}\" parameter to \"{value}\"!");
_config.API.InitOrUpdate();
SaveConfig();
GetServerInformation();
}
private void CmdSetupConfig(IPlayer player, string command, string[] args)
{
if (!player.IsServer) return;
if (args.Length < 3)
{
player.Reply(MSG_SETUP_CONFIG_ERR_SYNTAX);
return;
}
var api_key = args[0];
var api_url = args[1];
var server_id = args[2];
if (string.IsNullOrWhiteSpace(api_key) || string.IsNullOrWhiteSpace(api_url) ||
string.IsNullOrWhiteSpace(server_id))
{
player.Reply(MSG_SETUP_CONFIG_ERR_SYNTAX);
return;
}
_config.API = new APISettings
{
URL = api_url,
Key = api_key,
ServerID = server_id
};
_config.API.InitOrUpdate();
player.Reply(
$"You have successfully set the following API parameters in the config: URL={api_url}, KEY={api_key}, Server ID={server_id}.");
SaveConfig();
GetServerInformation();
}
private void CmdWarn(IPlayer player, string command, string[] args)
{
if (!player.IsServer && !player.HasPermission($"{Name}.warn"))
{
player.Reply(MSG_WARN_NO_PERMISSIONS);
return;
}
if (args.Length < 2)
{
player.Reply(MSG_WARN_ERR_SYNTAX);
return;
}
var targetPlayer = covalence.Players.FindPlayerById(args[0]);
if (targetPlayer == null || !targetPlayer.IsConnected)
{
player.Reply(Msg(player, ErrorPlayerOffline));
return;
}
CreateWarning(player, targetPlayer, args[1]);
}
#endregion
#region Dashboard
#if RUST
#region Fields
[PluginReference] private Oxide.Core.Plugins.Plugin ImageLibrary = null;
private enum DashboardTab
{
Players = 0
}
private Dictionary<ulong, ConfirmData> _confirmPlayers = new Dictionary<ulong, ConfirmData>();
private class ConfirmData
{
public string Reason = string.Empty;
public string Duration = string.Empty;
}
private const string
DashboardLayer = "UI.VyHub.Dashboard",
DashboardMainLayer = "UI.VyHub.Dashboard.Main",
DashboardConfirmLayer = "UI.VyHub.Dashboard.Confirm",
DashboardConfirmMainLayer = "UI.VyHub.Dashboard.Confirm.Main",
DashboardOpenCmd = "dashboard",
DashboardConsoleCmd = "UI_VyHub_Dashboard",
DASHBOARD_ACTION_BAN = "ban",
DASHBOARD_ACTION_WARN = "warn",
DASHBOARD_ACTION_UNBAN = "unban";
private const int
DASHBOARD_TABLE_PLAYERS_CONST_X_INDENT = 205,
DASHBOARD_TABLE_PLAYERS_ON_LINE = 2,
DASHBOARD_TABLE_PLAYERS_MAX_LINES = 8,
DASHBOARD_TABLE_PLAYERS_TOTAL_AMOUNT =
DASHBOARD_TABLE_PLAYERS_ON_LINE * DASHBOARD_TABLE_PLAYERS_MAX_LINES;
private const float
DASHBOARD_HEADER_BTN_WIDTH = 25,
DASHBOARD_TAB_HEIGHT = 36,
DASHBOARD_TAB_MARGIN = 0,
DASHBOARD_TABLE_PLAYERS_WIDTH = 292f,
DASHBOARD_TABLE_PLAYERS_AVATAR_SIZE = 36f,
DASHBOARD_TABLE_PLAYERS_HEIGHT = 36f,
DASHBOARD_TABLE_PLAYERS_X_MARGIN = 16f,
DASHBOARD_TABLE_PLAYERS_Y_MARGIN = 8f,
DASHBOARD_TABLE_PLAYERS_BTN_WIDTH = 65f,
DASHBOARD_TABLE_PLAYERS_BTN_HEIGHT = 20f,
DASHBOARD_TABLE_PLAYERS_BTN_MARGIN = 5f,
DASHBOARD_CONFIRM_HEIGHT = 230f,
DASHBOARD_CONFIRM_BANS_HEIGHT = 285f;
#endregion
#region Colors
private string _color1;
private string _color2;
private string _color3;
private string _color4;
private string _color5;
private string _color6;
private string _color7;
private string _color8;
private string _color9;
private string _color10;
private void InitColors()
{
_color1 = HexToCuiColor("#0E0E10");
_color2 = HexToCuiColor("#161617");
_color3 = HexToCuiColor("#FFFFFF");
_color4 = HexToCuiColor("#4B68FF");
_color5 = HexToCuiColor("#4B68FF", 50);
_color6 = HexToCuiColor("#242425");
_color7 = HexToCuiColor("#000000");
_color8 = HexToCuiColor("#FFFFFF", 50);
_color9 = HexToCuiColor("#FF4B4B");
_color10 = HexToCuiColor("#B19F56");
}
private static string HexToCuiColor(string HEX, float Alpha = 100)
{
if (string.IsNullOrEmpty(HEX)) HEX = "#FFFFFF";
var str = HEX.Trim('#');
if (str.Length != 6) throw new Exception(HEX);
var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);
return $"{(double) r / 255} {(double) g / 255} {(double) b / 255} {Alpha / 100f}";
}
#endregion
#region Interface
private void DashboardUI(BasePlayer player, DashboardTab selectedTab = DashboardTab.Players, int page = 0,
string search = "", bool first = false)
{
var container = new Oxide.Game.Rust.Cui.CuiElementContainer();
float xSwitch;
float ySwitch;
float localSwitch;
#region Background
if (first)
{
container.Add(new Oxide.Game.Rust.Cui.CuiPanel
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Image =
{
Color = "0 0 0 0.9",
Material = "assets/content/ui/uibackgroundblur.mat"
},
CursorEnabled = true
}, "Overlay", DashboardLayer + ".Background", DashboardLayer + ".Background");
container.Add(new Oxide.Game.Rust.Cui.CuiButton
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Text = {Text = ""},
Button =
{
Color = "0 0 0 0",
Close = DashboardLayer + ".Background"
}
}, DashboardLayer + ".Background");
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
OffsetMin = "-410 -210",
OffsetMax = "410 210"
},
Image =
{
Color = _color1
}
}, DashboardLayer + ".Background", DashboardLayer);
}
#endregion
#region Main
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Image =
{
Color = "0 0 0 0"
}
}, DashboardLayer, DashboardMainLayer, DashboardMainLayer);
#endregion
#region Header
container.Add(new Oxide.Game.Rust.Cui.CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = "0 -50",
OffsetMax = "0 0"
},
Image = {Color = _color2}
}, DashboardMainLayer, DashboardMainLayer + ".Header");
container.Add(new Oxide.Game.Rust.Cui.CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "30 0",
OffsetMax = "0 0"
},
Text =
{
Text = "Dashboard",
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-bold.ttf",
FontSize = 14,
Color = _color3
}
}, DashboardMainLayer + ".Header");
xSwitch = -25f;
#region Close
container.Add(new Oxide.Game.Rust.Cui.CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - DASHBOARD_HEADER_BTN_WIDTH} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Text =
{
Text = "✕",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 10,
Color = _color3
},
Button =
{
Close = DashboardLayer + ".Background",
Color = _color4
}
}, DashboardMainLayer + ".Header");
#endregion
#endregion
#region Tabs
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 1",
OffsetMin = "15 15",
OffsetMax = "185 -65"
},
Image =
{
Color = _color2
}
}, DashboardMainLayer, DashboardMainLayer + ".Tabs");
ySwitch = 0f;
foreach (DashboardTab targetTab in Enum.GetValues(typeof(DashboardTab)))
{
var isSelectedTab = targetTab == selectedTab;
if (isSelectedTab)
{
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = $"0 {ySwitch - DASHBOARD_TAB_HEIGHT}",
OffsetMax = $"0 {ySwitch}"
},
Image =
{
Color = _color5
}
}, DashboardMainLayer + ".Tabs", DashboardMainLayer + $".Tab.{targetTab}");
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 1",
OffsetMin = "0 0",
OffsetMax = "5 0"
},
Image =
{
Color = _color4
}
}, DashboardMainLayer + $".Tab.{targetTab}");
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "0 0",
AnchorMax = "1 1",
OffsetMin = "0 0",
OffsetMax = "0 0"
},
Text =
{
Text = $"{targetTab.ToString()}",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
Color = _color3
},
Button =
{
Color = "0 0 0 0",
Command = $"{DashboardConsoleCmd} page {targetTab} 0 {search}"
}
}, DashboardMainLayer + $".Tab.{targetTab}");
}
else
{
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = $"0 {ySwitch - DASHBOARD_TAB_HEIGHT}",
OffsetMax = $"0 {ySwitch}"
},
Text =
{
Text = $"{targetTab.ToString()}",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf"
},
Button =
{
Color = "0 0 0 0",
Command = $"{DashboardConsoleCmd} page {targetTab} 0 {search}"
}
}, DashboardMainLayer + ".Tabs", DashboardMainLayer + $".Tab.{targetTab}");
}
ySwitch = ySwitch - DASHBOARD_TAB_HEIGHT - DASHBOARD_TAB_MARGIN;
}
#endregion
#region Selected Tab
switch (selectedTab)
{
case DashboardTab.Players:
var members = GetPlayers(page, search);
#region Header
xSwitch = xSwitch - DASHBOARD_HEADER_BTN_WIDTH - 5f;
#region Next Page
container.Add(new Oxide.Game.Rust.Cui.CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - DASHBOARD_HEADER_BTN_WIDTH} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Text =
{
Text = "▶",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 10,
Color = _color3
},
Button =
{
Color = _color6,
Command = members.Length > (page + 1) * DASHBOARD_TABLE_PLAYERS_TOTAL_AMOUNT
? $"{DashboardConsoleCmd} page {selectedTab} {page + 1} {search}"
: ""
}
}, DashboardMainLayer + ".Header");
#endregion
xSwitch = xSwitch - DASHBOARD_HEADER_BTN_WIDTH - 5f;
#region Back Page
container.Add(new Oxide.Game.Rust.Cui.CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - DASHBOARD_HEADER_BTN_WIDTH} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Text =
{
Text = "◀",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 10,
Color = _color3
},
Button =
{
Color = _color6,
Command = page != 0
? $"{DashboardConsoleCmd} page {selectedTab} {page - 1} {search}"
: ""
}
}, DashboardMainLayer + ".Header");
#endregion
xSwitch = xSwitch - DASHBOARD_HEADER_BTN_WIDTH - 5f;
#region Search
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - 140} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Image =
{
Color = _color7
}
}, DashboardMainLayer + ".Header", DashboardMainLayer + ".Header.Search");
container.Add(new Oxide.Game.Rust.Cui.CuiElement()
{
Parent = DashboardMainLayer + ".Header.Search",
Components =
{
new Oxide.Game.Rust.Cui.CuiInputFieldComponent()
{
FontSize = 12,
Align = TextAnchor.MiddleLeft,
Command = $"{DashboardConsoleCmd} page {selectedTab} {page}",
Color = "1 1 1 0.95",
CharsLimit = 150,
Text = !string.IsNullOrWhiteSpace(search) ? $"{search}" : "Search...",
NeedsKeyboard = true
},
new Oxide.Game.Rust.Cui.CuiRectTransformComponent()
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "5 0", OffsetMax = "-5 0"
}
}
});
if (HasSearch(search))
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin = "-25 -12.5",
OffsetMax = "0 12.5"
},
Text =
{
Text = "✕",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 10,
Color = _color8
},
Button =
{
Color = "0 0 0 0",
Command = $"{DashboardConsoleCmd} page {selectedTab}"
}
}, DashboardMainLayer + ".Header.Search");
#endregion
#endregion
#region Content
ySwitch = -70f;
xSwitch = DASHBOARD_TABLE_PLAYERS_CONST_X_INDENT;
for (var index = 0; index < members.Length; index++)
{
var member = members[index];
var isWarned = _warnedUsers.Contains(member.UserIDString);
var isBanned = server.IsBanned(player.UserIDString) || _cachedBans.Contains(member.UserIDString);
#region Background
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "0 1",
OffsetMin = $"{xSwitch} {ySwitch - DASHBOARD_TABLE_PLAYERS_HEIGHT}",
OffsetMax = $"{xSwitch + DASHBOARD_TABLE_PLAYERS_WIDTH} {ySwitch}"
},
Image =
{
Color = _color2
}
}, DashboardMainLayer, DashboardMainLayer + $".Content.Player.{index}");
#endregion
#region Avatar
container.Add(new Oxide.Game.Rust.Cui.CuiElement()
{
Parent = DashboardMainLayer + $".Content.Player.{index}",
Components =
{
new Oxide.Game.Rust.Cui.CuiRawImageComponent
{
Png = ImageLibrary.Call<string>("GetImage", $"avatar_{member.UserIDString}")
},
new Oxide.Game.Rust.Cui.CuiRectTransformComponent
{
AnchorMin = "0 0", AnchorMax = "0 1",
OffsetMin = "0 0",
OffsetMax = $"{DASHBOARD_TABLE_PLAYERS_AVATAR_SIZE} 0"
}
}
});
#endregion
#region Name&SteamID
container.Add(new Oxide.Game.Rust.Cui.CuiLabel()
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 1",
OffsetMin = $"{DASHBOARD_TABLE_PLAYERS_AVATAR_SIZE + 10} 0",
OffsetMax = "0 0"
},
Text =
{
Text = $"{member.displayName}",
Align = TextAnchor.LowerLeft,
Font = "robotocondensed-bold.ttf",
FontSize = 12,
Color = _color3
}
}, DashboardMainLayer + $".Content.Player.{index}");
container.Add(new Oxide.Game.Rust.Cui.CuiLabel()
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 0.5",
OffsetMin = $"{DASHBOARD_TABLE_PLAYERS_AVATAR_SIZE + 10} 0",
OffsetMax = "0 0"
},
Text =
{
Text = $"{member.UserIDString}",
Align = TextAnchor.UpperLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 10,
Color = _color3
}
}, DashboardMainLayer + $".Content.Player.{index}");
#endregion
#region Buttons
localSwitch = -5;
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin =
$"{localSwitch - DASHBOARD_TABLE_PLAYERS_BTN_WIDTH} -{DASHBOARD_TABLE_PLAYERS_BTN_HEIGHT / 2}",
OffsetMax = $"{localSwitch} {DASHBOARD_TABLE_PLAYERS_BTN_HEIGHT / 2}"
},
Text =
{
Text = isBanned ? "Unban" : "Ban",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 10,
Color = _color3
},
Button =
{
Command =
isBanned ?
$"{DashboardConsoleCmd} {DASHBOARD_ACTION_UNBAN} {member.UserIDString}"
: $"{DashboardConsoleCmd} {DASHBOARD_ACTION_BAN} {member.UserIDString}",
Color = _color9
}
}, DashboardMainLayer + $".Content.Player.{index}");
localSwitch = localSwitch - DASHBOARD_TABLE_PLAYERS_BTN_WIDTH -
DASHBOARD_TABLE_PLAYERS_BTN_MARGIN;
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin =
$"{localSwitch - DASHBOARD_TABLE_PLAYERS_BTN_WIDTH} -{DASHBOARD_TABLE_PLAYERS_BTN_HEIGHT / 2}",
OffsetMax = $"{localSwitch} {DASHBOARD_TABLE_PLAYERS_BTN_HEIGHT / 2}"
},
Text =
{
Text = isWarned ? "Has warning" : "Warn",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 10,
Color = _color3
},
Button =
{
Command =
isWarned
? ""
: $"{DashboardConsoleCmd} {DASHBOARD_ACTION_WARN} {member.UserIDString}",
Color = isWarned ? _color10 : _color4
}
}, DashboardMainLayer + $".Content.Player.{index}");
#endregion
#region Table Utils
if ((index + 1) % DASHBOARD_TABLE_PLAYERS_ON_LINE == 0)
{
ySwitch = ySwitch - DASHBOARD_TABLE_PLAYERS_HEIGHT - DASHBOARD_TABLE_PLAYERS_Y_MARGIN;
xSwitch = DASHBOARD_TABLE_PLAYERS_CONST_X_INDENT;
}
else
{
xSwitch += DASHBOARD_TABLE_PLAYERS_WIDTH + DASHBOARD_TABLE_PLAYERS_X_MARGIN;
}
#endregion
}
#endregion
break;
}
#endregion
Oxide.Game.Rust.Cui.CuiHelper.AddUi(player, container);
}
private void ConfirmActionUI(BasePlayer player, string action, string targetName, ulong targetID)
{
var container = new Oxide.Game.Rust.Cui.CuiElementContainer();
var confirm = GetOrAddConfirmData(player);
float ySwitch;
float height;
#region Background
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Image =
{
Color = "0 0 0 0.9",
Material = "assets/content/ui/uibackgroundblur.mat"
},
CursorEnabled = true
}, "Overlay", DashboardConfirmLayer, DashboardConfirmLayer);
container.Add(new Oxide.Game.Rust.Cui.CuiButton
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Text = {Text = ""},
Button =
{
Color = "0 0 0 0",
Close = DashboardConfirmLayer,
Command = $"{DashboardConsoleCmd} confirm cancel"
}
}, DashboardConfirmLayer);
#endregion
#region Main
var mainHeight = action == DASHBOARD_ACTION_BAN ? DASHBOARD_CONFIRM_BANS_HEIGHT : DASHBOARD_CONFIRM_HEIGHT;
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0.5 0.5",
AnchorMax = "0.5 0.5",
OffsetMin = $"-125 -{mainHeight / 2f}",
OffsetMax = $"125 {mainHeight / 2f}"
},
Image =
{
Color = _color1
}
}, DashboardConfirmLayer, DashboardConfirmMainLayer, DashboardConfirmMainLayer);
#endregion
#region Header
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = "0 -50", OffsetMax = "0 0"
},
Image =
{
Color = _color2
}
}, DashboardConfirmMainLayer, DashboardConfirmMainLayer + ".Header");
container.Add(new Oxide.Game.Rust.Cui.CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "20 0",
OffsetMax = "0 0"
},
Text =
{
Text = "Confirm Action",
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-bold.ttf",
FontSize = 14,
Color = _color3
}
}, DashboardConfirmMainLayer + ".Header");
container.Add(new Oxide.Game.Rust.Cui.CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = "-35 -37.5",
OffsetMax = "-10 -12.5"
},
Text =
{
Text = "✕",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 10,
Color = _color3
},
Button =
{
Close = DashboardConfirmLayer,
Color = _color4,
Command = $"{DashboardConsoleCmd} confirm cancel"
}
}, DashboardConfirmMainLayer + ".Header");
#endregion
ySwitch = -60f;
height = 50f;
#region Message
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 1",
AnchorMax = "1 1",
OffsetMin = $"20 {ySwitch - height}",
OffsetMax = $"-20 {ySwitch}"
},
Image =
{
Color = _color2
}
}, DashboardConfirmMainLayer, DashboardConfirmMainLayer + ".Message");
container.Add(new Oxide.Game.Rust.Cui.CuiLabel()
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Text =
{
Text = $"Do you really want to <b>{action}</b> player\n<b>{targetName}</b> (<b>{targetID}</b>)?",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = _color3
}
}, DashboardConfirmMainLayer + ".Message");
#endregion
if (action != DASHBOARD_ACTION_UNBAN)
{
#region Reason
ySwitch = ySwitch - height - 5f;
EnterFieldUI(ref container, ref ySwitch, ref height, confirm, "reason");
#endregion
#region Duration
if (action == DASHBOARD_ACTION_BAN)
{
ySwitch = ySwitch - height - 5f;
EnterFieldUI(ref container, ref ySwitch, ref height, confirm, "duration");
}
#endregion
}
#region Buttons
ySwitch = ySwitch - height - 10f;
height = 40;
container.Add(new Oxide.Game.Rust.Cui.CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = $"20 {ySwitch - height}", OffsetMax = $"-20 {ySwitch}"
},
Image =
{
Color = _color2
}
}, DashboardConfirmMainLayer, DashboardConfirmMainLayer + ".Buttons");
#region Cancel
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "0 0.5",
OffsetMin = "15 -12.5",
OffsetMax = "95 12.5"
},
Text =
{
Text = "Cancel",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
Color = _color3
},
Button =
{
Close = DashboardConfirmLayer,
Color = _color4,
Command = $"{DashboardConsoleCmd} confirm cancel"
}
}, DashboardConfirmMainLayer + ".Buttons");
#endregion
#region Accept
container.Add(new Oxide.Game.Rust.Cui.CuiButton()
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin = "-95 -12.5",
OffsetMax = "-15 12.5"
},
Text =
{
Text = "Accept",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
Color = _color3
},
Button =
{
Close = DashboardConfirmLayer,
Color = _color9,
Command = $"{DashboardConsoleCmd} confirm {action} {targetID}"
}
}, DashboardConfirmMainLayer + ".Buttons");
#endregion
#endregion
Oxide.Game.Rust.Cui.CuiHelper.AddUi(player, container);
}
private void EnterFieldUI(ref Oxide.Game.Rust.Cui.CuiElementContainer container, ref float ySwitch, ref float height,
ConfirmData confirm, string type)
{
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 1",
AnchorMax = "1 1",
OffsetMin = $"20 {ySwitch - height}",
OffsetMax = $"-20 {ySwitch}"
},
Image =
{
Color = _color2
}
}, DashboardConfirmMainLayer, DashboardConfirmMainLayer + $".{type}");
string title;
switch (type)
{
case "duration":
title = $"Enter a {type} (in seconds):";
break;
default:
title = $"Enter a {type}:";
break;
}
container.Add(new Oxide.Game.Rust.Cui.CuiLabel()
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = "0 -20",
OffsetMax = "0 0"
},
Text =
{
Text = $"{title}",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = _color3
}
}, DashboardConfirmMainLayer + $".{type}");
container.Add(new Oxide.Game.Rust.Cui.CuiPanel()
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 0",
OffsetMin = "5 5",
OffsetMax = "-5 30"
},
Image =
{
Color = _color1
}
}, DashboardConfirmMainLayer + $".{type}", DashboardConfirmMainLayer + $".{type}.Enter");
var param = type == "reason" ? confirm.Reason : confirm.Duration;
container.Add(new Oxide.Game.Rust.Cui.CuiElement
{
Parent = DashboardConfirmMainLayer + $".{type}.Enter",
Components =
{
new Oxide.Game.Rust.Cui.CuiInputFieldComponent
{
FontSize = 10,
Align = TextAnchor.MiddleLeft,
Command = $"{DashboardConsoleCmd} confirm enter {type}",
Color = "1 1 1 0.95",
CharsLimit = 150,
Text = !string.IsNullOrWhiteSpace(param) ? $"{param}" : string.Empty,
NeedsKeyboard = true
},
new Oxide.Game.Rust.Cui.CuiRectTransformComponent
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "10 0", OffsetMax = "0 0"
}
}
});
}
#endregion
#region Commands
private void CmdOpenDashboard(IPlayer cov, string command, string[] args)
{
if (!cov.HasPermission($"{Name}.dashboard"))
return;
var player = cov.Object as BasePlayer;
if (player == null) return;
DashboardUI(player, first: true);
}
private void CmdConsoleDashboard(IPlayer covPlayer, string command, string[] args)
{
var player = covPlayer?.Object as BasePlayer;
if (player == null || args.Length < 1 ||
!permission.UserHasPermission(player.UserIDString, $"{Name}.dashboard"))
return;
switch (args[0])
{
case "page":
{
DashboardTab targetTab;
if (!(args.Length >= 2) || !Enum.TryParse(args[1], out targetTab)) return;
var page = 0;
if (args.Length >= 3)
int.TryParse(args[2], out page);
var search = args.Length >= 4 ? args[3] : string.Empty;
if (search == "delete")
search = string.Empty;
DashboardUI(player, targetTab, page, search);
break;
}
case DASHBOARD_ACTION_BAN:
case DASHBOARD_ACTION_WARN:
{
ulong targetID;
if (!(args.Length >= 2) || !ulong.TryParse(args[1], out targetID)) return;
string permissionMsg;
if (!HasActionPermission(player.UserIDString, args[0], out permissionMsg))
{
player.ChatMessage(permissionMsg);
return;
}
if (player.userID == targetID)
{
player.ChatMessage($"You can't {args[0]} yourself!");
return;
}
var targetPlayer = covalence.Players.FindPlayerById(targetID.ToString());
if (targetPlayer == null) return;
ConfirmActionUI(player, args[0], targetPlayer.Name, targetID);
break;
}
case DASHBOARD_ACTION_UNBAN:
{
ulong targetID;
if (!(args.Length >= 2) || !ulong.TryParse(args[1], out targetID)) return;
string permissionMsg;
if (!HasActionPermission(player.UserIDString, args[0], out permissionMsg))
{
player.ChatMessage(permissionMsg);
return;
}
if (player.userID == targetID)
{
player.ChatMessage($"You can't {args[0]} yourself!");
return;
}
var targetPlayer = covalence.Players.FindPlayerById(targetID.ToString());
if (targetPlayer == null) return;
ConfirmActionUI(player, args[0], targetPlayer.Name, targetID);
break;
}
case "confirm":
{
if (!(args.Length >= 2)) return;
var action = args[1];
switch (action)
{
case DASHBOARD_ACTION_WARN:
case DASHBOARD_ACTION_BAN:
case DASHBOARD_ACTION_UNBAN:
{
string permissionMsg;
if (!HasActionPermission(player.UserIDString, action, out permissionMsg))
{
player.ChatMessage(permissionMsg);
return;
}
break;
}
}
switch (action)
{
case DASHBOARD_ACTION_BAN:
case DASHBOARD_ACTION_WARN:
{
if (!(args.Length >= 3)) return;
var targetID = args[2];
if (string.IsNullOrWhiteSpace(targetID) || !targetID.IsSteamId())
return;
ConfirmData confirmData;
if (!_confirmPlayers.TryGetValue(player.userID, out confirmData))
return;
switch (action)
{
case DASHBOARD_ACTION_BAN:
{
var duration = default(TimeSpan);
if (!string.IsNullOrEmpty(confirmData.Duration))
{
var seconds = Convert.ToDouble(confirmData.Duration);
if (seconds > 0)
duration = TimeSpan.FromSeconds(seconds);
}
if (string.IsNullOrEmpty(confirmData.Reason))
confirmData.Reason = "no reason";
var targetPlayer = covalence.Players.FindPlayerById(targetID);
if (targetPlayer != null)
{
_cachedBans.Add(targetID);
var finalTime = duration.TotalSeconds > 0
? (long?) duration.TotalSeconds
: null;
var adminUser = GetVyHubUser(player.UserIDString);
if (adminUser != null)
{
CreateVyHubBan(finalTime, confirmData.Reason,
targetID, DateTime.UtcNow, adminUser.ID,
ban => targetPlayer.Ban(confirmData.Reason, duration));
}
else
{
CreateVyHubBanWithoutCreator(finalTime, confirmData.Reason,
targetID, DateTime.UtcNow,
ban => targetPlayer.Ban(confirmData.Reason, duration));
}
}
break;
}
case DASHBOARD_ACTION_WARN:
{
_warnedUsers.Add(targetID);
NextTick(() => CreateWarning(player.IPlayer, covalence.Players.FindPlayerById(targetID), confirmData.Reason));
break;
}
}
_confirmPlayers.Remove(player.userID);
DashboardUI(player);
break;
}
case DASHBOARD_ACTION_UNBAN:
{
if (!(args.Length >= 3)) return;
var targetID = args[2];
if (string.IsNullOrWhiteSpace(targetID) || !targetID.IsSteamId())
return;
ConfirmData confirmData;
if (!_confirmPlayers.TryGetValue(player.userID, out confirmData))
return;
switch (action)
{
case DASHBOARD_ACTION_UNBAN:
{
server.Unban(targetID);
_cachedBans.Remove(targetID);
break;
}
}
_confirmPlayers.Remove(player.userID);
DashboardUI(player);
break;
}
case "enter":
{
if (!(args.Length >= 4)) return;
var confirmData = GetOrAddConfirmData(player);
var result = args[3] == "delete" ? string.Empty : string.Join(" ", args.Skip(3));
switch (args[2])
{
case "reason":
{
confirmData.Reason = result;
break;
}
case "duration":
{
result = result.Replace(" ", string.Empty);
double durationTime;
if (double.TryParse(result, out durationTime))
confirmData.Duration = result;
break;
}
}
break;
}
}
break;
}
}
}
#endregion
#region Utils
#region Avatar
private readonly System.Text.RegularExpressions.Regex Regex = new System.Text.RegularExpressions.Regex(@"<avatarFull><!\[CDATA\[(.*)\]\]></avatarFull>");
private void GetAvatar(string userId, Action<string> callback)
{
if (callback == null) return;
SendWebRequest($"http://steamcommunity.com/profiles/{userId}?xml=1", null, (code, response) =>
{
if (code != 200 || response == null)
return;
var avatar = Regex?.Match(response).Groups[1].ToString();
if (string.IsNullOrEmpty(avatar))
return;
callback.Invoke(avatar);
});
}
#endregion
private bool HasActionPermission(string playerID, string action, out string resultMessage)
{
resultMessage = string.Empty;
string permToCheck;
switch (action)
{
case DASHBOARD_ACTION_BAN:
permToCheck = $"{Name}.ban";
resultMessage = MSG_BAN_NO_PERMISSIONS;
break;
case DASHBOARD_ACTION_WARN:
permToCheck = $"{Name}.warn";
resultMessage = MSG_WARN_NO_PERMISSIONS;
break;
case DASHBOARD_ACTION_UNBAN:
permToCheck = $"{Name}.unban";
resultMessage = MSG_UNBAN_NO_PERMISSIONS;
break;
default:
return true;
}
return permission.UserHasPermission(playerID, permToCheck);
}
private void UnloadDashboardUIs()
{
for (var i = 0; i < BasePlayer.activePlayerList.Count; i++)
UnloadDashboardUI(BasePlayer.activePlayerList[i]);
}
private void UnloadDashboardUI(BasePlayer player)
{
Oxide.Game.Rust.Cui.CuiHelper.DestroyUi(player, DashboardLayer + ".Background");
Oxide.Game.Rust.Cui.CuiHelper.DestroyUi(player, DashboardConfirmLayer);
}
private ConfirmData GetOrAddConfirmData(BasePlayer player)
{
ConfirmData confirmData;
if (!_confirmPlayers.TryGetValue(player.userID, out confirmData))
_confirmPlayers.TryAdd(player.userID, confirmData = new ConfirmData());
return confirmData;
}
private BasePlayer[] GetPlayers(int page, string search)
{
return HasSearch(search) ? BasePlayer.activePlayerList.Where(p => p.UserIDString == search || p.displayName == search ||
p.displayName.StartsWith(search) || p.displayName.Contains(search) ||
(search.IsSteamId() && p.UserIDString.Contains(search))).Skip(page * DASHBOARD_TABLE_PLAYERS_TOTAL_AMOUNT).Take(DASHBOARD_TABLE_PLAYERS_TOTAL_AMOUNT).ToArray()
: BasePlayer.activePlayerList.Skip(page * DASHBOARD_TABLE_PLAYERS_TOTAL_AMOUNT).Take(DASHBOARD_TABLE_PLAYERS_TOTAL_AMOUNT).ToArray();
}
private bool HasSearch(string search)
{
return !string.IsNullOrWhiteSpace(search) && search.Length > 1;
}
#endregion
#endif
#endregion
#region API Client
#region Server Info
private void GetServerInformation(Action callback = null)
{
SendWebRequestAndFetch(_config.API.ServerEndpoint, null,
"Cannot connect to VyHub API! Please follow the installation instructions: {0}",
"ServerBundle ID",
new Action<ServerInfo>(serverInfo =>
{
_serverBundleID = serverInfo.ServerBundleID;
callback?.Invoke();
Puts("Successfully connected to VyHub API.");
}));
}
private void PatchServer(List<Dictionary<string, object>> userActivities)
{
SendWebRequestAndFetch(_config.API.ServerEndpoint,
new Dictionary<string, object>
{
["users_max"] = covalence.Server.MaxPlayers,
["users_current"] = covalence.Server.Players,
["user_activities"] = userActivities,
["is_alive"] = true
},
"Failed to patch server: {0}",
"ServerBundle ID",
new Action<ServerInfo>(serverInfo => { _serverBundleID = serverInfo.ServerBundleID; }),
RequestMethod.PATCH);
}
private class ServerInfo
{
[JsonProperty("serverbundle_id")]
public string ServerBundleID;
}
#endregion
#region Adverts
private void FetchAdverts(Action<List<Advert>> callback = null)
{
SendWebRequestAndFetch(_config.API.FetchAdvertsEndpoint + $"&serverbundle_id={_serverBundleID}", null,
"Adverts could not be fetched from VyHub API: {0}",
"Adverts",
callback);
}
private class Advert
{
[JsonProperty("id")] public string ID;
[JsonProperty("title")] public string Title;
[JsonProperty("content")]
public string Content;
[JsonProperty("color")] public string Color;
}
#endregion
#region User
private void GetOrCreateUser(string playerID, Action<VyHubUser> callback = null)
{
var cachedUser = GetVyHubUser(playerID);
if (cachedUser != null)
{
callback?.Invoke(cachedUser);
return;
}
SendWebRequestAndFetch(_config.API.UserEndpoint + $"{playerID}?type={GameType}", null,
null,
"VyHub User",
new Action<VyHubUser>(user =>
{
_vyHubUsers.TryAdd(playerID, user);
callback?.Invoke(user);
}), onResponse: (response, code) =>
{
if (response == null || code != 200)
{
if (code == 404)
{
CreateUser(playerID, callback);
return true;
}
PrintError($"Failed to get user {playerID} from VyHub API.");
return true;
}
return false;
});
}
private void CreateUser(
string playerID,
Action<VyHubUser> callback = null)
{
var body = new Dictionary<string, object>
{
["type"] = GameType,
["identifier"] = playerID
};
var player = covalence.Players.FindPlayerById(playerID);
if (player != null && !string.IsNullOrEmpty(player.Name))
body.TryAdd("username", player.Name);
SendWebRequestAndFetch(_config.API.UserEndpoint,
body,
"Failed to create user in VyHub API: {0}",
"VyHub User",
new Action<VyHubUser>(user =>
{
if (user != null)
// ... [Code preview truncated due to length. Full source in attached file] ...