C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using WebSocketSharp;
namespace Oxide.Plugins {
[Info("GameStoresRUST", "HOUGAN & Sstine & rostov114 # GAMESTORES", "0.3.6")]
public class GameStoresRUST : RustPlugin {
#region References
[PluginReference]
private Plugin ImageLibrary;
#endregion
#region Classes
private static class Delays {
[JsonProperty("Игроки с активными запросами к АПИ")]
public static List<ulong> ItemList = new List<ulong>();
[JsonProperty("Количество запросов за последнюю секунду")]
public static int RequestPerSecond = 0;
[JsonProperty("Ограничение запросов в секунду")]
public static int RequestPerSecondLimit = 20;
public static bool CanRequest(BasePlayer player) {
if (RequestPerSecond > RequestPerSecondLimit) {
return false;
}
if (ItemList.Contains(player.userID)) {
player.ChatMessage(instance._(player, "WaitPreviousAction"));
return false;
}
return true;
}
public static void FinishRequest(BasePlayer player) {
if (ItemList.Contains(player.userID)) ItemList.Remove(player.userID);
}
public static IEnumerator MakeRequest(BasePlayer player) {
RequestPerSecond++;
if (ItemList.Contains(player.userID)) yield return null;
ItemList.Add(player.userID);
yield return new WaitForSeconds(3f);
if (ItemList.Contains(player.userID)) ItemList.Remove(player.userID);
}
}
private class Stats {
}
private class Configuration {
public class API {
[JsonProperty("ИД магазина в сервисе")]
public string ShopID = "UNDEFINED";
[JsonProperty("ИД сервера в сервисе")]
public string ServerID = "UNDEFINED";
[JsonProperty("Секретный ключ (не распространяйте его)")]
public string SecretKey = "UNDEFINED";
}
public class Interface {
[JsonProperty("Включить изображение корзины")]
public bool BucketEnable = true;
[JsonProperty("Включить отображение названий предметов")]
public bool TextShow = true;
[JsonProperty("Ссылка на изображение корзины (BUCKET - стандартное изображение)")]
public string BucketURL = "BUCKET";
[JsonProperty("Количество предметов на строке")]
public int ItemOnString = 7;
[JsonProperty("Количество строк в интерфейсе")]
public int StringAmount = 3;
[JsonProperty("Сторона одного предмета")]
public int ItemSide = 150;
[JsonProperty("Отступ между предметами")]
public int ItemMargin = 5;
}
public class TOP {
[JsonProperty("Отправлять данные топа игроков")]
public bool UseTop = true;
}
[JsonProperty("Настройки API плагина")]
public API APISettings = new API();
[JsonProperty("Настройки интерфейса плагина")]
public Interface InterfaceSettings = new Interface();
[JsonProperty("Настройки статистики сервера")]
public TOP TOPSettings = new TOP();
}
private class WItem {
public string ID;
public string Name;
public int ItemID;
public int Amount;
public string ShortName;
public string Command;
public string ImageUrl;
public bool Blocked;
public double Block_Date = 0;
public bool IsBlueprint;
public bool IsCommand;
public bool IsItem;
public WItem(Dictionary<string, object> data, bool show = true) {
try {
if (data.ContainsKey("id")) ID = data["id"].ToString();
if (data.ContainsKey("name")) Name = data["name"].ToString();
if (data.ContainsKey("item_id")) ItemID = System.Convert.ToInt32(data["item_id"]);
if (data.ContainsKey("amount")) Amount = System.Convert.ToInt32(data["amount"]);
if (data.ContainsKey("command")) Command = data["command"].ToString();
if (data.ContainsKey("img")) ImageUrl = data["img"].ToString();
if (data.ContainsKey("blocked")) Blocked = bool.Parse(data["blocked"].ToString());
if (data.ContainsKey("block_date") && data["block_date"] is int) {
double.TryParse(data["block_date"].ToString(), out Block_Date);
}
if (data.ContainsKey("type")) {
IsBlueprint = data["type"].ToString() == "bp";
IsCommand = data["type"].ToString() == "command";
IsItem = data["type"].ToString() == "item";
}
if (ItemID != 0) {
var itemInfo = ItemManager.FindItemDefinition(ItemID);
if (itemInfo != null) ShortName = itemInfo.shortname;
else if (IDToShortName.ContainsKey(ItemID)) {
itemInfo = ItemManager.FindItemDefinition(IDToShortName[ItemID]);
if (itemInfo == null) return;
ShortName = itemInfo.shortname;
}
}
var imageLibrary = instance.plugins.Find("ImageLibrary");
if (imageLibrary != null) {
if (ItemID == 0) {
if ((bool)imageLibrary.Call("HasImage", $"IconGS.{ID}")) {
string probablyId = (string)imageLibrary.Call("GetImage", $"IconGS.{ID}");
if (!probablyId.IsNullOrEmpty() && probablyId != instance.NoImageID && probablyId != instance.LoadingImageID) ImageUrl = probablyId;
return;
}
if (!ImageUrl.IsNullOrEmpty()) {
imageLibrary.Call("AddImage", ImageUrl.Replace("https", "http"), $"IconGS.{ID}");
}
}
else {
string probablyId = (string)imageLibrary.Call("GetImage", ShortName);
if (!probablyId.IsNullOrEmpty() && probablyId != instance.NoImageID && probablyId != instance.LoadingImageID) ImageUrl = probablyId;
}
}
}
catch (NullReferenceException e) {
Interface.Oxide.LogError(JsonConvert.SerializeObject(data));
}
}
}
#endregion
#region Variables
private static bool initialization = false;
private static bool Initialized = false;
private static GameStoresRUST instance;
private static Configuration Settings = new Configuration();
private string ShopURL = "UNDEFINED";
private int StartBalance = 0;
public string NoImageID = "";
public string LoadingImageID = "";
private Coroutine LoadingCoroutine;
private Dictionary<int, Dictionary<ulong, int>> ListTimeOutCommand = new Dictionary<int, Dictionary<ulong, int>>();
private Dictionary<ulong, List<int>> playersBasketCache = new Dictionary<ulong, List<int>>();
private HashSet<ulong> ListBannedCommandUserID = new HashSet<ulong>();
private Timer TimerCheckInstant;
private string MainApiLink = $"https://gamestores.ru/api/";
private string ReserveApiLink = $"https://gs.gamestores.ru/api/";
//private string BaseRequest => $"https://gamestores.ru/api/?shop_id={Settings.APISettings.ShopID}&secret={Settings.APISettings.SecretKey}{(!Settings.APISettings.ServerID.IsNullOrEmpty() && Settings.APISettings.ServerID != "0" && Settings.APISettings.ServerID != "1" && Settings.APISettings.ServerID != "UNDEFINED" ? $"&server={Settings.APISettings.ServerID}" : "")}";
private string BaseRequestParams => $"?shop_id={Settings.APISettings.ShopID}&secret={Settings.APISettings.SecretKey}{(!Settings.APISettings.ServerID.IsNullOrEmpty() && Settings.APISettings.ServerID != "0" && Settings.APISettings.ServerID != "1" && Settings.APISettings.ServerID != "UNDEFINED" ? $"&server= {
Settings.APISettings.ServerID
}
" : "")}";
private string BaseRequest = "";
#endregion
#region Language
private void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string>() {
// Global
{
"days", "дн."
}
, {
"hour", "ч."
}
, {
"minutes", "мин."
}
, {
"seconds", "сек."
}
, // Chat messages
{
"PluginNotInitialized", "Плагин магазина запущен некорректно"
}
, {
"PlayerFloodBlock", "Вы сделали слишком много запросов.Отдохните немного, скоро возможность выполнять действие к вам вернется."
}
, {
"ItemNotFound", "Предмет не найден, попробуйте перезапустить корзину"
}
, {
"UnexpectedError", "Непредвиденная ошибка со стороны сервера, просим прощения!"
}
, {
"WaitPreviousAction", "Пожалуйста, дождитесь <<окончания>> предыдущего действия!"
}
, // UI
{
"BASKET", "КОРЗИНА СЕРВЕРА"
}
, {
"EXIT", "ВЫХОД"
}
, {
"BASKET.DESCRIPTION", "Это ваша корзина с покупками, вы можете забрать их в любой момент"
}
, {
"BASKET.EMPTY", "Ваша корзина пуста"
}
, {
"HELP", "ПОМОЩЬ"
}
, {
"REQUEST.PROCESSING", "Подождите, мы обрабатываем ваш запрос..."
}
, {
"BASKET.UNAVAILABLE", "Корзина временно недоступна, попробуйте позже"
}
, {
"BASKET.NO.AUTH", "Вы не авторизованы в магазине!\n" + "Ссылку на авторизацию вы можете найти в разделе 'ПОМОЩЬ'"
}
, {
"USER.MANUAL", "ИНСТРУКЦИЯ ПОЛЬЗОВАТЕЛЯ"
}
, {
"USER.MANUAL.DESCRIPTION", "Здесь вы можете забрать товары приобретенные у нас в магазине!\n" + "Пополнить счёт можно различными способами: электронные кошельки, карты и т.д.\n" + "Авторизация в магазине происходит при помощи вашего аккаунта STEAM"
}
, {
"USER.MANUAL.BALANCE", "\n<size=18>При первой авторизации вы получите в подарок <b>{0} рублей</b>!</size>"
}
, {
"TAKE.ITEM.BLOCKED", "Вы не можете забрать этот предмет из корзины!\n" + "До его разблокировки осталось: {0}"
}
, {
"TAKE.REQUEST.PROCESSING", "Подождите, ваш запрос обрабатывается!"
}
, {
"TAKE.LAST.REQUEST.PROCESSING", "Подождите, ваш предыдущий запрос ещё обрабатывается!"
}
, {
"TAKE.WAIT", "ПОДОЖДИТЕ"
}
, {
"TAKE.GIVE.ERROR", "ОШИБКА\nПОЛУЧЕНИЯ"
}
, {
"TAKE.GIVE.ERROR.NOTIFY", "Произошла непредвиденная ошибка, попробуйте позже!\n" + "Ваш предмет в безопасности, не переживайте!"
}
, {
"TAKE.GIVE.SUCCESS", "УСПЕШНО\nПОЛУЧЕНО"
}
, {
"TAKE.GIVE.FEET", "Вы успешно получили предмет › <size=20>{0}</size> ‹\n" + "У вас недостаточно места в инвентаре, <b>предмет брошен</b> под ноги!"
}
, {
"TAKE.GIVE.INVENTORY", "Вы успешно получили предмет › <size=20>{0}</size> ‹"
}
, {
"TAKE.GIVE.COMMAND", "Вы успешно получили предмет › <size=20>{0}</size> ‹\n" + "Теперь вам доступны новые привилегии!"
}
, {
"TAKE.GIVE.BLUEPRINT.FEET", "Вы успешно получили рецепт предмета › <size=20>{0}</size> ‹\n" + "У вас недостаточно места в инвентаре, <b>предмет брошен</b> под ноги!"
}
, {
"TAKE.GIVE.BLUEPRINT.INVENTORY", "Вы успешно получили рецепт предмета › <size=20>{0}</size> ‹"
}
, {
"MANY.REQUESTS", "Вы делаете слишком много запросов к серверу!\n" + "Подождите <b>одну секунду</b>!"
}
}
, this, "ru");
lang.RegisterMessages(new Dictionary<string, string>() {
// Global
{
"days", "d."
}
, {
"hour", "h."
}
, {
"minutes", "m."
}
, {
"seconds", "s."
}
, // Chat messages
{
"PluginNotInitialized", "The store plugin is not launched correctly"
}
, {
"PlayerFloodBlock", "You have made too many requests.Relax a little, soon the ability to perform the action will return to you."
}
, {
"ItemNotFound", "Item not found, try restarting your cart"
}
, {
"UnexpectedError", "Unexpected error from server side, sorry!"
}
, {
"WaitPreviousAction", "Please wait for the <<end>> of the previous step!"
}
, // UI
{
"BASKET", "SERVER BASKET"
}
, {
"EXIT", "EXIT"
}
, {
"BASKET.DESCRIPTION", "This is your shopping cart, you can pick them up at any time"
}
, {
"BASKET.EMPTY", "Basket empty"
}
, {
"HELP", "HELP"
}
, {
"REQUEST.PROCESSING", "Please wait, we are processing your request..."
}
, {
"BASKET.UNAVAILABLE", "Cart is temporarily unavailable, please try again later"
}
, {
"BASKET.NO.AUTH", "You are not authorized in the store!\n" + "You can find a link to authorization in the 'HELP' section"
}
, {
"USER.MANUAL", "USER'S MANUAL"
}
, {
"USER.MANUAL.DESCRIPTION", "Here you can pick up the products purchased from our store!\n" + "You can replenish your account in various ways: e-wallets, cards, etc.\n" + "Authorization in the store takes place using your STEAM account"
}
, {
"USER.MANUAL.BALANCE", "\n<size=18>At the first authorization, you will receive a gift of <b>{0} rubles</b>!</size>"
}
, {
"TAKE.ITEM.BLOCKED", "You cannot pick up this item from your cart!\n" + "Before its unlocking, there are: {0}"
}
, {
"TAKE.REQUEST.PROCESSING", "Please wait, your request is being processed!"
}
, {
"TAKE.LAST.REQUEST.PROCESSING", "Please wait, your previous request is still being processed!"
}
, {
"TAKE.WAIT", "WAIT"
}
, {
"TAKE.GIVE.ERROR", "ERROR\nRECEIVING"
}
, {
"TAKE.GIVE.ERROR.NOTIFY", "An unexpected error occured, please try again later!\n" + "Your item is safe, don't worry!"
}
, {
"TAKE.GIVE.SUCCESS", "SUCCESSFULLY\nRECEIVED"
}
, {
"TAKE.GIVE.FEET", "You have successfully obtained an item › <size=20>{0}</size> ‹\n" + "You don't have enough space in your inventory, <b>the item was thrown</b> at your feet!"
}
, {
"TAKE.GIVE.INVENTORY", "You have successfully obtained an item › <size=20>{0}</size> ‹"
}
, {
"TAKE.GIVE.COMMAND", "You have successfully obtained an item › <size=20>{0}</size> ‹\n" + "New privileges are now available to you!"
}
, {
"TAKE.GIVE.BLUEPRINT.FEET", "You have successfully obtained the item blueprint › <size=20>{0}</size> ‹\n" + "You don't have enough space in your inventory, <b>the item was thrown</b> at your feet!"
}
, {
"TAKE.GIVE.BLUEPRINT.INVENTORY", "You have successfully obtained the item blueprint › <size=20>{0}</size> ‹"
}
, {
"MANY.REQUESTS", "You are making too many server requests!\n" + "Wait <b>one second</b>!"
}
}
, this, "en");
}
private string _(BasePlayer player, string key, params object[] args) {
return string.Format(lang.GetMessage(key, this, player?.UserIDString), args);
}
#endregion
#region Interface
private int TryImageCounter = 0;
private void OnServerInitialized() {
BaseRequest = MainApiLink + BaseRequestParams;
if (Settings.APISettings.ServerID != "0" && Settings.APISettings.ServerID != "UNDEFINED") {
TimerCheckInstant = timer.Repeat(20, 0, CheckInstant);
}
else {
LogAction(null, $"Некорректный ServerID, автоматическая выдача команд невозможна");
PrintError($"Incorrect ServerID, reciving auto commands (Products) disabled");
}
if (!ImageLibrary) {
if (TryImageCounter < 3) {
LogAction(null, $"ImageLibrary is not initialized, try again in 1 sec.", true);
TryImageCounter++;
timer.Once(1, OnServerInitialized);
return;
}
else LogAction(null, $"Starting without ImageLibrary", true);
}
if (ImageLibrary) {
NoImageID = (string)ImageLibrary.Call("GetImage", "NONE");
LoadingImageID = (string)ImageLibrary.Call("GetImage", "LOADING");
}
if (Settings.InterfaceSettings.BucketURL.Contains("http") && plugins.Find("ImageLibrary") != null) {
ImageLibrary.Call("AddImage", Settings.InterfaceSettings.BucketURL, "GameStoresRUSTBucket");
LoadingCoroutine = ServerMgr.Instance.StartCoroutine(WaitForLoad());
}
else {
//BasePlayer.activePlayerList.ForEach(OnPlayerInit);
for (var i = 0; i < BasePlayer.activePlayerList.Count; i++) {
OnPlayerConnected(BasePlayer.activePlayerList[i]);
}
}
instance = this;
if (!Settings.TOPSettings.UseTop) Unsubscribe(nameof(OnEntityDeath));
if (!Settings.TOPSettings.UseTop) Unsubscribe(nameof(OnPlayerDisconnected));
if (Settings.APISettings.ShopID == "UNDEFINED" || Settings.APISettings.SecretKey == "UNDEFINED") {
LogAction(null, $"Verify that plugin is installed correct! Some of API settings are 'UNDEFINED'", true, true);
return;
}
timer.Once(2, FetchShopUrl);
timer.Every(1, () => Delays.RequestPerSecond = 0);
ListTimeOutCommand[0] = new Dictionary<ulong, int>();
ListTimeOutCommand[1] = new Dictionary<ulong, int>();
ListTimeOutCommand[2] = new Dictionary<ulong, int>();
int totalTick = 0;
int tick = 0;
timer.Repeat(2, 0, () => {
if (totalTick == 30) {
totalTick = 0;
ListBannedCommandUserID.Clear();
}
ListTimeOutCommand[0].Clear();
if (tick == 3 || tick == 6) {
ListTimeOutCommand[1].Clear();
}
if (tick == 6) {
tick = 0;
ListTimeOutCommand[2].Clear();
}
tick++;
totalTick++;
}
);
}
private IEnumerator WaitForLoad() {
while (!(bool)ImageLibrary.Call("HasImage", "GameStoresRUSTBucket")) {
PrintError($"Image of bucket is loading!");
yield return new WaitForSeconds(1);
}
PrintWarning("Image of bucket loaded correct!");
//BasePlayer.activePlayerList.ForEach(OnPlayerInit);
for (var i = 0; i < BasePlayer.activePlayerList.Count; i++) {
OnPlayerConnected(BasePlayer.activePlayerList[i]);
}
yield return 0;
}
protected override void LoadConfig() {
base.LoadConfig();
try {
Settings = Config.ReadObject<Configuration>();
if (Settings?.APISettings == null) LoadDefaultConfig();
}
catch {
LogAction(null, $"Error reading config, creating one new config!", true, true);
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
protected override void LoadDefaultConfig() {
Settings = new Configuration();
}
protected override void SaveConfig() => Config.WriteObject(Settings);
private void Unload() {
//if (Initialized) StatHandler.SendStats();
if (LoadingCoroutine != null) ServerMgr.Instance.StopCoroutine(LoadingCoroutine);
//BasePlayer.activePlayerList.ForEach(p => CuiHelper.DestroyUi(p, IconLayer));
//BasePlayer.activePlayerList.ForEach(p => CuiHelper.DestroyUi(p, StoreLayer));
foreach (var pl in BasePlayer.activePlayerList) {
CuiHelper.DestroyUi(pl, IconLayer);
CuiHelper.DestroyUi(pl, StoreLayer);
OnPlayerConnected(pl);
}
}
#endregion
#region Hooks
private void OnPlayerDisconnected(BasePlayer player, string reason) {
StatHandler.AddStat(new StatHandler.TimeStat(player));
}
private void OnPlayerConnected(BasePlayer player) {
if (player.IsReceivingSnapshot) {
NextTick(() => OnPlayerConnected(player));
return;
}
if (Settings.InterfaceSettings.BucketEnable) InitializeIcon(player);
}
#endregion
#region Stats
private static class StatHandler {
internal class Stat {
[JsonProperty("dataType")]
public string DataType;
}
internal class KillStat : Stat {
[JsonProperty("player_id")]
public string PlayerUserId;
[JsonProperty("victim_id")]
public string VictimUserID;
[JsonProperty("type")]
public string Type;
[JsonProperty("time")]
public string Time;
}
internal class TimeStat : Stat {
[JsonProperty("player_id")]
public string PlayerID;
[JsonProperty("username")]
public string PlayerName;
[JsonProperty("played")]
public string Played;
[JsonProperty("time")]
public string Time;
public TimeStat(BasePlayer player) {
PlayerID = player.UserIDString;
PlayerName = player.displayName;
DataType = "leave";
Played = player.secondsConnected.ToString();
Time = CurrentTime().ToString();
}
}
private static List<Stat> Stats = new List<Stat>();
public static void AddStat(Stat stat) {
Stats.Add(stat);
if (Stats.Count > 10) {
SendStats();
Stats.Clear();
}
}
public static void SendStats() {
try {
if (!Initialized) {
instance.LogAction(null, $"Sending stats error! Plugin not initialized", true, true);
return;
}
if (Stats.Count == 0) {
instance.LogAction(null, $"Nothing to send", true);
return;
}
var obj = JsonConvert.SerializeObject(Stats);
RequestPost($"&method=topData&data={obj}", (i, s) => {
if (i != 200) return;
Dictionary<string, object> response = JsonConvert.DeserializeObject<Dictionary<string, object>>(s, new KeyValuesConverter());
if (response.ContainsKey("result") && response["result"].ToString() == "success") {
instance.LogAction(null, $"GameStores sent stats successful!", true);
Stats.Clear();
}
else {
instance.LogAction(null, $"Sending stats error!", true, true);
}
}
);
}
catch {
// ignored
}
}
}
[ConsoleCommand("sendtop")]
private void CmdSendTop(ConsoleSystem.Arg args) {
if (args.Player() != null && !args.Player().IsAdmin) return;
StatHandler.SendStats();
}
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
if (entity == null || info == null || info.Initiator == null) return;
if (Settings.TOPSettings.UseTop) {
BaseEntity initiator = info.Initiator;
if (entity as BasePlayer == null && initiator as BasePlayer == null) return;
StatHandler.KillStat stat = new StatHandler.KillStat();
if (initiator as BasePlayer != null) stat.PlayerUserId = initiator.ToPlayer().UserIDString;
else if (initiator.PrefabName.Contains("agents")) stat.PlayerUserId = "1";
else return;
if (entity as BasePlayer != null) {
stat.VictimUserID = entity.ToPlayer().UserIDString;
stat.Type = entity.ToPlayer().IsSleeping() ? "sleeper" : "kill";
}
else if (entity.PrefabName.Contains("agents")) {
stat.VictimUserID = "1";
stat.Type = "kill";
}
else {
return;
}
stat.DataType = "death";
stat.Time = CurrentTime().ToString();
StatHandler.AddStat(stat);
}
}
#endregion
#region Commands
[ChatCommand("store")]
private void CmdChatStore(BasePlayer player, string command, string[] args) {
if (player == null || player.Connection == null || player.IsSleeping()) {
return;
}
if (!Initialized) {
errorsReq++;
player.ChatMessage(_(player, "PluginNotInitialized"));
return;
}
if (args.Length == 1 && args[0].ToLower() == "hide") {
CuiHelper.DestroyUi(player, IconLayer);
}
else {
if (!Delays.CanRequest(player)) return;
InitializeStore(player, 0, true);
}
}
[ConsoleCommand("UI_GameStoresRUST")]
private void CmdConsoleCommand(ConsoleSystem.Arg args) {
BasePlayer player = args.Player();
if (player == null) return;
if (ListBannedCommandUserID.Contains(player.userID)) {
player.ChatMessage(_(player, "PlayerFloodBlock"));
return;
}
if (ListTimeOutCommand[0].ContainsKey(player.userID) == false) ListTimeOutCommand[0][player.userID] = 1;
else ListTimeOutCommand[0][player.userID] = ListTimeOutCommand[0][player.userID] + 1;
if (ListTimeOutCommand[1].ContainsKey(player.userID) == false) ListTimeOutCommand[1][player.userID] = 1;
else ListTimeOutCommand[1][player.userID] = ListTimeOutCommand[1][player.userID] + 1;
if (ListTimeOutCommand[2].ContainsKey(player.userID) == false) ListTimeOutCommand[2][player.userID] = 1;
else ListTimeOutCommand[2][player.userID] = ListTimeOutCommand[2][player.userID] + 1;
if (ListTimeOutCommand[0][player.userID] >= 10 || ListTimeOutCommand[1][player.userID] >= 20 || ListTimeOutCommand[2][player.userID] >= 30) {
this.ListBannedCommandUserID.Add(player.userID);
}
if (!args.HasArgs(1)) {
player.SendConsoleCommand("chat.say /store");
return;
}
switch (args.Args[0].ToLower()) {
case "page" : {
int page = 0;
if (!args.HasArgs(2) || !int.TryParse(args.Args[1], out page)) return;
InitializeStore(player, page, false);
break;
}
case "help" : {
string helpLayer = StoreLayer + ".Help";
CuiHelper.DestroyUi(player, helpLayer);
CuiHelper.DestroyUi(player, StoreLayer);
CuiElementContainer container = new CuiElementContainer();
container.Add(new CuiPanel {
CursorEnabled = true, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Image = {
Color = "0 0 0 0.9", Material = "assets/content/ui/uibackgroundblur.mat"
}
,
}
, "Overlay", helpLayer);
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 0.6", AnchorMax = "1 0.78", OffsetMax = "0 0"
}
, Text = {
Text = _(player, "USER.MANUAL"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf", FontSize = 34
}
}
, helpLayer);
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 0.3", AnchorMax = "1 0.72", OffsetMax = "0 0"
}
, Text = {
Text = _(player, "USER.MANUAL.DESCRIPTION"), Font = "robotocondensed-regular.ttf", FontSize = 22, Align = TextAnchor.MiddleCenter
}
}
, helpLayer);
string addText = StartBalance > 0 ? _(player, "USER.MANUAL.BALANCE", StartBalance) : "";
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 0.1", AnchorMax = "1 0.48", OffsetMax = "0 0"
}
, Text = {
Text = $"{addText}\n{ShopURL.ToUpper()}", Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf", FontSize = 32
}
}
, helpLayer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Button = {
Color = "0 0 0 0", Close = helpLayer, Command = "chat.say /store"
}
, Text = {
Text = ""
}
}
, helpLayer);
CuiHelper.AddUi(player, container);
break;
}
case "take" : {
if (!args.HasArgs(3)) return;
int index = 0, id = 0;
if (!int.TryParse(args.Args[1], out index) || !int.TryParse(args.Args[2], out id)) return;
if (!playersBasketCache.ContainsKey(player.userID)) {
player.ChatMessage(_(player, "ItemNotFound"));
return;
}
else if (!playersBasketCache[player.userID].Contains(id)) {
player.ChatMessage(_(player, "ItemNotFound"));
return;
}
if (args.HasArgs(5) && args.Args[3].ToLower() == "blocked") {
double left = 0;
if (!double.TryParse(args.Args[4], out left)) return;
TimeSpan span = TimeSpan.FromSeconds(left);
string text = "";
if (span.Days >= 1) text += $"{span.Days} " + _(player, "days") + " ";
if (span.Hours >= 1) text += $"{span.Hours} " + _(player, "hours") + " ";
if (span.Minutes >= 1) text += $"{span.Minutes} " + _(player, "minutes") + " ";
if (span.Seconds >= 1) text += $"{span.Seconds} " + _(player, "seconds");
ShowNotify(player, _(player, "TAKE.ITEM.BLOCKED", text));
return;
}
ShowNotify(player, _(player, "TAKE.REQUEST.PROCESSING"));
CuiElementContainer container = new CuiElementContainer();
if (!Delays.CanRequest(player)) {
ShowNotify(player, _(player, "TAKE.LAST.REQUEST.PROCESSING"));
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Button = {
Color = "1 1 1 0.2", Close = StoreLayer + ".BlockPanel." + index + ".Open", Command = $"UI_GameStoresRUST take {index} {id}"
}
, Text = {
Text = _(player, "TAKE.WAIT"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", Color = "1 1 1 0.4", FontSize = 24
}
}
, StoreLayer + ".BlockPanel." + index, StoreLayer + ".BlockPanel." + index + ".Open");
CuiHelper.AddUi(player, container);
return;
}
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Button = {
FadeIn = 1f, Color = "1 1 1 0.2", Close = StoreLayer + ".BlockPanel." + index + ".Open", Command = $"UI_GameStoresRUST take {index} {id}"
}
, Text = {
Text = _(player, "TAKE.WAIT"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", Color = "1 1 1 0.4", FontSize = 24
}
}
, StoreLayer + ".BlockPanel." + index, StoreLayer + ".BlockPanel." + index + ".Open");
CuiHelper.AddUi(player, container);
LogAction(null, $"---------------------------------");
LogAction(player, $"Запрос на получение предмета: {id}");
Request($"&item=true&steam_id={player.UserIDString}&id={id}", (i, s) => {
switch (i) {
case 0 : LogAction(player, $"API не ответило на запрос: {id}");
PrintError("Api does not responded to a request");
if (player != null) {
player.ChatMessage(_(player, "UnexpectedError"));
CuiHelper.DestroyUi(player, StoreLayer);
}
break;
case 200 : Dictionary<string, object> response = JsonConvert.DeserializeObject<Dictionary<string, object>>(s, new KeyValuesConverter());
if (!response.ContainsKey("data")) {
LogAction(player, $"Ошибка получения товара, отсутствует Data [{id}]");
container.Clear();
CuiHelper.DestroyUi(player, StoreLayer + ".BlockPanel." + index + ".Open");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Button = {
FadeIn = 1f, Color = "1 0.5 0.5 0.2", Close = StoreLayer + ".BlockPanel." + index + ".Open", Command = $"UI_GameStoresRUST take {index} {id}"
}
, Text = {
Text = _(player, "TAKE.GIVE.ERROR"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", Color = "1 0.7 0.7 1", FontSize = 22
}
}
, StoreLayer + ".BlockPanel." + index, StoreLayer + ".BlockPanel." + index + ".Open");
ShowNotify(player, _(player, "TAKE.GIVE.ERROR.NOTIFY"));
CuiHelper.AddUi(player, container);
return;
}
LogAction(player, $"Товар отмечен полученным [{id}]");
Request($"&gived=true&id={id}", (code, newResponse) => {
if (code != 200 || JsonConvert.DeserializeObject<JObject>(newResponse)["result"].ToString() != "success") {
container.Clear();
CuiHelper.DestroyUi(player, StoreLayer + ".BlockPanel." + index + ".Open");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Button = {
FadeIn = 1f, Color = "1 0.5 0.5 0.2", Close = StoreLayer + ".BlockPanel." + index + ".Open", Command = $"UI_GameStoresRUST take {index} {id}"
}
, Text = {
Text = _(player, "TAKE.GIVE.ERROR"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", Color = "1 0.7 0.7 1", FontSize = 22
}
}
, StoreLayer + ".BlockPanel." + index, StoreLayer + ".BlockPanel." + index + ".Open");
ShowNotify(player, _(player, "TAKE.GIVE.ERROR.NOTIFY"));
CuiHelper.AddUi(player, container);
return;
}
ProcessTake(player, response["data"] as Dictionary<string, object>);
}
, player);
container.Clear();
CuiHelper.DestroyUi(player, StoreLayer + ".BlockPanel." + index + ".Open");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Button = {
FadeIn = 1f, Color = "0.5 1 0.5 0.2"
}
, Text = {
Text = _(player, "TAKE.GIVE.SUCCESS"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", Color = "0.7 1 0.7 1", FontSize = 22
}
}
, StoreLayer + ".BlockPanel." + index, StoreLayer + ".BlockPanel." + index + ".Open");
if (playersBasketCache.ContainsKey(player.userID) && playersBasketCache[player.userID].Contains(id)) playersBasketCache[player.userID].RemoveAt(playersBasketCache[player.userID].IndexOf(id));
CuiHelper.AddUi(player, container);
break;
case 404 : LogAction(player, $"Сайт не ответил на запрос: {id}");
player.ChatMessage(_(player, "UnexpectedError"));
CuiHelper.DestroyUi(player, StoreLayer);
LogAction(null, "Response code: 404, please check your configurations", true);
break;
}
}
, player);
break;
}
}
}
#endregion
#region Interface
private static string StoreLayer = "UI_GameStoresRUST_Store";
private void InitializeStore(BasePlayer player, int page, bool first = true) {
CuiElementContainer container = new CuiElementContainer();
if (first) {
CuiHelper.DestroyUi(player, StoreLayer);
container.Add(new CuiPanel {
CursorEnabled = true, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
, Image = {
Color = "0 0 0 0.8", Material = "assets/content/ui/uibackgroundblur.mat"
}
,
}
, "Overlay", StoreLayer);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.3 0.9", AnchorMax = "0.7 1", OffsetMax = "0 0"
}
, Button = {
Color = "0 0 0 0"
}
, Text = {
Text = _(player, "BASKET"), Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf", FontSize = 32, Color = "1 1 1 0.6"
}
}
, StoreLayer, StoreLayer + ".ITT");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.8 0.9", AnchorMax = "0.935 1", OffsetMax = "0 0"
}
, Button = {
Color = "0 0 0 0", Close = StoreLayer, Command = "closemenu"
}
, Text = {
Text = _(player, "EXIT"), Align = TextAnchor.MiddleRight, Font = "robotocondensed-regular.ttf", FontSize = 28
}
}
, StoreLayer);
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 0", OffsetMin = "0 -0", OffsetMax = "0 20"
}
, Text = {
Text = _(player, "BASKET.DESCRIPTION"), Align = TextAnchor.UpperCenter, Font = "robotocondensed-regular.ttf", Color = "1 1 1 0.4"
}
}
, StoreLayer + ".ITT");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.065 0.9", AnchorMax = "0.2 1", OffsetMax = "0 0"
}
, Button = {
Color = "0 0 0 0", Command = "UI_GameStoresRUST help"
}
, Text = {
Text = _(player, "HELP"), Align = TextAnchor.MiddleLeft, Font = "robotocondensed-regular.ttf", FontSize = 28
}
}
, StoreLayer);
}
CuiHelper.DestroyUi(player, StoreLayer + ".BlockPanel");
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 0.9", OffsetMax = "0 0"
}
, Image = {
Color = "0 0 0 0"
}
}
, StoreLayer, StoreLayer + ".BlockPanel");
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1.1", OffsetMax = "0 0"
}
// ... [Code preview truncated due to length. Full source in attached file] ...