C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Rust;
using System.IO;
using System.Text.RegularExpressions;
namespace Oxide.Plugins
{
[Info("SQFrozen", "BLOOD KRAKEN", "2.3.1")]
[Description("Freeze your VIP/Premium/Elite groups to save time - Timer Pause Edition")]
class SQFrozen : RustPlugin
{
#region References
[PluginReference]
Plugin ImageLibrary, IQPermissions, IQEconomic;
#endregion
#region Config
private Configuration config;
public class Configuration
{
[JsonProperty("URL images")]
public ImagesConfig Images = new ImagesConfig();
[JsonProperty("Groups")]
public Dictionary<string, GroupConfig> Groups = new Dictionary<string, GroupConfig>
{
["vip"] = new GroupConfig
{
DisplayName = "VIP",
ImageUrl = "https://i.yapx.ru/c6DS6.png",
FrozenImageUrl = "https://i.yapx.ru/c6DUc.png",
Aliases = new List<string> { "vip" }
},
["premium"] = new GroupConfig
{
DisplayName = "PREMIUM",
ImageUrl = "https://i.yapx.ru/c6C5n.png",
FrozenImageUrl = "https://i.yapx.ru/c6DUc.png",
Aliases = new List<string> { "premium" }
},
["elita"] = new GroupConfig
{
DisplayName = "ELITE",
ImageUrl = "https://i.yapx.ru/c6CvG.png",
FrozenImageUrl = "https://i.yapx.ru/c6DUc.png",
Aliases = new List<string> { "elita", "elite" }
}
};
[JsonProperty("Days per snowflake")]
public int DaysPerSnowflake = 7;
[JsonProperty("Snowflake price")]
public int SnowflakePrice = 100;
[JsonProperty("Max snowflakes")]
public int MaxSnowflakes = 6;
[JsonProperty("UI Scale (0.1 - 1.0)")]
public float UIScale = 0.65f;
[JsonProperty("Debug mode (console logs)")]
public bool DebugMode = true;
[JsonProperty("Snowflake item shortname")]
public string SnowflakeItem = "bleach";
[JsonProperty("Snowflake skin ID")]
public ulong SnowflakeSkin = 3665432012;
[JsonProperty("Настройка физической валюты (Тип 1 - предмет в инвентаре)")]
public CurrencyConfig PhysicalCurrency = new CurrencyConfig
{
Enabled = true,
Shortname = "sticks",
SkinID = 3629342280,
DisplayName = "BLKR"
};
[JsonProperty("Настройка электронной валюты (Тип 2 - IQEconomic)")]
public ElectronicCurrencyConfig ElectronicCurrency = new ElectronicCurrencyConfig
{
Enabled = false,
PluginName = "IQEconomic"
};
[JsonProperty("Return snowflakes on early unfreeze")]
public bool ReturnSnowflakesOnEarlyUnfreeze = true;
}
public class ImagesConfig
{
public string Background = "https://i.yapx.ru/c593r.png";
public string CloseButton = "https://i.yapx.ru/c6CrX.png";
public string FreezeButton = "https://i.yapx.ru/c6CNM.png";
public string UnfreezeButton = "https://i.yapx.ru/c6CSX.png";
public string BuyButton = "https://i.yapx.ru/c6C4z.png";
public string CheckboxActive = "https://i.yapx.ru/c6Cnr.png";
public string SnowflakeActive = "https://i.yapx.ru/c6C7G.png";
public string SnowflakeInactive = "https://i.yapx.ru/c6DBR.png";
public string SnowflakeSelected = "https://i.yapx.ru/c6DHE.png";
public string CanFreezeIcon = "https://i.yapx.ru/c6DYE.png";
public string FrozenIcon = "https://i.yapx.ru/c6DUc.png";
}
public class GroupConfig
{
public string DisplayName;
public string ImageUrl;
public string FrozenImageUrl;
public List<string> Aliases = new List<string>();
}
public class CurrencyConfig
{
[JsonProperty("Включить физическую валюту")]
public bool Enabled = true;
[JsonProperty("Shortname")]
public string Shortname = "sticks";
[JsonProperty("SkinID")]
public ulong SkinID = 3629342280;
[JsonProperty("Отображаемое имя")]
public string DisplayName = "BLKR";
}
public class ElectronicCurrencyConfig
{
[JsonProperty("Включить электронную валюту")]
public bool Enabled = false;
[JsonProperty("Название плагина (IQEconomic/Economics/ServerRewards)")]
public string PluginName = "IQEconomic";
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null) throw new Exception();
}
catch
{
PrintWarning("Creating default config");
config = new Configuration();
SaveConfig();
}
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultConfig() => config = new Configuration();
#endregion
#region Data
private FrozenData frozenData;
private Dictionary<ulong, Dictionary<string, DateTime>> playerGroupExpiry = new Dictionary<ulong, Dictionary<string, DateTime>>();
private Dictionary<ulong, int> playerSelectedSnowflakes = new Dictionary<ulong, int>();
private Dictionary<ulong, string> playerSelectedGroup = new Dictionary<ulong, string>();
private const string DataPath = "SQFrozen/players/FrozenPermissions";
private const string ExpiryDataPath = "SQFrozen/players/GroupExpiry";
private string IQPermissionsDataPath => Path.Combine(Interface.Oxide.DataDirectory, "IQSystem", "IQPermissions", "Permissions.json");
public class FrozenData : Dictionary<ulong, Dictionary<string, FrozenGroupInfo>> {}
public class FrozenGroupInfo
{
public DateTime FrozenAt;
public DateTime OriginalExpiry;
public int SnowflakesUsed;
public TimeSpan RemainingTime;
public string TimeFormat;
public DateTime UnfreezeDate;
}
private void LoadData()
{
frozenData = Interface.Oxide.DataFileSystem.ReadObject<FrozenData>(DataPath) ?? new FrozenData();
playerGroupExpiry = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, Dictionary<string, DateTime>>>(ExpiryDataPath) ?? new Dictionary<ulong, Dictionary<string, DateTime>>();
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(DataPath, frozenData);
Interface.Oxide.DataFileSystem.WriteObject(ExpiryDataPath, playerGroupExpiry);
}
#endregion
#region Group Mapping Helpers
private string FindConfigGroupKey(string iqGroupName)
{
if (string.IsNullOrEmpty(iqGroupName)) return null;
string searchName = iqGroupName.ToLower();
foreach (var kvp in config.Groups)
{
string configKey = kvp.Key.ToLower();
var groupConfig = kvp.Value;
if (configKey == searchName)
return kvp.Key;
if (groupConfig.DisplayName?.ToLower() == searchName)
return kvp.Key;
if (groupConfig.Aliases != null)
{
foreach (var alias in groupConfig.Aliases)
{
if (alias?.ToLower() == searchName)
return kvp.Key;
}
}
}
return null;
}
private bool IsKnownGroup(string iqGroupName)
{
return FindConfigGroupKey(iqGroupName) != null;
}
private string GetNormalizedGroupKey(string groupName)
{
var configKey = FindConfigGroupKey(groupName);
return configKey ?? groupName.ToLower();
}
#endregion
#region Hooks
private void OnServerInitialized()
{
LoadData();
RegisterImages();
permission.RegisterPermission("sqfrozen.admin", this);
permission.RegisterPermission("sqfrozen.use", this);
timer.Every(3600f, CheckExpiredFrozenGroups);
if (IQPermissions == null)
{
PrintWarning("IQPermissions not found!");
}
else
{
PrintWarning("IQPermissions found.");
}
if (config.PhysicalCurrency.Enabled)
{
PrintWarning($"Using PHYSICAL currency: {config.PhysicalCurrency.Shortname} (Skin: {config.PhysicalCurrency.SkinID})");
}
else if (config.ElectronicCurrency.Enabled)
{
PrintWarning($"Using ELECTRONIC currency: {config.ElectronicCurrency.PluginName}");
}
}
private void OnPlayerDisconnected(BasePlayer player)
{
playerSelectedSnowflakes.Remove(player.userID);
playerSelectedGroup.Remove(player.userID);
}
private void Unload()
{
SaveData();
foreach (var player in BasePlayer.activePlayerList)
{
CuiHelper.DestroyUi(player, "SQFrozen_Main");
}
}
private void CheckExpiredFrozenGroups()
{
bool changed = false;
var now = DateTime.Now;
foreach (var playerData in frozenData.ToList())
{
foreach (var groupData in playerData.Value.ToList())
{
var info = groupData.Value;
if (now > info.UnfreezeDate)
{
ReturnGroup(playerData.Key, groupData.Key, info);
playerData.Value.Remove(groupData.Key);
changed = true;
}
}
if (playerData.Value.Count == 0)
frozenData.Remove(playerData.Key);
}
if (changed)
SaveData();
}
#endregion
#region ImageLibrary
private void RegisterImages()
{
if (ImageLibrary == null)
{
PrintError("ImageLibrary not found!");
return;
}
ImageLibrary.Call("AddImage", config.Images.Background, "SQFrozen_BG", 0UL);
ImageLibrary.Call("AddImage", config.Images.CloseButton, "SQFrozen_Close", 0UL);
ImageLibrary.Call("AddImage", config.Images.FreezeButton, "SQFrozen_Freeze", 0UL);
ImageLibrary.Call("AddImage", config.Images.UnfreezeButton, "SQFrozen_Unfreeze", 0UL);
ImageLibrary.Call("AddImage", config.Images.BuyButton, "SQFrozen_Buy", 0UL);
ImageLibrary.Call("AddImage", config.Images.CheckboxActive, "SQFrozen_CheckOn", 0UL);
ImageLibrary.Call("AddImage", config.Images.SnowflakeActive, "SQFrozen_SnowOn", 0UL);
ImageLibrary.Call("AddImage", config.Images.SnowflakeInactive, "SQFrozen_SnowOff", 0UL);
ImageLibrary.Call("AddImage", config.Images.SnowflakeSelected, "SQFrozen_SnowSel", 0UL);
ImageLibrary.Call("AddImage", config.Images.CanFreezeIcon, "SQFrozen_CanFreeze", 0UL);
ImageLibrary.Call("AddImage", config.Images.FrozenIcon, "SQFrozen_FrozenStatus", 0UL);
foreach (var group in config.Groups)
{
ImageLibrary.Call("AddImage", group.Value.ImageUrl, $"SQFrozen_Group_{group.Key}", 0UL);
ImageLibrary.Call("AddImage", group.Value.FrozenImageUrl, $"SQFrozen_Group_{group.Key}_Frozen", 0UL);
}
}
private string GetImage(string name)
{
if (ImageLibrary == null) return "";
return ImageLibrary.Call<string>("GetImage", name) ?? "";
}
#endregion
#region Commands
[ChatCommand("frozen")]
private void cmdFrozen(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, "sqfrozen.use"))
{
player.ChatMessage("<color=red>No permission!</color>");
return;
}
if (!playerSelectedSnowflakes.ContainsKey(player.userID))
playerSelectedSnowflakes[player.userID] = 1;
RefreshPlayerGroupData(player);
if (config.DebugMode)
{
DebugPlayerGroups(player);
}
OpenMainUI(player);
}
[ChatCommand("givesnow")]
private void cmdGiveSnow(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, "sqfrozen.admin"))
{
player.ChatMessage("<color=red>Нет доступа!</color>");
return;
}
int amount = 1;
if (args.Length > 0 && int.TryParse(args[0], out int parsedAmount))
{
amount = parsedAmount;
}
GiveSnowflakes(player, amount);
player.ChatMessage($"<color=green>Вы выдали себе {amount} снежинок!</color>");
}
[ChatCommand("setgrouptime")]
private void cmdSetGroupTime(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, "sqfrozen.admin"))
{
player.ChatMessage("<color=red>Нет доступа!</color>");
return;
}
if (args.Length < 2)
{
player.ChatMessage("<color=yellow>Использование: /setgrouptime <группа> <дни></color>");
return;
}
string group = args[0].ToLower();
if (!int.TryParse(args[1], out int days))
{
player.ChatMessage("<color=red>Укажите количество дней числом!</color>");
return;
}
if (!config.Groups.ContainsKey(group))
{
player.ChatMessage($"<color=red>Группа {group} не найдена в конфиге!</color>");
return;
}
if (!playerGroupExpiry.ContainsKey(player.userID))
playerGroupExpiry[player.userID] = new Dictionary<string, DateTime>();
playerGroupExpiry[player.userID][group] = DateTime.Now.AddDays(days);
SaveData();
player.ChatMessage($"<color=green>Группе {config.Groups[group].DisplayName} установлено время: {days} дней!</color>");
}
[ConsoleCommand("sqfrozen.select")]
private void ccmdSelect(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null || arg.Args == null || arg.Args.Length < 1) return;
string group = arg.Args[0].ToLower();
if (!config.Groups.ContainsKey(group)) return;
playerSelectedGroup[player.userID] = group;
if (!playerSelectedSnowflakes.ContainsKey(player.userID))
playerSelectedSnowflakes[player.userID] = 1;
OpenMainUI(player, group);
}
[ConsoleCommand("sqfrozen.snowflake")]
private void ccmdSnowflake(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null || arg.Args == null || arg.Args.Length < 2) return;
string group = arg.Args[0].ToLower();
if (!int.TryParse(arg.Args[1], out int count)) return;
int playerSnowflakes = CountSnowflakes(player);
count = Mathf.Clamp(count, 1, Mathf.Min(config.MaxSnowflakes, playerSnowflakes));
playerSelectedSnowflakes[player.userID] = count;
OpenMainUI(player, group);
}
[ConsoleCommand("sqfrozen.freeze")]
private void ccmdFreeze(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null || arg.Args == null || arg.Args.Length < 1) return;
string group = arg.Args[0].ToLower();
int snowflakes = playerSelectedSnowflakes.GetValueOrDefault(player.userID, 1);
int playerSnowflakes = CountSnowflakes(player);
if (playerSnowflakes < snowflakes)
{
player.ChatMessage($"<color=red>Недостаточно снежинок! Нужно: {snowflakes}, есть: {playerSnowflakes}</color>");
return;
}
FreezeGroup(player, group, snowflakes);
}
[ConsoleCommand("sqfrozen.unfreeze")]
private void ccmdUnfreeze(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null || arg.Args == null || arg.Args.Length < 1) return;
string group = arg.Args[0].ToLower();
UnfreezeGroup(player, group);
}
[ConsoleCommand("sqfrozen.buy")]
private void ccmdBuy(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null) return;
BuySnowflake(player);
}
[ConsoleCommand("sqfrozen.close")]
private void ccmdClose(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null) return;
CuiHelper.DestroyUi(player, "SQFrozen_Main");
playerSelectedSnowflakes.Remove(player.userID);
playerSelectedGroup.Remove(player.userID);
}
[ConsoleCommand("givefrozen")]
private void ccmdGiveFrozen(ConsoleSystem.Arg arg)
{
if (arg.Player() != null && !permission.UserHasPermission(arg.Player().UserIDString, "sqfrozen.admin"))
{
arg.ReplyWith("No permission");
return;
}
if (arg.Args == null || arg.Args.Length < 2)
{
arg.ReplyWith("Usage: givefrozen <steamid> <amount>");
return;
}
if (!ulong.TryParse(arg.Args[0], out ulong steamId) || !int.TryParse(arg.Args[1], out int amount))
{
arg.ReplyWith("Invalid arguments");
return;
}
var target = BasePlayer.FindByID(steamId);
if (target != null)
{
GiveSnowflakes(target, amount);
arg.ReplyWith($"Gave {amount} snowflakes to {steamId}");
if (target.IsConnected)
target.ChatMessage($"<color=cyan>[SQFrozen]</color> You got <color=yellow>{amount}</color> snowflakes!");
}
else
{
arg.ReplyWith("Player not found");
}
}
[ConsoleCommand("sqfrozen.debug")]
private void ccmdDebug(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, "sqfrozen.admin"))
{
player.ChatMessage("<color=red>No permission!</color>");
return;
}
DebugPlayerGroups(player);
player.ChatMessage("<color=green>Debug info printed to console!</color>");
}
[ConsoleCommand("sqfrozen.refresh")]
private void ccmdRefresh(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if (player == null) return;
RefreshPlayerGroupData(player);
player.ChatMessage("<color=green>Данные групп обновлены!</color>");
OpenMainUI(player);
}
#endregion
#region Debug
private void DebugPlayerGroups(BasePlayer player)
{
Puts($"=== SQFrozen Debug for {player.displayName} ({player.userID}) ===");
var iqData = GetIQPermissionsGroupData(player.userID);
Puts($"IQPermissions groups found: {iqData.Count}");
foreach (var kvp in iqData)
{
string mappedKey = FindConfigGroupKey(kvp.Key);
Puts($" IQ: '{kvp.Key}' -> Config: '{mappedKey ?? "NOT MAPPED"}', Expiry: {kvp.Value:O}");
}
Puts($"Oxide groups: {string.Join(", ", permission.GetUserGroups(player.UserIDString))}");
var allGroups = GetAllPlayerGroups(player);
Puts($"All groups found: {string.Join(", ", allGroups)}");
if (playerGroupExpiry.ContainsKey(player.userID))
{
Puts("Stored expiry times:");
foreach (var kvp in playerGroupExpiry[player.userID])
{
Puts($" {kvp.Key}: {kvp.Value:dd.MM.yyyy HH:mm}");
}
}
if (frozenData.ContainsKey(player.userID))
{
Puts("Frozen groups:");
foreach (var kvp in frozenData[player.userID])
{
var info = kvp.Value;
int daysLeft = (info.UnfreezeDate - DateTime.Now).Days;
Puts($" {kvp.Key}: FrozenAt={info.FrozenAt}, UnfreezeDate={info.UnfreezeDate}, RemainingTime={info.RemainingTime.Days}d {info.RemainingTime.Hours}h, DaysLeft={daysLeft}");
}
}
Puts($"Snowflakes in inventory: {CountSnowflakes(player)} (item: {config.SnowflakeItem}, skin: {config.SnowflakeSkin})");
Puts($"Currency balance: {GetCurrencyBalance(player)} {GetCurrencyName()}");
Puts("=== End Debug ===");
}
#endregion
#region IQPermissions Integration
private void RefreshPlayerGroupData(BasePlayer player)
{
if (player == null) return;
try
{
var iqGroups = GetIQPermissionsGroupData(player.userID);
if (!playerGroupExpiry.ContainsKey(player.userID))
playerGroupExpiry[player.userID] = new Dictionary<string, DateTime>();
foreach (var kvp in iqGroups)
{
string iqGroupName = kvp.Key;
DateTime expiry = kvp.Value;
string configKey = FindConfigGroupKey(iqGroupName);
if (configKey == null)
{
if (config.DebugMode)
{
Puts($"[Refresh] Unknown group '{iqGroupName}' - skipping or using raw name");
}
configKey = iqGroupName.ToLower();
}
if (expiry > DateTime.Now)
{
playerGroupExpiry[player.userID][configKey] = expiry;
if (config.DebugMode)
{
Puts($"[Refresh] Updated {player.displayName} - IQ: '{iqGroupName}' -> Config: '{configKey}', Expiry: {expiry:dd.MM.yyyy HH:mm}");
}
}
}
var groupsToRemove = new List<string>();
foreach (var groupKey in playerGroupExpiry[player.userID].Keys.ToList())
{
bool foundInIQ = false;
foreach (var iqKvp in iqGroups)
{
if (GetNormalizedGroupKey(iqKvp.Key) == groupKey)
{
foundInIQ = true;
break;
}
}
if (!foundInIQ)
{
bool isFrozen = frozenData.ContainsKey(player.userID) &&
frozenData[player.userID].ContainsKey(groupKey);
if (!isFrozen)
{
groupsToRemove.Add(groupKey);
}
}
}
foreach (var groupKey in groupsToRemove)
{
playerGroupExpiry[player.userID].Remove(groupKey);
if (config.DebugMode)
{
Puts($"[Refresh] Removed expired group {groupKey} for {player.displayName}");
}
}
if (playerGroupExpiry[player.userID].Count == 0)
playerGroupExpiry.Remove(player.userID);
SaveData();
if (config.DebugMode)
{
Puts($"[Refresh] Completed for {player.displayName}. Active groups: {iqGroups.Count}");
}
}
catch (Exception ex)
{
PrintError($"Error refreshing player data: {ex.Message}");
}
}
private Dictionary<string, DateTime> GetIQPermissionsGroupData(ulong userID)
{
var result = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);
try
{
if (!File.Exists(IQPermissionsDataPath))
return result;
string json = File.ReadAllText(IQPermissionsDataPath);
var data = JObject.Parse(json);
var groupsData = data["Информация о группах игрока"] as JObject;
if (groupsData == null) return result;
string userIdStr = userID.ToString();
foreach (var group in groupsData.Properties())
{
var players = group.Value as JObject;
if (players == null) continue;
if (players[userIdStr] != null)
{
string dateStr = players[userIdStr].ToString();
if (DateTime.TryParse(dateStr, out DateTime expiry))
{
result[group.Name] = expiry;
}
}
}
}
catch (Exception ex)
{
Puts($"Error reading IQPermissions data: {ex.Message}");
}
return result;
}
private string FormatTimeForIQPermissions(TimeSpan time)
{
var parts = new List<string>();
if (time.Days > 0)
parts.Add($"{time.Days}d");
if (time.Hours > 0)
parts.Add($"{time.Hours}h");
if (time.Minutes > 0)
parts.Add($"{time.Minutes}m");
if (time.Seconds > 0 && time.Days == 0)
parts.Add($"{time.Seconds}s");
return string.Join(" ", parts);
}
#endregion
#region Currency System
private int GetCurrencyBalance(BasePlayer player)
{
if (config.PhysicalCurrency.Enabled)
{
return CountPhysicalCurrency(player);
}
else if (config.ElectronicCurrency.Enabled)
{
return GetElectronicBalance(player);
}
return 0;
}
private bool RemoveCurrency(BasePlayer player, int amount)
{
if (config.PhysicalCurrency.Enabled)
{
return RemovePhysicalCurrency(player, amount);
}
else if (config.ElectronicCurrency.Enabled)
{
return RemoveElectronicBalance(player, amount);
}
return false;
}
private string GetCurrencyName()
{
if (config.PhysicalCurrency.Enabled)
{
return config.PhysicalCurrency.DisplayName;
}
else if (config.ElectronicCurrency.Enabled)
{
return config.ElectronicCurrency.PluginName;
}
return "UNKNOWN";
}
#region Physical Currency
private int CountPhysicalCurrency(BasePlayer player)
{
int count = 0;
var containerList = new List<ItemContainer>
{
player.inventory.containerMain,
player.inventory.containerBelt,
player.inventory.containerWear
};
foreach (var container in containerList)
{
if (container == null) continue;
foreach (var item in container.itemList)
{
if (item.info.shortname == config.PhysicalCurrency.Shortname &&
item.skin == config.PhysicalCurrency.SkinID)
count += item.amount;
}
}
return count;
}
private bool RemovePhysicalCurrency(BasePlayer player, int amount)
{
int toRemove = amount;
var containerList = new List<ItemContainer>
{
player.inventory.containerMain,
player.inventory.containerBelt,
player.inventory.containerWear
};
foreach (var container in containerList)
{
if (container == null) continue;
foreach (var item in container.itemList.ToList())
{
if (item.info.shortname == config.PhysicalCurrency.Shortname &&
item.skin == config.PhysicalCurrency.SkinID)
{
if (item.amount <= toRemove)
{
toRemove -= item.amount;
item.Remove();
}
else
{
item.amount -= toRemove;
item.MarkDirty();
toRemove = 0;
}
if (toRemove <= 0) return true;
}
}
}
return toRemove <= 0;
}
#endregion
#region Electronic Currency
private int GetElectronicBalance(BasePlayer player)
{
string pluginName = config.ElectronicCurrency.PluginName.ToLower();
try
{
switch (pluginName)
{
case "iqeconomic":
if (IQEconomic == null) return 0;
object iqBalance = IQEconomic.Call("API_GET_BALANCE", player.userID);
return iqBalance != null ? Convert.ToInt32(iqBalance) : 0;
case "economics":
Plugin economics = plugins.Find("Economics");
if (economics == null) return 0;
object ecoBalance = economics.Call("Balance", player.UserIDString);
return ecoBalance != null ? Convert.ToInt32(ecoBalance) : 0;
case "serverrewards":
Plugin serverRewards = plugins.Find("ServerRewards");
if (serverRewards == null) return 0;
object srBalance = serverRewards.Call("CheckPoints", player.userID);
return srBalance != null ? Convert.ToInt32(srBalance) : 0;
default:
PrintError($"Unknown electronic currency plugin: {pluginName}");
return 0;
}
}
catch (Exception ex)
{
PrintError($"Error getting electronic balance: {ex.Message}");
return 0;
}
}
private bool RemoveElectronicBalance(BasePlayer player, int amount)
{
string pluginName = config.ElectronicCurrency.PluginName.ToLower();
try
{
switch (pluginName)
{
case "iqeconomic":
if (IQEconomic == null) return false;
IQEconomic.Call("API_REMOVE_BALANCE", player.userID, amount);
return true;
case "economics":
Plugin economics = plugins.Find("Economics");
if (economics == null) return false;
economics.Call("Withdraw", player.UserIDString, (double)amount);
return true;
case "serverrewards":
Plugin serverRewards = plugins.Find("ServerRewards");
if (serverRewards == null) return false;
object result = serverRewards.Call("TakePoints", player.userID, amount);
return result != null && (bool)result;
default:
PrintError($"Unknown electronic currency plugin: {pluginName}");
return false;
}
}
catch (Exception ex)
{
PrintError($"Error removing electronic balance: {ex.Message}");
return false;
}
}
#endregion
#endregion
#region Group Management
private bool RemoveGroupFromPlayer(ulong userID, string group)
{
bool removed = false;
string originalIQGroupName = group;
var configGroup = config.Groups.ContainsKey(group) ? config.Groups[group] : null;
if (configGroup != null && configGroup.Aliases != null && configGroup.Aliases.Count > 0)
{
var iqData = GetIQPermissionsGroupData(userID);
foreach (var alias in configGroup.Aliases)
{
if (iqData.ContainsKey(alias))
{
originalIQGroupName = alias;
break;
}
}
}
try
{
string command = $"revokegroup {userID} {originalIQGroupName}";
Puts($"Executing console: {command}");
ConsoleSystem.Run(ConsoleSystem.Option.Server, command);
removed = true;
}
catch (Exception ex)
{
Puts($"Console revokegroup error: {ex.Message}");
}
try
{
if (File.Exists(IQPermissionsDataPath))
{
string json = File.ReadAllText(IQPermissionsDataPath);
var data = JObject.Parse(json);
var groupsData = data["Информация о группах игрока"] as JObject;
if (groupsData != null)
{
string userIdStr = userID.ToString();
var possibleNames = new List<string> { group, originalIQGroupName };
if (configGroup?.Aliases != null)
possibleNames.AddRange(configGroup.Aliases);
foreach (var searchName in possibleNames.Distinct(StringComparer.OrdinalIgnoreCase))
{
var groupProperty = groupsData.Properties()
.FirstOrDefault(p => p.Name.Equals(searchName, StringComparison.OrdinalIgnoreCase));
if (groupProperty != null)
{
var players = groupProperty.Value as JObject;
if (players != null && players[userIdStr] != null)
{
players.Remove(userIdStr);
Puts($"Removed {userIdStr} from group {groupProperty.Name} in JSON");
File.WriteAllText(IQPermissionsDataPath, data.ToString(Formatting.Indented));
Puts($"Saved IQPermissions JSON");
removed = true;
break;
}
}
}
}
}
}
catch (Exception ex)
{
Puts($"JSON edit error: {ex.Message}");
}
try
{
string steamId = userID.ToString();
if (permission.UserHasGroup(steamId, group))
{
permission.RemoveUserGroup(steamId, group);
Puts($"Also removed from Oxide groups");
}
}
catch { }
return removed;
}
private bool AddGroupToPlayer(ulong userID, string group, string timeFormat)
{
bool added = false;
DateTime expiry = DateTime.Now;
try
{
var regex = new Regex(@"(\d+)([dhms])");
var matches = regex.Matches(timeFormat.ToLower());
foreach (Match match in matches)
{
int value = int.Parse(match.Groups[1].Value);
string unit = match.Groups[2].Value;
switch (unit)
{
case "d": expiry = expiry.AddDays(value); break;
case "h": expiry = expiry.AddHours(value); break;
case "m": expiry = expiry.AddMinutes(value); break;
case "s": expiry = expiry.AddSeconds(value); break;
}
}
}
catch
{
expiry = DateTime.Now.AddDays(1);
}
string iqGroupName = group;
var configGroup = config.Groups.ContainsKey(group) ? config.Groups[group] : null;
if (configGroup != null)
{
iqGroupName = configGroup.Aliases?.FirstOrDefault() ?? configGroup.DisplayName ?? group;
}
try
{
string command = $"addgroup {userID} {iqGroupName} {timeFormat}";
Puts($"Executing console: {command}");
ConsoleSystem.Run(ConsoleSystem.Option.Server, command);
added = true;
}
catch (Exception ex)
{
Puts($"Console addgroup error: {ex.Message}");
}
try
{
JObject data;
if (File.Exists(IQPermissionsDataPath))
{
string json = File.ReadAllText(IQPermissionsDataPath);
data = JObject.Parse(json);
}
else
{
data = new JObject
{
["Информация о привилегиях игрока"] = new JObject(),
["Информация о группах игрока"] = new JObject()
};
}
var groupsData = data["Информация о группах игрока"] as JObject;
if (groupsData == null)
{
groupsData = new JObject();
data["Информация о группах игрока"] = groupsData;
}
var possibleNames = new List<string> { iqGroupName };
if (configGroup?.Aliases != null)
possibleNames.AddRange(configGroup.Aliases);
possibleNames.Add(group);
JObject players = null;
string actualGroupName = iqGroupName;
foreach (var searchName in possibleNames.Distinct(StringComparer.OrdinalIgnoreCase))
{
var groupProperty = groupsData.Properties()
.FirstOrDefault(p => p.Name.Equals(searchName, StringComparison.OrdinalIgnoreCase));
if (groupProperty != null)
{
actualGroupName = groupProperty.Name;
players = groupProperty.Value as JObject;
break;
}
}
if (players == null)
{
players = new JObject();
groupsData[iqGroupName] = players;
actualGroupName = iqGroupName;
}
players[userID.ToString()] = expiry.ToString("O");
Puts($"Added to JSON: {userID} -> {actualGroupName}, expires: {expiry}");
File.WriteAllText(IQPermissionsDataPath, data.ToString(Formatting.Indented));
Puts($"Saved IQPermissions JSON");
added = true;
}
catch (Exception ex)
{
Puts($"JSON edit error: {ex.Message}");
}
try
{
permission.AddUserGroup(userID.ToString(), group);
Puts($"Also added to Oxide groups");
}
catch { }
return added;
}
private void ReturnGroup(ulong userID, string group, FrozenGroupInfo info)
{
string timeFormat = info.TimeFormat;
if (string.IsNullOrEmpty(timeFormat))
{
timeFormat = FormatTimeForIQPermissions(info.RemainingTime);
Puts($"[ReturnGroup] Warning: TimeFormat was empty, using calculated: {timeFormat}");
}
Puts($"[ReturnGroup] Returning group {group} to {userID} with saved time: {timeFormat} (Remaining: {info.RemainingTime.Days}d {info.RemainingTime.Hours}h)");
bool success = AddGroupToPlayer(userID, group, timeFormat);
var player = BasePlayer.FindByID(userID);
if (player != null && player.IsConnected)
{
if (success)
{
player.ChatMessage($"<color=cyan>[SQFrozen]</color> Your <color=yellow>{config.Groups[group].DisplayName}</color> group has been restored! Time: {timeFormat}");
}
else
{
player.ChatMessage($"<color=red>[SQFrozen] Error restoring group! Contact admin.</color>");
}
}
}
#endregion
#region Logic
// ИСПРАВЛЕНО v2.3.1: Убрана проверка на количество дней заморозки
private void FreezeGroup(BasePlayer player, string groupName, int snowflakes)
{
if (!config.Groups.ContainsKey(groupName))
{
player.ChatMessage("<color=red>Invalid group!</color>");
return;
}
RefreshPlayerGroupData(player);
string actualGroupName = groupName;
if (!HasGroup(player, groupName))
{
var allGroups = GetAllPlayerGroups(player);
var similarGroup = allGroups.FirstOrDefault(g => g.Equals(groupName, StringComparison.OrdinalIgnoreCase));
if (similarGroup != null)
{
actualGroupName = similarGroup;
}
else
{
player.ChatMessage($"<color=red>You don't have this group!</color>");
return;
}
}
string groupKey = actualGroupName.ToLower();
if (frozenData.ContainsKey(player.userID) && f
// ... [Code preview truncated due to length. Full source in attached file] ...