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 Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using Oxide.Core.Libraries.Covalence;
namespace Oxide.Plugins {
//додати інформацію привілей день годину хвилини
//до закінчення в інтерфейсі праворуч
//+ кольори привілеїв
[Info("Timed Permissions", "Barry_Allenn", "1.6.0")]
[Description("Allows you to grant permissions or groups for a specific time")]
class TimedPermissions : CovalencePlugin {
[PluginReference]
private Plugin ImageLibrary;
private const string AdminPermission = "timedpermissions.use";
private const string AdvancedAdminPermission = "timedpermissions.advanced";
private static TimedPermissions _plugin;
private static List<PlayerInformation> _playerInformationCollection = new List<PlayerInformation>();
private Regex _timeSpanPattern = new Regex(@"(?:(?<days>\d{1,3})d)?(?:(?<hours>\d{1,3})h)?(?:(?<minutes>\d{1,3})m)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private Configuration _config;
#region Hooks & Loading
void OnServerInitialized() {
ImageLibrary.Call("AddImage", "https://i.ibb.co/vL9zbSK/4lmBa3O.png", "timeadd");
ImageLibrary.Call("AddImage", "https://i.ibb.co/sFD89LV/4lmBa23O.png", "closetimeadd");
ImageLibrary.Call("AddImage", "https://i.ibb.co/yN0HgP0/2.png", "spinfo");
ImageLibrary.Call("AddImage", "https://i.ibb.co/gj414h6/4lmfa3O.png", "noypinfo");
}
private void Loaded() {
_plugin = this;
LoadData(ref _playerInformationCollection);
if (_playerInformationCollection == null) {
_playerInformationCollection = new List<PlayerInformation>();
SaveData(_playerInformationCollection);
}
_plugin.timer.Repeat(60, 0, () => {
for (int i = _playerInformationCollection.Count - 1; i >= 0; i--) {
PlayerInformation playerInformation = _playerInformationCollection[i];
playerInformation.Update();
}
}
);
}
private void OnUserConnected(IPlayer player) {
PlayerInformation.Get(player.Id)?.EnsureAllAccess();
}
private void OnNewSave(string filename) {
LoadConfig();
// Ensure config is loaded at this point
if (_config.WipeDataOnNewSave) {
string backupFileName;
ResetAllAccess(out backupFileName);
PrintWarning($"New save file detected: all groups and permissions revoked and data cleared.Backup created at {backupFileName}.json");
}
}
#endregion
#region Commands
[Command("pinfo")]
private void CmdPlayerInfo(IPlayer player, string cmd, string[] args) {
IPlayer target;
// Определяем цель команды
if (args.Length == 0 || !player.HasPermission(AdminPermission)) target = player;
else target = FindPlayer(args[0], player);
if (target == null) return;
var information = PlayerInformation.Get(target.Id);
if (information == null) {
// Если информации о группах нет, показываем соответствующее сообщение
ShowNoPrivilegesUI(player);
}
else {
// Показываем только группы
ShowRemainingGroupsUI(player, information);
}
}
private void ShowRemainingGroupsUI(IPlayer player, PlayerInformation information) {
var container = new CuiElementContainer();
string panelName = CuiHelper.GetGuid();
// Добавляем основную панель с полупрозрачным фоном
container.Add(new CuiPanel {
Image = {
Color = "0 0 0 0"
}
, // Полупрозрачный чёрный фон
RectTransform = {
AnchorMin = "0.4 0.4", AnchorMax = "0.6 0.6"
}
, CursorEnabled = false
}
, "Hud", panelName);
// Добавляем растянутую картинку на всю панель
container.Add(new CuiElement {
Parent = panelName, Components = {
new CuiRawImageComponent {
Png = (string) ImageLibrary.Call("GetImage", "spinfo")
}
, // Картинка
new CuiRectTransformComponent {
AnchorMin = "2.2 -0.5", // Нижний левый угол совпадает с панелью
AnchorMax = "3 0.7" // Верхний правый угол совпадает с панелью
}
}
}
);
// Уникальные группы
var uniqueGroups = information.Groups.GroupBy(g => g.Value) // Группируем по названию группы.Select(g => g.First()) // Берём первый элемент из каждой группы.ToList();
string groupInfo;
if (uniqueGroups.Any()) {
groupInfo = string.Join("\n", uniqueGroups.Select(g => {
var timeRemaining = g.ExpireDate - DateTime.UtcNow;
string timeText = GetTimeRemaining(timeRemaining);
return lang.GetMessage("Group Info Item", this, player.Id).Replace("{group}", $"<color={GetPrivilegeColor(g.Value)}>{CapitalizeFull(g.Value)}</color>").Replace("{time}", timeText);
}
));
}
else {
groupInfo = lang.GetMessage("No Groups", this, player.Id);
}
// Добавляем текстовую информацию поверх картинки
container.Add(new CuiLabel {
Text = {
Text = $"{lang.GetMessage("Group Info Header", this, player.Id)}", FontSize = 13, Align = TextAnchor.UpperLeft, Color = "1 1 1 1"
}
, RectTransform = {
AnchorMin = "2.5 0.55", AnchorMax = "3.1 0.66"
}
}
, panelName);
container.Add(new CuiLabel {
Text = {
Text = $"{groupInfo}", FontSize = 13, Align = TextAnchor.UpperLeft, Color = "1 1 1 1"
}
, RectTransform = {
AnchorMin = "2.33 -0.5", AnchorMax = "3.1 0.45"
}
}
, panelName);
CuiHelper.AddUi(player.Object as BasePlayer, container);
// Удаление UI через 10 секунд
timer.Once(5f, () => CuiHelper.DestroyUi(player.Object as BasePlayer, panelName));
}
// показ нету
private void ShowNoPrivilegesUI(IPlayer player) {
var container = new CuiElementContainer();
string panelName = CuiHelper.GetGuid();
container.Add(new CuiPanel {
Image = {
Color = "0 0 0 0"
}
, // Полупрозрачный чёрный фон
RectTransform = {
AnchorMin = "0.4 0.4", AnchorMax = "0.6 0.6"
}
, CursorEnabled = false
}
, "Hud", panelName);
// Добавляем растянутую картинку на всю панель
container.Add(new CuiElement {
Parent = panelName, Components = {
new CuiRawImageComponent {
Png = (string) ImageLibrary.Call("GetImage", "noypinfo")
}
, new CuiRectTransformComponent {
AnchorMin = "2 0", AnchorMax = "3.02 0.45", OffsetMax = "0 0"
}
}
}
);
container.Add(new CuiLabel {
Text = {
Text = $"{lang.GetMessage("No Groups", this, player.Id)}", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "1 1 1 1"
}
, RectTransform = {
AnchorMin = "2 0", AnchorMax = "3.02 0.45"
}
}
, panelName);
CuiHelper.AddUi(player.Object as BasePlayer, container);
// Удаление UI через 5 секунд
timer.Once(5f, () => CuiHelper.DestroyUi(player.Object as BasePlayer, panelName));
}
private string GetPrivilegeColor(string privilegeName) {
// Применяем цвет в зависимости от привилегии
return _privilegeColors.ContainsKey(privilegeName.ToLower()) ? _privilegeColors[privilegeName.ToLower()] : "#FFFFFF";
// Белый цвет по умолчанию
}
private string FormatWithYellowColor(string value) {
// Делаем весь текст заглавным и добавляем тег для жёлтого цвета
return $"<color=#FFFF00>{value.ToUpper()}</color>";
}
private string GetTimeRemaining(TimeSpan timeRemaining) {
int days = (int)timeRemaining.TotalDays;
// Количество дней
int hours = timeRemaining.Hours;
// Количество часов
int minutes = timeRemaining.Minutes;
// Количество минут
// Возвращаем строку с количеством дней, часов и минут
return $"{days} d {hours} h {minutes} m";
// Используем для англ.языка, изменим в локализации для русс.и укр.}
private string CapitalizeFull(string value) {
if (string.IsNullOrEmpty(value)) return value;
return value.ToUpper();
// Преобразуем всю строку в верхний регистр
}
private readonly Dictionary<string, string> _privilegeColors = new Dictionary<string, string> {
{
"vip", "#FFFF01"
}
, // Жёлтый для VIP
{
"archon", "#ff4500"
}
, // Красный для admin
{
"elita", "#9d00ff"
}
, // Синий для moderator
{
"deluxe", "#00ccff"
}
, // Зелёный для elita
{
"premium", "#00FF7F"
}
, // Зелёный для elita
{
"default", "#FFFFFF"
}
// Белый для остальных
}
;
[Command("grantperm"), Permission(AdminPermission)]
private void CmdGrantPerm(IPlayer player, string cmd, string[] args) {
if (args.Length != 3) {
player.Reply(GetMessage("Syntax : grantperm", player.Id));
return;
}
IPlayer target = FindPlayer(args[0], player);
TimeSpan duration;
if (target == null) return;
if (!TryParseTimeSpan(args[2], out duration)) {
player.Reply(GetMessage("Invalid Time Format", player.Id));
return;
}
PlayerInformation.GetOrCreate(target).AddPermission(args[1].ToLower(), DateTime.UtcNow + duration);
}
[Command("revokeperm"), Permission(AdminPermission)]
private void CmdRevokePerm(IPlayer player, string cmd, string[] args) {
if (args.Length != 2) {
player.Reply(GetMessage("Syntax : revokeperm", player.Id));
return;
}
IPlayer target = FindPlayer(args[0], player);
if (target == null) return;
PlayerInformation information = PlayerInformation.Get(target.Id);
if (information == null || !information.Permissions.Any(p => p.Value == args[1].ToLower())) {
player.Reply(GetMessage("User Doesn't Have Permission", player.Id).Replace("{target}", target.Name).Replace("{permission}", args[1].ToLower()));
return;
}
information.RemovePermission(args[1].ToLower());
}
[Command("addgroup"), Permission(AdminPermission)]
private void CmdAddGroup(IPlayer player, string cmd, string[] args) {
if (args.Length != 3) {
player.Reply(GetMessage("Syntax : addgroup", player.Id));
return;
}
IPlayer target = FindPlayer(args[0], player);
TimeSpan duration;
if (target == null) return;
if (!TryParseTimeSpan(args[2], out duration)) {
player.Reply(GetMessage("Invalid Time Format", player.Id));
return;
}
PlayerInformation.GetOrCreate(target).AddGroup(args[1], DateTime.UtcNow + duration);
}
[Command("removegroup"), Permission(AdminPermission)]
private void CmdRemoveGroup(IPlayer player, string cmd, string[] args) {
if (args.Length != 2) {
player.Reply(GetMessage("Syntax : removegroup", player.Id));
return;
}
IPlayer target = FindPlayer(args[0], player);
if (target == null) return;
PlayerInformation information = PlayerInformation.Get(target.Id);
if (information == null || !information.Groups.Any(p => p.Value == args[1].ToLower())) {
player.Reply(GetMessage("User Isn't In Group", player.Id).Replace("{target}", target.Name).Replace("{group}", args[1].ToLower()));
return;
}
information.RemoveGroup(args[1].ToLower());
}
[Command("timedpermissions_resetaccess"), Permission(AdvancedAdminPermission)]
private void CmdResetAccess(IPlayer player, string cmd, string[] args) {
if (args.Length != 1 || !args[0].Equals("yes", StringComparison.InvariantCultureIgnoreCase)) {
player.Reply(GetMessage("Syntax : resetaccess", player.Id));
player.Reply(GetMessage("Reset Access Warning", player.Id));
return;
}
string backupFileName;
ResetAllAccess(out backupFileName);
player.Reply(GetMessage("Access Reset Successfully", player.Id).Replace("{filename}", backupFileName));
}
#endregion
#region Helper Methods
private void ShowPrivilegeGrantedUI(IPlayer player, string privilegeName) {
// Получаем цвет для привилегии
string privilegeColor = GetPrivilegeColor(privilegeName);
// Формируем уведомление с цветом
string localizedMessage = lang.GetMessage("Privilege Granted", this, player.Id);
localizedMessage = string.Format(localizedMessage, $"<color={privilegeColor}>{privilegeName.ToUpper()}</color>");
// Добавляем цвет в название привилегии
CuiElementContainer container = new CuiElementContainer();
string panelName = CuiHelper.GetGuid();
// Фон панели
container.Add(new CuiPanel {
Image = {
Color = "0 0 0 0"
}
, // Полупрозрачный черный фон
RectTransform = {
AnchorMin = "0.4 0.8", AnchorMax = "0.6 0.9"
}
, CursorEnabled = false
}
, "Hud", panelName);
// (Опционально) Добавление картинки
container.Add(new CuiElement {
Parent = panelName, Components = {
new CuiRawImageComponent {
Png = (string) ImageLibrary.Call("GetImage", "timeadd")
}
, new CuiRectTransformComponent {
AnchorMin = "2 -5", AnchorMax = "3.2 -4", OffsetMax = "0 0"
}
}
}
);
// Текст сообщения
container.Add(new CuiLabel {
Text = {
Text = localizedMessage, FontSize = 11, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.8"
}
, RectTransform = {
AnchorMin = "2 -5", AnchorMax = "3.2 -4"
}
}
, panelName);
// Отображение интерфейса
CuiHelper.AddUi(player.Object as BasePlayer, container);
// Удаление интерфейса через 5 секунд
timer.Once(7f, () => {
CuiHelper.DestroyUi(player.Object as BasePlayer, panelName);
}
);
}
private void ShowPrivilegeExpiredUI(IPlayer player, string privilegeName) {
// Получаем цвет для привилегии
string privilegeColor = GetPrivilegeColor(privilegeName);
// Формируем уведомление с цветом
string localizedMessage = lang.GetMessage("Privilege Expired", this, player.Id);
localizedMessage = string.Format(localizedMessage, $"<color={privilegeColor}>{privilegeName.ToUpper()}</color>");
// Добавляем цвет в название привилегии
CuiElementContainer container = new CuiElementContainer();
string panelName = CuiHelper.GetGuid();
// Фон панели (полупрозрачный)
container.Add(new CuiPanel {
Image = {
Color = "0 0 0 0"
}
, // Полупрозрачный черный фон
RectTransform = {
AnchorMin = "0.4 0.8", AnchorMax = "0.6 0.9"
}
, CursorEnabled = false
}
, "Hud", panelName);
// Добавление картинки (можно заменить на свою)
container.Add(new CuiElement {
Parent = panelName, Components = {
new CuiRawImageComponent {
Png = (string) ImageLibrary.Call("GetImage", "closetimeadd")
}
, new CuiRectTransformComponent {
AnchorMin = "2 -5", AnchorMax = "3.2 -4", OffsetMax = "0 0"
}
}
}
);
// Текст сообщения
container.Add(new CuiLabel {
Text = {
Text = localizedMessage, FontSize = 11, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.8"
}
, RectTransform = {
AnchorMin = "2 -5", AnchorMax = "3.2 -4"
}
}
, panelName);
// Отображение интерфейса
CuiHelper.AddUi(player.Object as BasePlayer, container);
// Удаление интерфейса через 5 секунд
timer.Once(7f, () => {
CuiHelper.DestroyUi(player.Object as BasePlayer, panelName);
}
);
}
private void ResetAllAccess(out string backupFileName) {
backupFileName = $"{nameof(TimedPermissions)}_Backups/{DateTime.UtcNow.Date:yyyy-MM-dd}_{DateTime.UtcNow:T}";
SaveData(_playerInformationCollection, backupFileName);
// create backup of current data
foreach (PlayerInformation playerInformation in _playerInformationCollection) playerInformation.RemoveAllAccess();
_playerInformationCollection = new List<PlayerInformation>();
SaveData(_playerInformationCollection);
}
#region Time Helper
private bool TryParseTimeSpan(string source, out TimeSpan date) {
var match = _timeSpanPattern.Match(source);
if (!match.Success) {
date = default(TimeSpan);
return false;
}
if (!match.Groups[0].Value.Equals(source)) {
date = default(TimeSpan);
return false;
}
Group daysGroup = match.Groups["days"];
Group hoursGroup = match.Groups["hours"];
Group minutesGroup = match.Groups["minutes"];
int days = daysGroup.Success ? int.Parse(daysGroup.Value) : 0;
int hours = hoursGroup.Success ? int.Parse(hoursGroup.Value) : 0;
int minutes = minutesGroup.Success ? int.Parse(minutesGroup.Value) : 0;
if (days + hours + minutes == 0) {
date = default(TimeSpan);
return false;
}
date = new TimeSpan(days, hours, minutes, 0);
return true;
}
#endregion
#region Finding Helper
private IPlayer FindPlayer(string nameOrId, IPlayer player) {
if (IsConvertibleTo<ulong>(nameOrId) && nameOrId.StartsWith("7656119") && nameOrId.Length == 17) {
IPlayer result = players.All.ToList().Find(p => p.Id == nameOrId);
if (result == null) player.Reply($"Could not find player with ID '{nameOrId}'");
return result;
}
List<IPlayer> foundPlayers = new List<IPlayer>();
foreach (IPlayer current in players.Connected) {
if (string.Equals(current.Name, nameOrId, StringComparison.CurrentCultureIgnoreCase)) return current;
if (current.Name.ToLower().Contains(nameOrId.ToLower())) foundPlayers.Add(current);
}
switch (foundPlayers.Count) {
case 0 : player.Reply($"Could not find player with name '{nameOrId}'");
break;
case 1 : return foundPlayers[0];
default : string[] names = (from current in foundPlayers select current.Name).ToArray();
player.Reply("Multiple matching players found: \n" + string.Join(", ", names));
break;
}
return null;
}
#endregion
#region Conversion Helper
private static bool IsConvertibleTo<T>(object obj) {
try {
var temp = (T)Convert.ChangeType(obj, typeof(T));
return true;
}
catch {
return false;
}
}
#endregion
#region Data Helper
private static void LoadData<T>(ref T data, string filename = null) => data = Interface.Oxide.DataFileSystem.ReadObject<T>(filename ?? nameof(TimedPermissions));
private static void SaveData<T>(T data, string filename = null) => Interface.Oxide.DataFileSystem.WriteObject(filename ?? nameof(TimedPermissions), data);
#endregion
#region Message Wrapper
public static string GetMessage(string key, string id) => _plugin.lang.GetMessage(key, _plugin, id);
#endregion
#endregion
#region Localization
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["No Permission"]
= "You don't have permission to use this command.", ["Invalid Time Format"] = "Invalid Time Format: Ex: 1d12h30m | d = days, h = hours, m = minutes", ["Player Has No Info"] = "There is no info about this player.", ["Player Info"] = "Information for <color=#C4FF00>{player}</color>:" + Environment.NewLine + "<color=#C4FF00></color>{groups}" + Environment.NewLine + "<color=#C4FF00></color>{permissions}", ["User Doesn't Have Permission"] = "{target} does not have permission '{permission}'.", ["User Isn't In Group"] = "{target} isn't in group '{group}'.", ["Reset Access Warning"] = "This command will reset all access data and create a backup.Please confirm by calling the command with 'yes' as parameter", ["Access Reset Successfully"] = "All groups and permissions revoked and data cleared.Backup created at {filename}.json", ["Syntax : revokeperm"] = "Syntax: revokeperm <player|steamid> <permission>", ["Syntax : grantperm"] = "Syntax: removegroup <player|steamid> <group>", ["Syntax : removegroup"] = "Syntax: removegroup <player|steamid> <group>", ["Syntax : addgroup"] = "Syntax: addgroup <player|steamid> <group> <time Ex: 1d12h30m>", ["Syntax : resetaccess"] = "Syntax: timedpermissions_resetaccess [yes]", // Английский (по умолчанию)
["Privilege Granted"]
= "Privilege Granted!\n<size=17>You have successfully received {0}!</size>", ["Privilege Remaining"] = "<color={0}>{1}</color> {2} d {3} h {4} m", ["No Groups"] = "You have no Privileges.", ["Group Info Header"] = "Privileges:", ["Group Info Item"] = "{group}: {time}", ["Privilege Expired"] = "<color=#b30404><size=17>Privilege Expired!</size></color>\nPrivilege {0} has expired!"
}
, this);
// Украинский перевод
lang.RegisterMessages(new Dictionary<string, string> {
["No Permission"]
= "Ви не маєте дозволу використовувати цю команду.", ["Invalid Time Format"] = "Неправильний формат часу: Наприклад, 1д12г30х | д = дні, г = години, х = хвилини", ["Player Has No Info"] = "Немає інформації про цього гравця.", ["Player Info"] = "Інформація про <color=#C4FF00>{player}</color>:" + Environment.NewLine + "<color=#C4FF00></color>{groups}" + Environment.NewLine + "<color=#C4FF00></color>{permissions}", ["User Doesn't Have Permission"] = "{target} не має дозволу '{permission}'.", ["User Isn't In Group"] = "{target} не знаходиться у групі '{group}'.", ["Reset Access Warning"] = "Ця команда скине всі дані доступу та створить резервну копію.Будь ласка, підтвердіть, викликавши команду з параметром 'yes'.", ["Access Reset Successfully"] = "Всі групи та дозволи були скасовані, а дані очищено.Резервну копію створено: {filename}.json", ["Privilege Granted"] = "<size=17>Привілегія отримана!</size>\nВи успішно отримали {0}!", ["Privilege Remaining"] = "<color={0}>{1}</color> {2} дн.{3} год.{4} хв.", ["No Groups"] = "У вас немає Привілеїв", ["Group Info Header"] = "Привілей:", ["Group Info Item"] = "{group}: {time}", ["Privilege Expired"] = "<color=#b30404><size=17>Привілегія закінчилася!</size></color>\nПривілегія {0} закінчилася!",
}
, this, "uk");
// Русский перевод
lang.RegisterMessages(new Dictionary<string, string> {
["No Permission"]
= "У вас нет прав для использования этой команды.", ["Invalid Time Format"] = "Неверный формат времени: Например, 1д12ч30м | д = дни, ч = часы, м = минуты", ["Player Has No Info"] = "Нет информации об этом игроке.", ["Player Info"] = "Информация о <color=#C4FF00>{player}</color>:" + Environment.NewLine + "<color=#C4FF00></color>{groups}" + Environment.NewLine + "<color=#C4FF00></color>{permissions}", ["User Doesn't Have Permission"] = "{target} не имеет разрешения '{permission}'.", ["User Isn't In Group"] = "{target} не состоит в группе '{group}'.", ["Reset Access Warning"] = "Эта команда сбросит все данные доступа и создаст резервную копию.Пожалуйста, подтвердите, вызвав команду с параметром 'yes'.", ["Access Reset Successfully"] = "Все группы и разрешения удалены, а данные очищены.Резервная копия создана: {filename}.json", ["Privilege Granted"] = "<color=#039c00><size=17>Привелегия получена!</size></color>\nВы успешно получили {0}!", ["Privilege Remaining"] = "<color={0}>{1}</color> {2} дн.{3} ч.{4} мин.", ["No Groups"] = "У вас нет Привилегий", ["Group Info Header"] = "Привелегий:", ["Group Info Item"] = "{group}: {time}", ["Privilege Expired"] = "<color=#b30404><size=17>Привелегия истекла!</size></color>\nПривелегия {0} истекла!"
}
, this, "ru");
}
#endregion
#region Configuration
protected override void LoadConfig() {
base.LoadConfig();
_config = Config.ReadObject<Configuration>();
SaveConfig();
}
protected override void LoadDefaultConfig() => _config = new Configuration();
protected override void SaveConfig() => Config.WriteObject(_config);
private class Configuration {
[JsonProperty("Wipe Data on New Save (Limited to Certain Games)")]
public bool WipeDataOnNewSave {
get;
private set;
}
= false;
}
#endregion
#region Data Structures
private class PlayerInformation {
[JsonProperty("Id")]
public string Id {
get;
set;
}
[JsonProperty("Name")]
public string Name {
get;
set;
}
[JsonProperty("Permissions")]
private readonly List<ExpiringAccessValue> _permissions = new List<ExpiringAccessValue>();
[JsonProperty("Groups")]
private readonly List<ExpiringAccessValue> _groups = new List<ExpiringAccessValue>();
[JsonIgnore]
public ReadOnlyCollection<ExpiringAccessValue> Permissions => _permissions.AsReadOnly();
[JsonIgnore]
public ReadOnlyCollection<ExpiringAccessValue> Groups => _groups.AsReadOnly();
public static PlayerInformation Get(string id) => _playerInformationCollection.FirstOrDefault(p => p.Id == id);
public static PlayerInformation GetOrCreate(IPlayer player) {
PlayerInformation information = Get(player.Id);
if (information == null) {
information = new PlayerInformation(player);
_playerInformationCollection.Add(information);
SaveData(_playerInformationCollection);
}
return information;
}
#region Permissions
public void AddPermission(string permission, DateTime newExpireDate) {
ExpiringAccessValue existingAccess = _permissions.FirstOrDefault(p => p.Value == permission);
if (existingAccess != null) {
// Если привилегия уже существует, продлеваем срок относительно текущей даты окончания
existingAccess.ExpireDate = existingAccess.ExpireDate > DateTime.UtcNow ? existingAccess.ExpireDate + (newExpireDate - DateTime.UtcNow) : newExpireDate;
// Если срок истёк, задаём новый срок
_plugin.Puts($"{Name} ({Id}) - Permission extended: {permission} until {existingAccess.ExpireDate}");
}
else {
// Если привилегия новая, добавляем её
_permissions.Add(new ExpiringAccessValue(permission, newExpireDate));
_plugin.permission.GrantUserPermission(Id, permission, null);
_plugin.Puts($"{Name} ({Id}) - Permission granted: {permission} until {newExpireDate}");
}
SaveData(_playerInformationCollection);
}
public void RemovePermission(string permission) {
ExpiringAccessValue accessValue = _permissions.FirstOrDefault(p => p.Value == permission);
if (accessValue == null) {
return;
// Если привилегии нет, ничего не делаем
}
// Уведомляем игрока, что привилегия закончилась
IPlayer player = _plugin.players.FindPlayerById(Id);
if (player != null) {
_plugin.ShowPrivilegeExpiredUI(player, permission);
// Показываем уведомление
}
// Удаление привилегии
_permissions.Remove(accessValue);
_plugin.permission.RevokeUserPermission(Id, accessValue.Value);
_plugin.Puts($"{Name} ({Id}) - Permission expired: {accessValue.Value}");
// Если у игрока нет привилегий и групп, удаляем его информацию
if (_groups.Count == 0 && _permissions.Count == 0) _playerInformationCollection.Remove(this);
SaveData(_playerInformationCollection);
}
#endregion
#region Groups
public void AddGroup(string group, DateTime newExpireDate) {
ExpiringAccessValue existingAccess = _groups.FirstOrDefault(g => g.Value == group);
if (existingAccess != null) {
// Если группа уже существует, продлеваем срок относительно текущей даты окончания
existingAccess.ExpireDate = existingAccess.ExpireDate > DateTime.UtcNow ? existingAccess.ExpireDate + (newExpireDate - DateTime.UtcNow) : newExpireDate;
_plugin.Puts($"{Name} ({Id}) - Group extended: {group} until {existingAccess.ExpireDate}");
// Отправка уведомления в Discord о продлении
_plugin.DiscordSendMessage($"{ConVar.Server.hostname}", "", "", $"{Name} ({Id}) - Привилегия продлена: {group}", $"на {existingAccess.ExpireDate - DateTime.UtcNow}" );
}
else {
// Если группа новая, добавляем её
_groups.Add(new ExpiringAccessValue(group, newExpireDate));
_plugin.permission.AddUserGroup(Id, group);
_plugin.Puts($"{Name} ({Id}) - Group added: {group} until {newExpireDate}");
// Отправка уведомления в Discord о выдаче
_plugin.DiscordSendMessage($"{ConVar.Server.hostname}", "", "", $"{Name} ({Id}) - Выдана привилегия: {group}", $"на {newExpireDate - DateTime.UtcNow}" );
}
SaveData(_playerInformationCollection);
}
public void RemoveGroup(string group) {
var accessValue = _groups.FirstOrDefault(g => g.Value == group);
if (accessValue == null) throw new ArgumentException("Player does not have access to the given group", nameof(group));
// Уведомляем игрока, что группа закончилась
IPlayer player = _plugin.players.FindPlayerById(Id);
if (player != null) {
_plugin.ShowPrivilegeExpiredUI(player, group);
// Показываем уведомление
}
// Удаление группы
_groups.Remove(accessValue);
_plugin.permission.RemoveUserGroup(Id, accessValue.Value);
_plugin.Puts($"{Name} ({Id}) - Группа закончилась: {accessValue.Value}");
// Удаление информации о игроке, если нет других групп или привилегий
if (_groups.Count == 0 && _permissions.Count == 0) _playerInformationCollection.Remove(this);
_plugin.DiscordSendMessage($"{ConVar.Server.hostname}", "", "", $"{Name} ({Id}) - скінчилась: {accessValue.Value}", $"");
SaveData(_playerInformationCollection);
}
#endregion
#region Other
public void RemoveAllAccess() {
foreach (ExpiringAccessValue permission in _permissions) _plugin.permission.RevokeUserPermission(Id, permission.Value);
_permissions.Clear();
foreach (ExpiringAccessValue group in _groups) _plugin.permission.RemoveUserGroup(Id, group.Value);
_groups.Clear();
}
public void EnsureAllAccess() {
foreach (ExpiringAccessValue permission in _permissions) _plugin.permission.GrantUserPermission(Id, permission.Value, null);
foreach (ExpiringAccessValue group in _groups) _plugin.permission.AddUserGroup(Id, group.Value);
}
public void Update() {
foreach (ExpiringAccessValue permission in _permissions.ToList()) if (permission.IsExpired) RemovePermission(permission.Value);
foreach (ExpiringAccessValue group in _groups.ToList()) if (group.IsExpired) RemoveGroup(group.Value);
}
#endregion
public override int GetHashCode() => Id.GetHashCode();
private PlayerInformation(IPlayer player) {
Id = player.Id;
Name = player.Name;
}
[JsonConstructor]
private PlayerInformation() {
}
}
private class ExpiringAccessValue {
[JsonProperty]
public string Value {
get;
private set;
}
[JsonProperty]
public DateTime ExpireDate {
get;
set;
}
[JsonIgnore]
public bool IsExpired => DateTime.Compare(DateTime.UtcNow, ExpireDate) > 0;
public override int GetHashCode() => Value.GetHashCode();
public ExpiringAccessValue(string value, DateTime expireDate) {
Value = value;
ExpireDate = expireDate;
}
public ExpiringAccessValue() {
}
}
#endregion
void DiscordSendMessage(string n, string p, string p2, string p3, string p4) {
if (String.IsNullOrEmpty(WebHook)) return;
List<Fields> fields = new List<Fields> {
new Fields(p, p2, false), new Fields(p3, p4, false),
}
;
FancyMessage newMessage = new FancyMessage(null, false, new FancyMessage.Embeds[1] {
new FancyMessage.Embeds(null, 525133, fields, new Authors(n, ConVar.Server.url, ConVar.Server.headerimage, null), new Footer("Author: Barry_Allenn", "https://i.ibb.co/3F2B8cn/photo-2024-11-05-01-44-42.jpg", ""))
}
);
Request($"{WebHook}", newMessage.toJSON());
}
string WebHook = "https://discord.com/api/webhooks/1303142599854657548/aILeUM7Ure6XehVRgsApwkI_mqrpVjvijG0yp35VBnrI8bECjB_0svi0Oe3FbEeIn39G";
public class FancyMessage {
public string content {
get;
set;
}
public bool tts {
get;
set;
}
public Embeds[] embeds {
get;
set;
}
public class Embeds {
public string title {
get;
set;
}
public int color {
get;
set;
}
public List<Fields> fields {
get;
set;
}
public Footer footer {
get;
set;
}
public Authors author {
get;
set;
}
public Embeds(string title, int color, List<Fields> fields, Authors author, Footer footer) {
this.title = title;
this.color = color;
this.fields = fields;
this.author = author;
this.footer = footer;
}
}
public FancyMessage(string content, bool tts, Embeds[] embeds) {
this.content = content;
this.tts = tts;
this.embeds = embeds;
}
public string toJSON() => JsonConvert.SerializeObject(this);
}
public class Footer {
public string text {
get;
set;
}
public string icon_url {
get;
set;
}
public string proxy_icon_url {
get;
set;
}
public Footer(string text, string icon_url, string proxy_icon_url) {
this.text = text;
this.icon_url = icon_url;
this.proxy_icon_url = proxy_icon_url;
}
}
public class Authors {
public string name {
get;
set;
}
public string url {
get;
set;
}
public string icon_url {
get;
set;
}
public string proxy_icon_url {
get;
set;
}
public Authors(string name, string url, string icon_url, string proxy_icon_url) {
this.name = name;
this.url = url;
this.icon_url = icon_url;
this.proxy_icon_url = proxy_icon_url;
}
}
public class Fields {
public string name {
get;
set;
}
public string value {
get;
set;
}
public bool inline {
get;
set;
}
public Fields(string name, string value, bool inline) {
this.name = name;
this.value = value;
this.inline = inline;
}
}
private void Request(string url, string payload, Action<int> callback = null) {
Dictionary<string, string> header = new Dictionary<string, string>();
header.Add("Content-Type", "application/json");
webrequest.Enqueue(url, payload, (code, response) => {
if (code != 200 && code != 204) {
if (response != null) {
try {
JObject json = JObject.Parse(response);
if (code == 429) {
float seconds = float.Parse(Math.Ceiling((double)(int)json["retry_after"] / 1000).ToString());
}
else {
PrintWarning($" Discord rejected that payload! Responded with \"{json["message"].ToString()}\" Code: {code}");
}
}
catch {
PrintWarning($"Failed to get a valid response from discord! Error: \"{response}\" Code: {code}");
}
}
else {
PrintWarning($"Discord didn't respond (down?) Code: {code}");
}
}
try {
callback?.Invoke(code);
}
catch (Exception ex) {
}
}
, this, RequestMethod.POST, header);
}
}
}