C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Random = UnityEngine.Random;
namespace Oxide.Plugins
{
[Info("Shop", "Mevent", "1.0.27")]
public class ShopRu : RustPlugin
{
#region Fields
[PluginReference]
private Plugin ImageLibrary, ItemCostCalculator, HumanNPC, Notify, UINotify, NoEscape, Duel, Duelist;
private static ShopRu _instance;
private readonly Dictionary<int, ShopItem> _shopItems = new Dictionary<int, ShopItem>();
private readonly Dictionary<BasePlayer, Coroutine> _coroutines = new Dictionary<BasePlayer, Coroutine>();
private readonly Dictionary<string, List<string>> _itemsCategories =
new Dictionary<string, List<string>>();
private readonly List<string> _images = new List<string>();
private const string Layer = "UI.Shop";
private const string ModalLayer = "UI.Shop.Modal";
private const string EditingLayer = "UI.Shop.Editing";
private const string PermAdmin = "shopru.admin";
private const string PermFreeBypass = "shopru.free";
private readonly Dictionary<ulong, DataCart> _carts = new Dictionary<ulong, DataCart>();
private class DataCart
{
public readonly Dictionary<ShopItem, int> Items = new Dictionary<ShopItem, int>();
public void AddItem(ShopItem item)
{
int amount;
if (Items.TryGetValue(item, out amount))
{
if (item.BuyMaxAmount > 0 && amount >= item.BuyMaxAmount) return;
Items[item]++;
return;
}
Items.Add(item, 1);
}
public void RemoveItem(ShopItem item)
{
Items.Remove(item);
}
public void ChangeAmountItem(ShopItem item, int amount)
{
if (amount > 0)
Items[item] = amount;
else
Items.Remove(item);
}
public int GetAmount()
{
return Items.Sum(x => x.Key.Amount * x.Value);
}
public double GetPrice(BasePlayer player)
{
return Items.Sum(x => x.Key.GetPrice(player) * x.Value);
}
public int GetTotalAmount()
{
return (from check in Items
let shopItem = check.Key
where shopItem.Type == ItemType.Item && shopItem.Definition != null
select shopItem.GetStacks(shopItem.Definition, shopItem.Amount * check.Value).Count).Sum();
}
#region Data
public PlayerCart ToPlayerCart()
{
return new PlayerCart
{
Items = Items.ToDictionary(x => x.Key.ID, y => y.Value)
};
}
public DataCart()
{
}
public DataCart(PlayerCart cart)
{
Items = cart.Items.ToDictionary(x => _instance.FindItemById(x.Key), y => y.Value);
}
#endregion
}
private readonly Dictionary<BasePlayer, NPCShop> _openedShops = new Dictionary<BasePlayer, NPCShop>();
private NPCShop GetShopByPlayer(BasePlayer player)
{
NPCShop shop;
return _openedShops.TryGetValue(player, out shop) ? shop : null;
}
private readonly Dictionary<BasePlayer, Dictionary<string, object>> _itemEditing =
new Dictionary<BasePlayer, Dictionary<string, object>>();
#endregion
#region Colors
private string _firstColor;
private string _secondColor;
private string _thirdColor;
private string _fourthColor;
private string _fifthColor;
private string _sixthColor;
private string _seventhColor;
#endregion
#region Config
private Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Команды", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly string[] Commands = {"shop", "shops"};
[JsonProperty(PropertyName = "Включить логирование в консоль? | Enable logging to the console?")]
public readonly bool LogToConsole = true;
[JsonProperty(PropertyName = "Включить логирование в файл? | Enable logging to the file?")]
public readonly bool LogToFile = true;
[JsonProperty(PropertyName = "Загружать изображения при подключении к серверу?")]
public readonly bool LoginImages = true;
[JsonProperty(PropertyName = "Работать с Notify?")]
public readonly bool UseNotify = true;
[JsonProperty(PropertyName = "Могут ли админы редактировать предметы? (флаг)")]
public readonly bool FlagAdmin = true;
[JsonProperty(PropertyName = "Поддержка NoEscape")]
public bool BlockNoEscape;
[JsonProperty(PropertyName = "Запрещать открытие на дуэлях?")]
public bool UseDuels;
[JsonProperty(PropertyName = "Задержка между загрузкой изображений")]
public readonly float ImagesDelay = 1f;
[JsonProperty(PropertyName = "Экономика")]
public readonly EconomyConf Economy = new EconomyConf
{
Type = EconomyType.Plugin,
AddHook = "Deposit",
BalanceHook = "Balance",
RemoveHook = "Withdraw",
Plug = "Economics",
ShortName = "scrap",
DisplayName = string.Empty,
Skin = 0
};
[JsonProperty(PropertyName = "Магазин", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly List<ShopCategory> Shop = new List<ShopCategory>();
[JsonProperty(PropertyName = "1 Цвет")]
public readonly string FirstColor = "#161617";
[JsonProperty(PropertyName = "2 Цвет")]
public readonly string SecondColor = "#4B68FF";
[JsonProperty(PropertyName = "3 Цвет")]
public readonly string ThirdColor = "#0E0E10";
[JsonProperty(PropertyName = "4 Цвет")]
public readonly string FourthColor = "#A0A935";
[JsonProperty(PropertyName = "5 Цвет")]
public readonly string FifthColor = "#FF4B4B";
[JsonProperty(PropertyName = "6 Цвет")]
public readonly string SixthColor = "#324192";
[JsonProperty(PropertyName = "7 Цвет")]
public readonly string SeventhColor = "#CD3838";
[JsonProperty(PropertyName = "Магазины NPC (NPC ID - категории магазина)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly Dictionary<string, NPCShop> NPCs = new Dictionary<string, NPCShop>
{
["1234567"] = new NPCShop
{
Shops = new List<string>
{
"Tool",
"Food"
}
},
["7654321"] = new NPCShop
{
Shops = new List<string>
{
"Weapon",
"Ammunition"
}
},
["4644687478"] = new NPCShop
{
Shops = new List<string>
{
"*"
}
}
};
[JsonProperty(PropertyName = "Интерфейс")]
public readonly UserInterface UI = new UserInterface
{
DisplayType = "Overlay",
Width = 770,
Height = 500,
CategoriesOnString = 9,
CategoriesMargin = 7.5f,
CategoriesHeight = 40,
ItemsOnString = 4,
Strings = 2,
ItemWidth = 150,
ItemHeight = 165,
Margin = 35,
UseScrollCategories = true,
EnableSearch = true,
RoundDigits = 5
};
[JsonProperty(PropertyName = "Заблокированные скины для продажи",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly Dictionary<string, List<ulong>> BlockedSkins = new Dictionary<string, List<ulong>>
{
["short name"] = new List<ulong>
{
52,
25
},
["short name 2"] = new List<ulong>
{
52,
25
}
};
public VersionNumber Version;
}
private class UserInterface
{
[JsonProperty(PropertyName = "Тип отображения (Overlay/Hud)")]
public string DisplayType;
[JsonProperty(PropertyName = "Высота")]
public float Height;
[JsonProperty(PropertyName = "Ширина")]
public float Width;
[JsonProperty(PropertyName = "Кол-во категорий на странице")]
public int CategoriesOnString;
[JsonProperty(PropertyName = "Отступ между категориями")]
public float CategoriesMargin;
[JsonProperty(PropertyName = "Высота категорий")]
public float CategoriesHeight;
[JsonProperty(PropertyName = "Кол-во предметов на одной линии")]
public int ItemsOnString;
[JsonProperty(PropertyName = "Кол-во линий")]
public int Strings;
[JsonProperty(PropertyName = "Высота предмета")]
public float ItemHeight;
[JsonProperty(PropertyName = "Ширина предмета")]
public float ItemWidth;
[JsonProperty(PropertyName = "Отступ")]
public float Margin;
[JsonProperty(PropertyName = "Использовать скролл в категориях?")]
public bool UseScrollCategories;
[JsonProperty(PropertyName = "Включить поиск?")]
public bool EnableSearch;
[JsonProperty(PropertyName = "Количество цифр после десятичной точки для округления цен")]
public int RoundDigits;
}
private class NPCShop
{
[JsonProperty(PropertyName = "Категории [* - все]",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Shops;
}
private class ShopCategory
{
[JsonProperty(PropertyName = "Включить")]
public bool Enabled;
[JsonProperty(PropertyName = "Название")]
public string Title;
[JsonProperty(PropertyName = "Разрешение")]
public string Permission;
[JsonProperty(PropertyName = "Предметы", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ShopItem> Items;
}
private enum ItemType
{
Item,
Command,
Plugin,
Kit
}
private class ShopItem
{
[JsonProperty(PropertyName = "Тип")] [JsonConverter(typeof(StringEnumConverter))]
public ItemType Type;
[JsonProperty(PropertyName = "ID")] public int ID;
[JsonProperty(PropertyName = "Изображение")]
public string Image;
[JsonProperty(PropertyName = "Название")]
public string Title;
[JsonProperty(PropertyName = "Описание")]
public string Description;
[JsonProperty(PropertyName = "Команда (%steamid%)")]
public string Command;
[JsonProperty(PropertyName = "Kit")] public string Kit;
[JsonProperty(PropertyName = "Плагин")]
public PluginItem Plugin;
[JsonProperty(PropertyName = "DisplayName (пусто - по умолчанию)")]
public string DisplayName;
[JsonProperty(PropertyName = "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = "Скин")] public ulong Skin;
[JsonProperty(PropertyName = "Количество")]
public int Amount;
[JsonProperty(PropertyName = "Цена")] public double Price;
[JsonProperty(PropertyName = "Цена продажи")]
public double SellPrice;
[JsonProperty(PropertyName = "Задержка покупки (0 - отключить)")]
public float BuyCooldown;
[JsonProperty(PropertyName = "Задержка продажи (0 - отключить)")]
public float SellCooldown;
[JsonProperty(PropertyName = "Скидка (%)", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> Discount = new Dictionary<string, int>();
[JsonProperty(PropertyName = "Лимит продаж (0 - без лимита)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> SellLimits = new Dictionary<string, int>();
[JsonProperty(PropertyName = "Лимит покупок (0 - без лимита)",
ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> BuyLimits = new Dictionary<string, int>();
[JsonProperty(PropertyName = "Максимальное покупаемое количество (0 - отключить)")]
public int BuyMaxAmount;
[JsonProperty(PropertyName = "Максимальное продаваемое количество (0 - отключить)")]
public int SellMaxAmount;
[JsonIgnore] private string _publicTitle;
[JsonIgnore]
public string PublicTitle
{
get
{
if (string.IsNullOrEmpty(_publicTitle))
_publicTitle = GetName();
return _publicTitle;
}
}
private string GetName()
{
if (!string.IsNullOrEmpty(Title))
return Title;
if (!string.IsNullOrEmpty(DisplayName))
return DisplayName;
var def = ItemManager.FindItemDefinition(ShortName);
if (!string.IsNullOrEmpty(ShortName) && def != null)
return def.displayName.translated;
return string.Empty;
}
[JsonIgnore] public ItemDefinition Definition;
public Dictionary<string, object> ToDictionary()
{
return new Dictionary<string, object>
{
["Generated"] = false,
["ID"] = ID,
["Type"] = Type,
["Image"] = Image,
["Title"] = Title,
["Command"] = Command,
["DisplayName"] = DisplayName,
["ShortName"] = ShortName,
["Skin"] = Skin,
["Amount"] = Amount,
["Price"] = Price,
["SellPrice"] = SellPrice,
["Plugin_Hook"] = Plugin.Hook,
["Plugin_Name"] = Plugin.Plugin,
["Plugin_Amount"] = Plugin.Amount
};
}
public ShopItem()
{
}
public ShopItem(Dictionary<string, object> dictionary)
{
ID = (int) dictionary["ID"];
Type = (ItemType) dictionary["Type"];
Image = (string) dictionary["Image"];
Title = (string) dictionary["Title"];
Command = (string) dictionary["Command"];
DisplayName = (string) dictionary["DisplayName"];
ShortName = (string) dictionary["ShortName"];
Skin = (ulong) dictionary["Skin"];
Amount = (int) dictionary["Amount"];
Price = (double) dictionary["Price"];
SellPrice = (double) dictionary["SellPrice"];
Plugin = new PluginItem
{
Hook = (string) dictionary["Plugin_Hook"],
Plugin = (string) dictionary["Plugin_Name"],
Amount = (int) dictionary["Plugin_Amount"]
};
Discount = new Dictionary<string, int>();
}
public double GetPrice(BasePlayer player)
{
var discount = GetDiscount(player);
var price = Price;
return Math.Round(discount != 0 ? price * (1f - discount / 100f) : price,
_instance._config.UI.RoundDigits);
}
public int GetDiscount(BasePlayer player)
{
return (from check in Discount
where _instance.permission.UserHasPermission(player.UserIDString, check.Key)
select check.Value).Prepend(0).Max();
}
public int GetLimit(BasePlayer player, bool buy = true)
{
var dict = buy ? BuyLimits : SellLimits;
if (dict.Count == 0)
return 0;
return (from check in dict
where _instance.permission.UserHasPermission(player.UserIDString, check.Key)
select check.Value).Prepend(0).Max();
}
public void Get(BasePlayer player, int count = 1)
{
switch (Type)
{
case ItemType.Item:
ToItem(player, count);
break;
case ItemType.Command:
ToCommand(player, count);
break;
case ItemType.Plugin:
Plugin.Get(player, count);
break;
case ItemType.Kit:
ToKit(player, count);
break;
}
}
private void ToKit(BasePlayer player, int count)
{
if (string.IsNullOrEmpty(Kit)) return;
for (var i = 0; i < count; i++)
Interface.Oxide.CallHook("GiveKit", player, Kit);
}
private void ToItem(BasePlayer player, int count)
{
var def = ItemManager.FindItemDefinition(ShortName);
if (def == null)
{
Debug.LogError($"Error creating item with ShortName '{ShortName}'");
return;
}
GetStacks(def, Amount * count)?.ForEach(stack =>
{
var newItem = ItemManager.Create(def, stack, Skin);
if (newItem == null)
{
_instance?.PrintError($"Error creating item with ShortName '{ShortName}'");
return;
}
if (!string.IsNullOrEmpty(DisplayName)) newItem.name = DisplayName;
player.GiveItem(newItem, BaseEntity.GiveItemReason.PickedUp);
});
}
private void ToCommand(BasePlayer player, int count)
{
for (var i = 0; i < count; i++)
{
var command = Command.Replace("\n", "|").Replace("%steamid%", player.UserIDString, StringComparison.OrdinalIgnoreCase).Replace(
"%username%",
player.displayName, StringComparison.OrdinalIgnoreCase);
foreach (var check in command.Split('|')) _instance?.Server.Command(check);
}
}
public List<int> GetStacks(ItemDefinition item, int amount)
{
var list = new List<int>();
var maxStack = item.stackable;
if (maxStack == 0) maxStack = 1;
while (amount > maxStack)
{
amount -= maxStack;
list.Add(maxStack);
}
list.Add(amount);
return list;
}
public override string ToString()
{
switch (Type)
{
case ItemType.Item:
return $"[ITEM-{ID}] {ShortName}x{Amount}(DN: {DisplayName}, SKIN: {Skin})";
case ItemType.Command:
return $"[COMMAND-{ID}] {Command}";
case ItemType.Plugin:
return
$"[PLUGIN-{ID}] Name: {Plugin?.Plugin}, Hook: {Plugin?.Hook}, Amount: {Plugin?.Amount ?? 0}";
case ItemType.Kit:
return $"[KIT-{ID}] {Kit}";
default:
return base.ToString();
}
}
}
private class PluginItem
{
[JsonProperty(PropertyName = "Hook")] public string Hook;
[JsonProperty(PropertyName = "Plugin Name")]
public string Plugin;
[JsonProperty(PropertyName = "Amount")]
public int Amount;
public void Get(BasePlayer player, int count = 1)
{
var plug = _instance?.plugins.Find(Plugin);
if (plug == null)
{
_instance?.PrintError($"Plugin '{Plugin}' not found !!! ");
return;
}
switch (Plugin)
{
case "Economics":
{
plug.Call(Hook, player.userID, (double) Amount * count);
break;
}
default:
{
plug.Call(Hook, player.userID, Amount * count);
break;
}
}
}
}
private enum EconomyType
{
Plugin,
Item
}
private class EconomyConf
{
[JsonProperty(PropertyName = "Тип (Plugin/Item)")] [JsonConverter(typeof(StringEnumConverter))]
public EconomyType Type;
[JsonProperty(PropertyName = "Plugin name")]
public string Plug;
[JsonProperty(PropertyName = "Balance add hook")]
public string AddHook;
[JsonProperty(PropertyName = "Balance remove hook")]
public string RemoveHook;
[JsonProperty(PropertyName = "Balance show hook")]
public string BalanceHook;
[JsonProperty(PropertyName = "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = "Display Name (empty - default)")]
public string DisplayName;
[JsonProperty(PropertyName = "Skin")] public ulong Skin;
public double ShowBalance(BasePlayer player)
{
switch (Type)
{
case EconomyType.Plugin:
{
var plugin = _instance?.plugins?.Find(Plug);
if (plugin == null) return 0;
return Math.Round(Convert.ToDouble(plugin.Call(BalanceHook, player.userID)), 2);
}
case EconomyType.Item:
{
return ItemCount(player.inventory.AllItems(), ShortName, Skin);
}
default:
return 0;
}
}
public void AddBalance(BasePlayer player, double amount)
{
switch (Type)
{
case EconomyType.Plugin:
{
var plugin = _instance?.plugins?.Find(Plug);
if (plugin == null) return;
switch (Plug)
{
case "BankSystem":
case "ServerRewards":
plugin.Call(AddHook, player.userID, (int) amount);
break;
default:
plugin.Call(AddHook, player.userID, amount);
break;
}
break;
}
case EconomyType.Item:
{
var am = (int) amount;
var item = ToItem(am);
if (item == null) return;
player.GiveItem(item);
break;
}
}
}
public bool RemoveBalance(BasePlayer player, double amount)
{
switch (Type)
{
case EconomyType.Plugin:
{
if (ShowBalance(player) < amount) return false;
var plugin = _instance?.plugins.Find(Plug);
if (plugin == null) return false;
switch (Plug)
{
case "BankSystem":
case "ServerRewards":
plugin.Call(RemoveHook, player.userID, (int) amount);
break;
default:
plugin.Call(RemoveHook, player.userID, amount);
break;
}
return true;
}
case EconomyType.Item:
{
var playerItems = player.inventory.AllItems();
var am = (int) amount;
if (ItemCount(playerItems, ShortName, Skin) < am) return false;
Take(playerItems, ShortName, Skin, am);
return true;
}
default:
return false;
}
}
private Item ToItem(int amount)
{
var item = ItemManager.CreateByName(ShortName, amount, Skin);
if (item == null)
{
Debug.LogError($"Error creating item with ShortName: '{ShortName}'");
return null;
}
if (!string.IsNullOrEmpty(DisplayName)) item.name = DisplayName;
return item;
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
if (_config.Version < Version)
UpdateConfigValues();
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();
}
private void UpdateConfigValues()
{
PrintWarning("Config update detected! Updating config values...");
var baseConfig = new Configuration();
if (_config.Version == default(VersionNumber) && _config.Version < new VersionNumber(1, 0, 21))
{
_data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Name);
if (_data != null)
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Players", _data);
}
if (_config.Version < new VersionNumber(1, 0, 21))
_config.Shop.ForEach(shop =>
{
shop.Items.ForEach(item =>
{
item.SellLimits = new Dictionary<string, int>
{
["shopru.default"] = 0,
["shopru.vip"] = 0
};
item.BuyLimits = new Dictionary<string, int>
{
["shopru.default"] = 0,
["shopru.vip"] = 0
};
});
});
if (_config.Version < new VersionNumber(1, 0, 24)) _config.UI.DisplayType = baseConfig.UI.DisplayType;
_config.Version = Version;
PrintWarning("Config update completed!");
}
#endregion
#region Data
private PluginData _data;
private void SaveData()
{
SavePlayers();
SaveCooldown();
SaveLimits();
}
private void SavePlayers()
{
_data.PlayerCarts.Clear();
foreach (var check in _carts)
_data.PlayerCarts.Add(check.Key, check.Value.ToPlayerCart());
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Players", _data);
}
private void SaveCooldown()
{
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Cooldown", _cooldown);
}
private void SaveLimits()
{
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Limits", _limits);
}
private void LoadData()
{
try
{
_data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>($"{Name}/Players");
_cooldown = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, Cooldown>>($"{Name}/Cooldown");
_limits = Interface.Oxide.DataFileSystem.ReadObject<PlayerLimits>($"{Name}/Limits");
}
catch (Exception e)
{
PrintError(e.ToString());
}
if (_data == null) _data = new PluginData();
if (_cooldown == null) _cooldown = new Dictionary<ulong, Cooldown>();
if (_limits == null) _limits = new PlayerLimits();
}
private class PluginData
{
[JsonProperty(PropertyName = "Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly Dictionary<ulong, PlayerCart> PlayerCarts = new Dictionary<ulong, PlayerCart>();
}
private class PlayerCart
{
[JsonProperty(PropertyName = "Items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<int, int> Items = new Dictionary<int, int>();
}
#endregion
#region Hooks
private void Init()
{
_instance = this;
LoadData();
if (!_config.LoginImages)
Unsubscribe(nameof(OnPlayerConnected));
_firstColor = HexToCuiColor(_config.FirstColor);
_secondColor = HexToCuiColor(_config.SecondColor);
_thirdColor = HexToCuiColor(_config.ThirdColor);
_fourthColor = HexToCuiColor(_config.FourthColor);
_fifthColor = HexToCuiColor(_config.FifthColor);
_sixthColor = HexToCuiColor(_config.SixthColor);
_seventhColor = HexToCuiColor(_config.SeventhColor);
}
private void OnServerInitialized()
{
if (_config.Shop.Count == 0)
FillCategories();
LoadImages();
_config.Shop.ForEach(category =>
{
if (!string.IsNullOrEmpty(category.Permission) && !permission.PermissionExists(category.Permission))
permission.RegisterPermission(category.Permission, this);
});
permission.RegisterPermission(PermAdmin, this);
permission.RegisterPermission(PermFreeBypass, this);
CheckOnDuplicates();
ItemsToDict();
foreach (var image in _shopItems.Values.Select(shopItem =>
!string.IsNullOrEmpty(shopItem.Image) ? shopItem.Image : shopItem.ShortName).Where(image => !_images.Contains(image))) _images.Add(image);
foreach (var check in _data.PlayerCarts)
_carts.Add(check.Key, new DataCart(check.Value));
if (_config.LoginImages)
foreach (var player in BasePlayer.activePlayerList)
OnPlayerConnected(player);
AddCovalenceCommand(_config.Commands, nameof(CmdShopOpen));
if (_shopItems.Any(x => x.Value.BuyCooldown > 0 || x.Value.SellCooldown > 0))
timer.Every(1, ItemsUpdateController);
}
private void Unload()
{
foreach (var player in BasePlayer.activePlayerList)
{
CuiHelper.DestroyUi(player, Layer);
CuiHelper.DestroyUi(player, ModalLayer);
CuiHelper.DestroyUi(player, EditingLayer);
OnPlayerDisconnected(player);
}
SaveData();
_instance = null;
}
private void OnPlayerConnected(BasePlayer player)
{
if (player == null) return;
var coroutine = ServerMgr.Instance.StartCoroutine(LoadImages(player));
if (_coroutines.ContainsKey(player))
_coroutines[player] = coroutine;
else
_coroutines.Add(player, coroutine);
}
private void OnPlayerDisconnected(BasePlayer player)
{
if (player == null) return;
_itemsToUpdate.Remove(player);
if (_itemEditing.ContainsKey(player)) _itemEditing.Remove(player);
if (_coroutines.ContainsKey(player))
{
var coroutine = _coroutines[player];
if (coroutine != null)
ServerMgr.Instance.StopCoroutine(coroutine);
}
}
private void OnUseNPC(BasePlayer npc, BasePlayer player)
{
if (npc == null || player == null) return;
NPCShop npcShop;
if (!_config.NPCs.TryGetValue(npc.UserIDString, out npcShop) || npcShop == null) return;
_openedShops[player] = npcShop;
MainUi(player, npcShop: npcShop, first: true);
}
#endregion
#region Commands
private void CmdShopOpen(IPlayer cov, string command, string[] args)
{
var player = cov?.Object as BasePlayer;
if (player == null) return;
if (_config.UseDuels && InDuel(player))
{
SendNotify(player, NoUseDuel, 1);
return;
}
MainUi(player, first: true);
}
[ConsoleCommand("UI_Shop")]
private void CmdConsoleShop(ConsoleSystem.Arg arg)
{
var player = arg?.Player();
if (player == null || !arg.HasArgs()) return;
switch (arg.Args[0])
{
case "closeui":
{
_itemsToUpdate.Remove(player);
_openedShops.Remove(player);
break;
}
case "main_page":
{
int catPage, page;
if (!arg.HasArgs(3) || !int.TryParse(arg.Args[1], out catPage) ||
!int.TryParse(arg.Args[2], out page)) return;
var search = string.Empty;
if (arg.HasArgs(4)) search = string.Join(" ", arg.Args.Skip(3));
if (string.IsNullOrEmpty(search) && catPage == -1)
catPage = 0;
MainUi(player, catPage, page, GetShopByPlayer(player), search);
break;
}
case "buyitem":
{
int id;
if (!arg.HasArgs(2) ||
!int.TryParse(arg.Args[1], out id)) return;
var shopItem = FindItemById(id);
if (shopItem == null) return;
var playerCart = GetPlayerCart(player);
if (playerCart == null) return;
playerCart.AddItem(shopItem);
var cooldownTime = GetCooldownTime(player.userID, shopItem, true);
if (cooldownTime > 0)
{
SendNotify(player, BuyCooldownMessage, 1, shopItem.PublicTitle,
FormatShortTime(player, TimeSpan.FromSeconds(cooldownTime)));
return;
}
var container = new CuiElementContainer();
RefreshCart(ref container, player, playerCart);
CuiHelper.AddUi(player, container);
break;
}
case "changeicat":
{
int catPage, iCategory;
if (!arg.HasArgs(3) || !int.TryParse(arg.Args[1], out catPage) ||
!int.TryParse(arg.Args[2], out iCategory)) return;
var container = new CuiElementContainer();
RefreshCategories(ref container, player, GetCategories(player, GetShopByPlayer(player)), catPage,
iCategory);
CuiHelper.AddUi(player, container);
break;
}
case "gocat":
{
int catPage, iCategory;
if (!arg.HasArgs(3) || !int.TryParse(arg.Args[1], out catPage) ||
!int.TryParse(arg.Args[2], out iCategory)) return;
MainUi(player, catPage, npcShop: GetShopByPlayer(player));
var container = new CuiElementContainer();
RefreshCategories(ref container, player, GetCategories(player, GetShopByPlayer(player)), catPage,
iCategory);
CuiHelper.AddUi(player, container);
break;
}
case "cart_page":
{
int page;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out page)) return;
var playerCart = GetPlayerCart(player);
if (playerCart == null) return;
var container = new CuiElementContainer();
RefreshCart(ref container, player, playerCart, page);
CuiHelper.AddUi(player, container);
break;
}
case "cart_item_remove":
{
int id;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out id)) return;
var shopItem = FindItemById(id);
if (shopItem == null) return;
var playerCart = GetPlayerCart(player);
if (playerCart == null) return;
playerCart.RemoveItem(shopItem);
var container = new CuiElementContainer();
RefreshCart(ref container, player, playerCart);
CuiHelper.AddUi(player, container);
break;
}
case "cart_item_change":
{
int id, amount;
if (!arg.HasArgs(3) ||
!int.TryParse(arg.Args[1], out id) ||
!int.TryParse(arg.Args[2], out amount)) return;
var shopItem = FindItemById(id);
if (shopItem == null) return;
var playerCart = GetPlayerCart(player);
if (playerCart == null) return;
if (shopItem.BuyMaxAmount > 0 && amount > shopItem.BuyMaxAmount)
amount = shopItem.BuyMaxAmount;
playerCart.ChangeAmountItem(shopItem, amount);
var container = new CuiElementContainer();
RefreshCart(ref container, player, playerCart);
CuiHelper.AddUi(player, container);
break;
}
case "cart_try_buyitems":
{
AcceptBuy(player);
break;
}
case "cart_buyitems":
{
var playerCart = GetPlayerCart(player);
if (playerCart == null) return;
var price = playerCart.GetPrice(player);
if (price <= 0) return;
if (_config.BlockNoEscape && NoEscape != null)
{
var success = NoEscape?.Call("IsBlocked", player);
if (success is bool && (bool) success)
{
ErrorUi(player, Msg(player, BuyRaidBlocked));
return;
}
}
var totalcount = playerCart.GetTotalAmount();
var slots = player.inventory.containerBelt.capacity -
player.inventory.containerBelt.itemList.Count +
(player.inventory.containerMain.capacity -
player.inventory.containerMain.itemList.Count);
if (slots < totalcount)
{
ErrorUi(player, Msg(player, NotEnoughtSpace));
return;
}
if (!permission.UserHasPermission(player.UserIDString, PermFreeBypass) &&
!_config.Economy.RemoveBalance(player, price))
{
ErrorUi(player, Msg(player, NotMoney));
return;
}
if (playerCart.Items.Any(x =>
{
var limit = GetLimit(player, x.Key, true);
if (limit > 0) return false;
ErrorUi(player, Msg(player, BuyLimitReached, x.Key.PublicTitle));
return true;
}))
return;
var logItems = Pool.GetList<string>();
foreach (var cartItem in playerCart.Items)
{
logItems.Add(cartItem.Key.ToString());
cartItem.Key?.Get(player, cartItem.Value);
SetCooldown(player, cartItem.Key, true);
UseLimit(player, cartItem.Key, true);
}
Log("Buy", LogBuyItems, player.displayName, player.UserIDString,
price, string.Join(", ", logItems));
CuiHelper.DestroyUi(player, Layer);
_carts.Remove(player.userID);
_itemsToUpdate.Remove(player);
SendNotify(player, ReceivedItems, 0);
break;
}
case "trysellitem":
{
int itemId;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out itemId)) return;
var item = FindItemById(itemId);
if (item == null) return;
var amount = 1;
if (arg.HasArgs(3) && !int.TryParse(arg.Args[2], out amount) || amount < 1) return;
if (item.SellMaxAmount > 0 && amount > item.SellMaxAmount) amount = item.SellMaxAmount;
SellUi(player, item, amount);
break;
}
case "sellitem":
{
int itemId, amount;
if (!arg.HasArgs(3) ||
!int.TryParse(arg.Args[1], out itemId) ||
!int.TryParse(arg.Args[2], out amount)) return;
var item = FindItemById(itemId);
if (item == null) return;
var cooldownTime = GetCooldownTime(player.userID, item, false);
if (cooldownTime > 0)
{
ErrorUi(player, Msg(player, SellCooldownMessage));
return;
}
if (_config.BlockNoEscape && NoEscape != null)
{
var success = NoEscape?.Call("IsBlocked", player);
if (success is bool && (bool) success)
{
ErrorUi(player, Msg(player, SellRaidBlocked));
return;
}
}
var limit = GetLimit(player, item, false);
if (limit <= 0)
{
ErrorUi(player, Msg(player, SellLimitReached, item.PublicTitle));
return;
}
List<ulong> blockedSkins;
if (_config.BlockedSkins.TryGetValue(item.ShortName, out blockedSkins))
if (blockedSkins.Contains(item.Skin))
{
ErrorUi(player, Msg(player, SkinBlocked));
return;
}
var totalAmount = item.Amount * amount;
var
// ... [Code preview truncated due to length. Full source in attached file] ...