Иконка ресурса

FREE GameStoresRUST : 1.0.23 1.0.23

Нет прав для скачивания
C#:
// #define TESTING

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Steamworks;
using UnityEngine;
using UnityEngine.Networking;

#if CARBON
using Carbon.Base;
using Carbon.Modules;
#endif

namespace Oxide.Plugins
{
	[Info("GameStoresRUST", "HOUGAN & Sstine & rostov114 & Mevent # GAMESTORES", "1.0.23")]
	public class GameStoresRUST : RustPlugin
	{
		#region Fields

		[PluginReference] private Plugin
			GameStoresWipeBlock = null,
			ImageLibrary = null,
			NoEscape = null;

		private static GameStoresRUST Instance;

#if CARBON
		private ImageDatabaseModule imageDatabase = BaseModule.GetModule<ImageDatabaseModule>();
#endif

		private bool initialization, Initialized, maintenance;

		private string ShopURL = "UNDEFINED";
		private int StartBalance;

		private Dictionary<int, Dictionary<ulong, int>> ListTimeOutCommand = new();

		private HashSet<ulong> ListBannedCommandUserID = new();

		private Dictionary<ulong, PlayerBasket> _playerBaskets = new();

		private Timer _checkInstant;

		#region Images

		private string NoImageID = string.Empty, LoadingImageID = string.Empty;

		private const string ImageBucket = "GameStoresRUSTBucket";
		
		private Coroutine _loadingCoroutine;

		#endregion

		#region Web Requests

		private readonly List<Coroutine> _activeCoroutines = new();

		private readonly List<UnityWebRequest> _activeRequests = new();

		private bool SecureConnection = true;

		private Dictionary<string, string> reqHeaders = new()
		{
			["User-Agent"] = "GameStores Plugin"
		};

		private const string
			MainApiLink = "https://apip.gamestores.app/v1/",
			CFApiLink = "https://api.gamestores.app/v1/",
			PayApiLink = "https://pay.gamestores.app/api/";
		
		private string BestApiLink = string.Empty;

		private int errorsReq;
		private const int MaxErrorsReq = 5;

		#endregion Web Requests

		#endregion

		#region Config

		private Configuration _config;

		private class Configuration
		{
			public class APIConfiguration
			{
				[JsonProperty("Store ID")] public string ShopID = "UNDEFINED";

				[JsonProperty("Server ID")] public string ServerID = "UNDEFINED";

				[JsonProperty("Secret key (don't spread it)")]
				public string SecretKey = "UNDEFINED";
			}

			public class InterfaceConfiguration
			{
				[JsonProperty("Enable cart image")] public bool BucketEnable = true;

				[JsonProperty("Enable display of item names")]
				public bool TextShow = true;

				[JsonProperty("Link to cart image (BUCKET - default image)")]
				public string BucketURL = "BUCKET";

				[JsonProperty("Number of items per line")]
				public int ItemOnString = 7;

				[JsonProperty("Number of lines in the interface")]
				public int StringAmount = 3;

				[JsonProperty("Side of one item")] public int ItemSide = 150;

				[JsonProperty("Space between objects")]
				public int ItemMargin = 5;

				[JsonProperty("Position settings cart image")]
				public InterfacePosition BucketPosition = new()
				{
					AnchorMin = "0 1",
					AnchorMax = "0 1",
					OffsetMin = "8 -40",
					OffsetMax = "43 -6"
				};

				[JsonProperty("Background settings")] public BackgroundSettings Background = new()
				{
					AnchorMin = "0 0",
					AnchorMax = "1 1",
					OffsetMin = "0 0",
					OffsetMax = "0 0",
					Material = "assets/content/ui/uibackgroundblur.mat",
					Sprite = string.Empty,
					Image = string.Empty,
					Color = IColor.Create("#000000", 80),
					DisplayType = "Overlay"
				};

				[JsonProperty("Basket title settings")]
				public ButtonSettings BasketTitle = new()
				{
					AnchorMin = "0.3 0.9",
					AnchorMax = "0.7 1",
					OffsetMin = "0 0",
					OffsetMax = "0 0",
					FontSize = 32,
					IsBold = false,
					Align = TextAnchor.MiddleCenter,
					Color = IColor.Create("#FFFFFF", 60),
					ButtonColor = IColor.Create("#000000", 0),
					Sprite = string.Empty,
					Material = string.Empty,
					Image = string.Empty,
					ImageColor = IColor.Create("#FFFFFF")
				};

				[JsonProperty("Basket description settings")]
				public TextSettings BasketDescription = new()
				{
					AnchorMin = "0 0",
					AnchorMax = "1 0",
					OffsetMin = "0 -0",
					OffsetMax = "0 20",
					FontSize = 14,
					IsBold = false,
					Align = TextAnchor.UpperCenter,
					Color = IColor.Create("#FFFFFF", 40)
				};

				[JsonProperty("Help button settings")] public ButtonSettings HelpButton = new()
				{
					AnchorMin = "0.065 0.9",
					AnchorMax = "0.2 1",
					OffsetMin = "0 0",
					OffsetMax = "0 0",
					FontSize = 28,
					IsBold = false,
					Align = TextAnchor.MiddleLeft,
					Color = IColor.Create("#FFFFFF"),
					ButtonColor = IColor.Create("#000000", 0),
					Sprite = string.Empty,
					Material = string.Empty,
					Image = string.Empty,
					ImageColor = IColor.Create("#FFFFFF")
				};

				[JsonProperty(PropertyName = "Block panel settings")]
				public ImageSettings BlockPanel = new()
				{
					AnchorMin = "0 0",
					AnchorMax = "1 0.9",
					OffsetMin = "0 0",
					OffsetMax = "0 0",
					Color = IColor.Create("#000000", 0),
					Sprite = string.Empty,
					Material = string.Empty,
					Image = string.Empty
				};

				[JsonProperty(PropertyName = "Request processing title settings")]
				public TextSettings RequestProcessingTitle = new()
				{
					AnchorMin = "0 0",
					AnchorMax = "1 1.1",
					OffsetMin = "0 0",
					OffsetMax = "0 0",
					Align = TextAnchor.MiddleCenter,
					Color = IColor.Create("#FFFFFF"),
					IsBold = false,
					FontSize = 34
				};

				[JsonProperty(PropertyName = "Store exit button settings")]
				public ButtonSettings StoreExitButton = new()
				{
					AnchorMin = "0.8 0.9", AnchorMax = "0.935 1", OffsetMin = "0 0", OffsetMax = "0 0",
					ButtonColor = IColor.Create("#000000", 0),
					Material = string.Empty,
					Image = string.Empty,
					Sprite = string.Empty,
					Color = IColor.Create("#FFFFFF"),
					Align = TextAnchor.MiddleRight,
					FontSize = 28,
					IsBold = false,
					ImageColor = IColor.Create("#FFFFFF")
				};

				[JsonProperty(PropertyName = "Item background color")]
				public IColor ItemBackgroundColor = IColor.Create("#FFFFFF", 20);

				#region UI.Components

				public class BackgroundSettings : ImageSettings
				{
					[JsonProperty(PropertyName = "Display type (Overlay/Hud)")]
					public string DisplayType;

					public CuiElement Get(string name, string destroyUI, bool needCursor)
					{
						var image = GetImage(DisplayType, name, destroyUI);

						if (needCursor)
							image.Components.Add(new CuiNeedsCursorComponent());

						return image;
					}
				}

				public class ImageSettings : InterfacePosition
				{
					[JsonProperty(PropertyName = "Sprite")]
					public string Sprite;

					[JsonProperty(PropertyName = "Material")]
					public string Material;

					[JsonProperty(PropertyName = "Image")] public string Image;

					[JsonProperty(PropertyName = "Color")] public IColor Color;

					private ICuiComponent GetImage()
					{
						if (!string.IsNullOrEmpty(Image))
						{
							var rawImage = new CuiRawImageComponent
							{
								Png = Instance?.GetImage(Image),
								Color = Color.Get
							};

							if (!string.IsNullOrEmpty(Sprite))
								rawImage.Sprite = Sprite;

							if (!string.IsNullOrEmpty(Material))
								rawImage.Material = Material;

							return rawImage;
						}

						var image = new CuiImageComponent
						{
							Color = Color.Get
						};

						if (!string.IsNullOrEmpty(Sprite))
							image.Sprite = Sprite;

						if (!string.IsNullOrEmpty(Material))
							image.Material = Material;

						return image;
					}

					public CuiElement GetImage(string parent,
						string name = null,
						string destroyUI = null)
					{
						if (string.IsNullOrEmpty(name))
							name = CuiHelper.GetGuid();

						return new CuiElement
						{
							Name = name,
							Parent = parent,
							DestroyUi = destroyUI,
							Components =
							{
								GetImage(),
								GetPosition()
							}
						};
					}
				}

				public class ButtonSettings : TextSettings
				{
					[JsonProperty(PropertyName = "Button Color")]
					public IColor ButtonColor;

					[JsonProperty(PropertyName = "Sprite")]
					public string Sprite;

					[JsonProperty(PropertyName = "Material")]
					public string Material;

					[JsonProperty(PropertyName = "Image")] public string Image;

					[JsonProperty(PropertyName = "Image Color")]
					public IColor ImageColor;

					public List<CuiElement> Get(
						string msg,
						string cmd,
						string parent,
						string name = null,
						string destroyUI = null,
						string close = null)
					{
						if (string.IsNullOrEmpty(name))
							name = CuiHelper.GetGuid();

						var list = new List<CuiElement>();

						var btn = new CuiButtonComponent
						{
							Color = ButtonColor.Get
						};

						if (!string.IsNullOrEmpty(cmd))
							btn.Command = cmd;

						if (!string.IsNullOrEmpty(close))
							btn.Close = close;

						if (!string.IsNullOrEmpty(Sprite))
							btn.Sprite = Sprite;

						if (!string.IsNullOrEmpty(Material))
							btn.Material = Material;

						if (!string.IsNullOrEmpty(Image))
						{
							list.Add(new CuiElement
							{
								Name = name,
								Parent = parent,
								DestroyUi = destroyUI,
								Components =
								{
									new CuiRawImageComponent
									{
										Png = Instance?.GetImage(Image),
										Color = ImageColor.Get
									},
									GetPosition()
								}
							});

							list.Add(new CuiElement
							{
								Parent = name,
								Components =
								{
									btn,
									new CuiRectTransformComponent()
								}
							});
						}
						else
						{
							list.Add(new CuiElement
							{
								Name = name,
								Parent = parent,
								DestroyUi = destroyUI,
								Components =
								{
									btn,
									GetPosition()
								}
							});
						}

						if (!string.IsNullOrEmpty(msg))
							list.Add(new CuiElement
							{
								Parent = name,
								Components =
								{
									GetTextComponent(msg),
									new CuiRectTransformComponent()
								}
							});

						return list;
					}
				}

				public class TextSettings : InterfacePosition
				{
					[JsonProperty(PropertyName = "Font Size")]
					public int FontSize;

					[JsonProperty(PropertyName = "Is Bold?")]
					public bool IsBold;

					[JsonProperty(PropertyName = "Align")] [JsonConverter(typeof(StringEnumConverter))]
					public TextAnchor Align;

					[JsonProperty(PropertyName = "Color")] public IColor Color;

					protected CuiTextComponent GetTextComponent(string msg)
					{
						return new CuiTextComponent
						{
							Text = msg,
							FontSize = FontSize,
							Font = IsBold ? "robotocondensed-bold.ttf" : "robotocondensed-regular.ttf",
							Align = Align,
							Color = Color.Get
						};
					}

					public CuiElement GetText(string msg, string parent, string name = null, string destroyUI = null)
					{
						if (string.IsNullOrEmpty(name))
							name = CuiHelper.GetGuid();

						return new CuiElement
						{
							Name = name,
							Parent = parent,
							DestroyUi = destroyUI,
							Components =
							{
								GetTextComponent(msg),
								GetPosition()
							}
						};
					}
				}

				public class InterfacePosition
				{
					public string AnchorMin;

					public string AnchorMax;

					public string OffsetMin;

					public string OffsetMax;

					protected CuiRectTransformComponent GetPosition()
					{
						return new CuiRectTransformComponent
						{
							AnchorMin = AnchorMin,
							AnchorMax = AnchorMax,
							OffsetMin = OffsetMin,
							OffsetMax = OffsetMax
						};
					}
				}

				public class IColor
				{
					[JsonProperty(PropertyName = "Opacity (0 - 100)",
						NullValueHandling = NullValueHandling.Include)]
					public float Alpha;

					[JsonProperty(PropertyName = "HEX", NullValueHandling = NullValueHandling.Include)]
					public string Hex;

					public static IColor Create(string hex, float alpha = 100)
					{
						return new IColor
						{
							Hex = hex,
							Alpha = alpha
						};
					}

					[JsonIgnore] private string _color;

					[JsonIgnore]
					public string Get
					{
						get
						{
							if (string.IsNullOrEmpty(_color))
								UpdateColor();

							return _color;
						}
					}

					public void UpdateColor()
					{
						_color = GetColor();
					}

					private string GetColor()
					{
						if (string.IsNullOrEmpty(Hex)) Hex = "#FFFFFF";

						var str = Hex.Trim('#');
						if (str.Length != 6) throw new Exception(Hex);
						var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
						var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
						var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);

						return $"{(double) r / 255} {(double) g / 255} {(double) b / 255} {Alpha / 100}";
					}
				}

				#endregion
			}

			public class PluginConfiguration
			{
				[JsonProperty("Commands to open the store", ObjectCreationHandling = ObjectCreationHandling.Replace)]
				public string[] Commands = {"store", "bucket"};

				[JsonProperty("Enable show joining players in server tags")]
				public bool ShowJoiningPlayers = false;

				[JsonProperty("Load default images over client")]
				public bool LoadSpriteImages = true;

				[JsonProperty("Use Building Blocked?")]
				public bool UseBuildingBlocked = false;

				[JsonProperty("Use Combat Blocked?")] public bool UseCombatBlocked = false;

				[JsonProperty("Use Raid Blocked?")] public bool UseRaidBlocked = false;

				[JsonProperty("Execute instant commands if the player was not on the server?")]
				public bool ExecuteInstantCommandsWhenNotInServer = false;
			}

			[JsonProperty("API configuration")] public APIConfiguration API = new();

			[JsonProperty("Plugin Configuration")] public PluginConfiguration Plugin = new();

			[JsonProperty("UI Configuration")] public InterfaceConfiguration UI = new();

			public VersionNumber ConfigurationVersion = new(2, 0, 0);
		}

		#region Old Config

		private void UpdateConfig(ConfigurationOld _old)
		{
			_config.API.ServerID = _old.API.ServerID;
			_config.API.ShopID = _old.API.ShopID;
			_config.API.SecretKey = _old.API.SecretKey;

			_config.UI.BucketEnable = _old.Interface.BucketEnable;
			_config.UI.TextShow = _old.Interface.TextShow;
			_config.UI.BucketURL = _old.Interface.BucketURL;
			_config.UI.ItemOnString = _old.Interface.ItemOnString;
			_config.UI.StringAmount = _old.Interface.StringAmount;
			_config.UI.ItemSide = _old.Interface.ItemSide;
			_config.UI.ItemMargin = _old.Interface.ItemMargin;

			_config.UI.BucketPosition.AnchorMin = _old.Interface.BucketPosition.AnchorMin;
			_config.UI.BucketPosition.AnchorMax = _old.Interface.BucketPosition.AnchorMax;
			_config.UI.BucketPosition.OffsetMin = _old.Interface.BucketPosition.OffsetMin;
			_config.UI.BucketPosition.OffsetMax = _old.Interface.BucketPosition.OffsetMax;
		}

		private class ConfigurationOld
		{
			public class APIConfiguration
			{
				[JsonProperty("ИД магазина в сервисе")]
				public string ShopID = "UNDEFINED";

				[JsonProperty("ИД сервера в сервисе")] public string ServerID = "UNDEFINED";

				[JsonProperty("Секретный ключ (не распространяйте его)")]
				public string SecretKey = "UNDEFINED";
			}

			public class InterfaceConfiguration
			{
				[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;

				[JsonProperty("Настройки позиции изображение корзины")]
				public Position BucketPosition = new();

				public class Position
				{
					public string AnchorMin = "0 1";
					public string AnchorMax = "0 1";
					public string OffsetMin = "8 -40";
					public string OffsetMax = "43 -6";
				}
			}

			[JsonProperty("Настройки API плагина")]
			public APIConfiguration API = new();

			[JsonProperty("Настройки интерфейса плагина")]
			public InterfaceConfiguration Interface = new();
		}

		#endregion

		protected override void LoadConfig()
		{
			base.LoadConfig();

			try
			{
				_config = Config.ReadObject<Configuration>();
				if (_config?.API == null || _config.API.SecretKey == "UNDEFINED")
				{
					PrintWarning("Old config?");

					var oldConfig = Config.ReadObject<ConfigurationOld>();
					if (oldConfig?.API != null && oldConfig.API.SecretKey != "UNDEFINED")
					{
						PrintError("Old config! Update configuration!");

						UpdateConfig(oldConfig);

						NextTick(SaveConfig);
						return;
					}

					PrintError("Your configuration is invalid! Create new!");
					LoadDefaultConfig();
				}
			}
			catch (Exception e)
			{
				LogAction(null, "Error reading config, creating one new config!", true, true);
				LoadDefaultConfig();
				Debug.LogException(e);
			}

			NextTick(SaveConfig);
		}

		protected override void LoadDefaultConfig()
		{
			_config = new Configuration();
		}

		protected override void SaveConfig()
		{
			Config.WriteObject(_config);
		}

		#endregion

		#region Hooks

		#region Init / Unload

		private void Init()
		{
			BestApiLink = MainApiLink;

			Instance = this;
		}

		private void OnServerInitialized()
		{
#if !CARBON
			if (ImageLibrary == null)
			{
				if (TryImageCounter < maxImageCheck)
				{
					LogAction(null, "ImageLibrary is not initialized, try again in 1 sec.", true);
					TryImageCounter++;

					timer.In(1, OnServerInitialized);
					return;
				}

				LogAction(null, "Starting without ImageLibrary", true);
			}
			else
#endif
			{
				InitializeImages();
				if (_config.UI.BucketURL.Contains("http")
#if !CARBON
				    && ImageLibrary != null
#endif
				   )
					InitializeBucketImage();
				else
					InitializePlayers();
			}

			LoadHeaderParams();

			if (!InitializeServerSettings())
				return;
			
			RegisterCommands();

			timer.Once(2, FetchShopUrl);

			InitializeTimeoutCommands();
		}

		private void Unload()
		{
			try
			{
				DestroyInstantTimer();

				if (_loadingCoroutine != null) ServerMgr.Instance.StopCoroutine(_loadingCoroutine);

				foreach (var player in BasePlayer.activePlayerList)
				{
					CuiHelper.DestroyUi(player, IconLayer);
					CuiHelper.DestroyUi(player, StoreLayer);
				}

				DestroyRequestCoroutines();

				DisposeActiveRequests();
			}
			finally
			{
				Instance = null;
			}
		}

		#endregion

		#region Player

		private void OnPlayerConnected(BasePlayer player)
		{
			if (player == null) return;

			if (_config.UI.BucketEnable)
				InitializeIcon(player);
		}

		private void OnPlayerDisconnected(BasePlayer player)
		{
			if (player == null) return;

			DequeueBasketRequest(player.userID);
		}

		#endregion

		#region Server

		private void OnServerInformationUpdated()
		{
			if (!_config.Plugin.ShowJoiningPlayers)
			{
				Unsubscribe(nameof(OnServerInformationUpdated));
				return;
			}

			NextTick(() =>
			{
				if (SteamServer.GameTags.Length > 122)
				{
					LogAction(null, "-----------------------------", true, true);
					LogAction(null, "Perhaps you specified it incorrectly 'server.tags'!", true, true);
					LogAction(null, "The tag of connecting players WILL NOT be added!", true, true);
					LogAction(null, "-----------------------------", true, true);

					Unsubscribe(nameof(OnServerInformationUpdated));
					return;
				}

				var newTags = new List<string>();
				foreach (var tag in SteamServer.GameTags.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries))
				{
					newTags.Add(tag);

					if (tag.Substring(0, 2) == "qp")
						newTags.Add($"jp{SingletonComponent<ServerMgr>.Instance.connectionQueue.Joining}");
				}

				try
				{
					SteamServer.GameTags = string.Join(",", newTags);
				}
				catch (Exception ex)
				{
					Unsubscribe(nameof(OnServerInformationUpdated));
				}
			});
		}

		#endregion

		#endregion

		#region Commands

		private void CmdChatStore(IPlayer cov, string command, string[] args)
		{
			var player = cov?.Object as BasePlayer;
			if (player == null || player.Connection == null || player.IsSleeping())
				return;

			if (maintenance)
			{
				Reply(player, Maintenance);
				return;
			}

			if (!Initialized)
			{
				HandleInitializationError(player);
				return;
			}

			if (args.Length == 1 && args[0].ToLower() == "hide")
			{
				CuiHelper.DestroyUi(player, IconLayer);
				return;
			}
			

			if (CanRequestBasket(player))
				InitializeStore(player, 0);
		}

		[ConsoleCommand("UI_GameStoresRUST")]
		private void CmdConsoleCommand(ConsoleSystem.Arg args)
		{
			var player = args.Player();
			if (player == null) return;

			if (HandleCommandBan(player, args)) return;

			switch (args.Args[0].ToLower())
			{
				case "page":
				{
					var page = args.GetInt(1);

					InitializeStore(player, page, false);
					break;
				}

				case "help":
				{
					ShowHelpUI(player);
					break;
				}

				case "take":
				{
					if (!args.HasArgs(3)) return;

					if (!int.TryParse(args.Args[1], out var index) ||
					    !int.TryParse(args.Args[2], out var basketID)) return;

					ProcessTakeCommand(player, index, basketID);
					break;
				}
			}
		}

		[ConsoleCommand("closemenu")]
		private void CmdCloseMenu(ConsoleSystem.Arg args)
		{
			var player = args.Player();
			if (player == null) return;

			DequeueBasketRequest(player.userID);
		}

		#endregion

		#region Interface

		private const string
			StoreLayer = "UI_GameStoresRUST_Store",
			IconLayer = "UI_GameStoresRUST_Bucket",
			HelpLayer = StoreLayer + ".Help";

		private void InitializeStore(BasePlayer player, int page, bool first = true)
		{
			var container = new CuiElementContainer();

			if (first)
				CreateStoreUiContainer(ref container, player);

			CreateBlockPanel(ref container, player);

			if (first)
				CreateStoreExitButtonUI(player, ref container);

			CuiHelper.AddUi(player, container);

			if (first)
				RequestBasket(player, page);
			else
				ShowBasketItemsUI(player, page);
		}

		private void ShowNotify(BasePlayer player, string text, float destroyTime = 0f)
		{
			CuiHelper.AddUi(player, new CuiElementContainer
			{
				{
					new CuiLabel
					{
						RectTransform =
						{
							AnchorMin = "0 0.80", AnchorMax = "1 0.90", OffsetMax = "0 0"
						},
						Text =
						{
							FadeIn = 1f, Text = text, Align = TextAnchor.UpperCenter,
							Font = "robotocondensed-regular.ttf",
							FontSize = 16
						}
					},
					StoreLayer, StoreLayer + ".Notify", StoreLayer + ".Notify"
				}
			});

			if (destroyTime > 0f)
				timer.In(destroyTime, () => CuiHelper.DestroyUi(player, StoreLayer + ".Notify"));
		}

		private void ShowHelpUI(BasePlayer player)
		{
			CuiHelper.DestroyUi(player, StoreLayer);

			var 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, HelpLayer);

			container.Add(new CuiLabel
			{
				RectTransform = {AnchorMin = "0 0.6", AnchorMax = "1 0.78", OffsetMax = "0 0"},
				Text =
				{
					Text = Msg(player, MsgUserManual), 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 = Msg(player, MsgUserManualDescription),
					Font = "robotocondensed-regular.ttf", FontSize = 22, Align = TextAnchor.MiddleCenter
				}
			}, HelpLayer);

			var addText = StartBalance > 0 ? Msg(player, MsgUserManualBalance, StartBalance) : string.Empty;
			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 = string.Empty}
			}, HelpLayer);

			CuiHelper.AddUi(player, container);
		}

		#region UI.Components

		private int basketItemsPerPage => _config.UI.ItemOnString * _config.UI.StringAmount;

		private void ShowBasketItemsUI(BasePlayer player,
			int page)
		{
			if (!_playerBaskets.TryGetValue(player.userID, out var playerBasket))
				return;

			var wItems = playerBasket.GetItems(page, basketItemsPerPage);

			var secondContainer = new CuiElementContainer();

			secondContainer.Add(new CuiLabel
			{
				RectTransform = {AnchorMin = "0 0", AnchorMax = "1 0.14", OffsetMax = "0 0"},
				Text = {Text = (page + 1).ToString(), Align = TextAnchor.MiddleCenter, FontSize = 34}
			}, StoreLayer + ".BlockPanel");

			secondContainer.Add(new CuiButton
			{
				RectTransform =
					{AnchorMin = "0.4 0.14", AnchorMax = "0.4 0.14", OffsetMin = "-40 -125", OffsetMax = "125 40"},
				Button = {Color = "0 0 0 0", Command = page > 0 ? $"UI_GameStoresRUST page {page - 1}" : string.Empty},
				Text =
				{
					Text = "<", Color = page > 0 ? "1 1 1 1" : "1 1 1 0.2", Align = TextAnchor.MiddleCenter,
					Font = "robotocondensed-regular.ttf", FontSize = 80
				}
			}, StoreLayer + ".BlockPanel");

			secondContainer.Add(new CuiButton
			{
				RectTransform =
					{AnchorMin = "0.6 0.14", AnchorMax = "0.6 0.14", OffsetMin = "-125 -125", OffsetMax = "40 40"},
				Button =
				{
					Color = "0 0 0 0",
					Command = (page + 1) * basketItemsPerPage < playerBasket.GetCount()
						? $"UI_GameStoresRUST page {page + 1}"
						: string.Empty
				},
				Text =
				{
					Text = ">",
					Color = (page + 1) * basketItemsPerPage < playerBasket.GetCount() ? "1 1 1 1" : "1 1 1 0.2",
					Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf", FontSize = 80
				}
			}, StoreLayer + ".BlockPanel");

			for (var i = 0; i < basketItemsPerPage; i++)
			{
				UI_RecountPosition(out var xSwitch, out var ySwitch, i, basketItemsPerPage);

				secondContainer.Add(new CuiButton
					{
						RectTransform =
						{
							AnchorMin = "0.495 0.55",
							AnchorMax = "0.495 0.55",
							OffsetMin = $"{xSwitch} {ySwitch - _config.UI.ItemSide}",
							OffsetMax = $"{xSwitch + _config.UI.ItemSide} {ySwitch}"
						},
						Button = {Color = _config.UI.ItemBackgroundColor.Get, Command = string.Empty},
						Text = {Text = string.Empty}
					}, StoreLayer + ".BlockPanel", StoreLayer + $".BlockPanel.{i}");
			}

			for (var index = 0; index < wItems.Count; index++)
			{
				var item = wItems[index];

				ShowBasketItemUI(player, item, ref secondContainer, index);
			}

			CuiHelper.AddUi(player, secondContainer);
			CuiHelper.DestroyUi(player, StoreLayer + ".BlockPanel.Text");
		}

		private void ShowBasketItemUI(BasePlayer player, WItem item, ref CuiElementContainer secondContainer,
			int index)
		{
			if (item.IsBlueprint) ItemBlueprintImageUI(ref secondContainer, index);

			if (_config.Plugin.LoadSpriteImages && item.IsValid && item.itemDefinition != null)
			{
				secondContainer.Add(new CuiElement
				{
					Parent = StoreLayer + $".BlockPanel.{index}",
					Components =
					{
						new CuiImageComponent {ItemId = item.itemDefinition.itemid},
						new CuiRectTransformComponent
							{AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "5 5", OffsetMax = "-5 -5"}
					}
				});
			}
			else
			{
				if (!item.ImageUrl.Contains("http"))
					secondContainer.Add(new CuiElement
					{
						Parent = StoreLayer + $".BlockPanel.{index}",
						Components =
						{
							new CuiRawImageComponent {Png = item.ImageUrl},
							new CuiRectTransformComponent
								{AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "5 5", OffsetMax = "-5 -5"}
						}
					});
				else
					secondContainer.Add(new CuiElement
					{
						Parent = StoreLayer + $".BlockPanel.{index}",
						Components =
						{
							new CuiRawImageComponent {Url = item.ImageUrl},
							new CuiRectTransformComponent
								{AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "5 5", OffsetMax = "-5 -5"}
						}
					});
			}

			if (item.Amount > 1)
				secondContainer.Add(new CuiLabel
					{
						RectTransform =
							{AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 5", OffsetMax = "-5 0"},
						Text =
						{
							Text = "x" + item.Amount, Align = TextAnchor.LowerRight,
							Font = "robotocondensed-regular.ttf", FontSize = 24
						}
					}, StoreLayer + $".BlockPanel.{index}");

			secondContainer.Add(new CuiButton
				{
					RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"},
					Button =
					{
						Color = "0 0 0 0", Close = StoreLayer + $".BlockPanel.{index}.Open",
						Command =
							$"UI_GameStoresRUST take {index} {item.basketId}"
					},
					Text = {Text = string.Empty}
				}, StoreLayer + $".BlockPanel.{index}", StoreLayer + $".BlockPanel.{index}.Open");

			if (_config.UI.TextShow)
				secondContainer.Add(new CuiLabel
					{
						RectTransform =
							{AnchorMin = "0 0", AnchorMax = "1 0", OffsetMin = "0 -22.5", OffsetMax = "0 0"},
						Text =
						{
							Text = item.Name, Align = TextAnchor.MiddleCenter,
							Font = "robotocondensed-regular.ttf", FontSize = 16, Color = "1 1 1 0.8"
						}
					}, StoreLayer + $".BlockPanel.{index}");

			if (!CanRequestGetItem(Convert.ToInt32(item.basketId)))
			{
				ShowNotify(player, Msg(player, MsgTakeRequestProcessing));

				secondContainer.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} {item.basketId}"
					},
					Text =
					{
						Text = Msg(player, MsgTakeWait), Align = TextAnchor.MiddleCenter,
						Font = "robotocondensed-bold.ttf", Color = "1 1 1 0.4", FontSize = 24
					}
				}, StoreLayer + ".BlockPanel." + index, StoreLayer + ".BlockPanel." + index + ".Open");
			}
		}

		private void ItemBlueprintImageUI(ref CuiElementContainer secondContainer, int index)
		{
			if (_config.Plugin.LoadSpriteImages)
			{
				secondContainer.Add(new CuiElement
				{
					Parent = StoreLayer + $".BlockPanel.{index}",
					Components =
					{
						new CuiImageComponent {ItemId = ItemManager.blueprintBaseDef.itemid},
						new CuiRectTransformComponent
							{AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "5 5", OffsetMax = "-5 -5"}
					}
				});
			}
			else
			{
#if CARBON
				var blueprintImageComponent = new CuiRawImageComponent {Png = GetImage("blueprintbase")};
#else
				var blueprintImageComponent = ImageLibrary?.IsLoaded == true
					? new CuiRawImageComponent {Png = GetImage("blueprintbase")}
					: new CuiRawImageComponent {Url = "https://gamestores.app/img/games/rust/blueprintbase.png"};
#endif
				secondContainer.Add(new CuiElement
				{
					Parent = StoreLayer + $".BlockPanel.{index}",
					Components =
					{
						blueprintImageComponent,
						new CuiRectTransformComponent
							{AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "5 5", OffsetMax = "-5 -5"}
					}
				});
			}
		}

		private void CreateStoreExitButtonUI(BasePlayer player, ref CuiElementContainer container)
		{
			container.AddRange(_config.UI.StoreExitButton.Get(Msg(player, MsgExit), "closemenu", StoreLayer,
				close: StoreLayer));
		}

		private void CreateStoreUiContainer(ref CuiElementContainer container, BasePlayer player)
		{
			container.Add(_config.UI.Background.Get(StoreLayer, StoreLayer, true));

			container.AddRange(_config.UI.BasketTitle.Get(Msg(player, MsgBasket), string.Empty, StoreLayer));

			container.Add(_config.UI.BasketDescription.GetText(Msg(player, MsgBasketDescription), StoreLayer));

			container.AddRange(_config.UI.HelpButton.Get(Msg(player, MsgHelp), "UI_GameStoresRUST help",
				StoreLayer));
		}

		private void CreateBlockPanel(ref CuiElementContainer container, BasePlayer player)
		{
			container.Add(_config.UI.BlockPanel.GetImage(StoreLayer, StoreLayer + ".BlockPanel",
				StoreLayer + ".BlockPanel"));

			container.Add(_config.UI.RequestProcessingTitle.GetText(Msg(player, MsgRequestProcessing),
				StoreLayer + ".BlockPanel", StoreLayer + ".BlockPanel.Text"));
		}

		private void InitializeIcon(BasePlayer player)
		{
			UpdateUI(player, container =>
			{
				if (_config.UI.BucketURL.Contains("http"))
					CreateBucketIconWithImageLibrary(ref container);
				else
					CreateBucketIconWithoutImageLibrary(ref container);
			});
		}

		private void CreateBucketIconWithImageLibrary(ref CuiElementContainer container)
		{
#if CARBON
			var bucketImageComponent = new CuiRawImageComponent {Png = GetImage(ImageBucket)};
#else
			var bucketImageComponent = ImageLibrary is {IsLoaded: true}
				? new CuiRawImageComponent {Png = GetImage(ImageBucket)}
				: new CuiRawImageComponent {Url = _config.UI.BucketURL};
#endif

			container.Add(new CuiElement
			{
				Parent = "Overlay",
				Name = IconLayer,
				DestroyUi = IconLayer,
				Components =
				{
					bucketImageComponent,
					new CuiRectTransformComponent
					{
						AnchorMin = _config.UI.BucketPosition.AnchorMin,
						AnchorMax = _config.UI.BucketPosition.AnchorMax,
						OffsetMin = _config.UI.BucketPosition.OffsetMin,
						OffsetMax = _config.UI.BucketPosition.OffsetMax
					}
				}
			});

			container.Add(new CuiButton
			{
				RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"},
				Button = {Color = "0 0 0 0", Command = "chat.say /store"},
				Text = {Text = string.Empty}
			}, IconLayer);
		}

		private void CreateBucketIconWithoutImageLibrary(ref CuiElementContainer container)
		{
			container.Add(new CuiButton
			{
				RectTransform =
				{
					AnchorMin = _config.UI.BucketPosition.AnchorMin,
					AnchorMax = _config.UI.BucketPosition.AnchorMax,
					OffsetMin = _config.UI.BucketPosition.OffsetMin,
					OffsetMax = _config.UI.BucketPosition.OffsetMax
				},
				Button = {Color = "1 1 1 0.6", Sprite = "assets/icons/open.png", Command = "chat.say /store"},
				Text = {Text = string.Empty}
			}, "Overlay", IconLayer, IconLayer);
		}

		private void UI_RecountPosition(out double xSwitch, out double ySwitch, int count, int max)
		{
			var stringAmount = Math.Ceiling((double) max / _config.UI.ItemOnString);
			var currentString = Math.Floor((double) count / _config.UI.ItemOnString);
			var currentPosition = count % _config.UI.ItemOnString;


			var topYPosition = 0 + (float) stringAmount / 2 * _config.UI.ItemSide +
			                   ((float) stringAmount / 2 - 1) * _config.UI.ItemMargin;
			var topXPosition = 0 - (float) _config.UI.ItemOnString / 2 * _config.UI.ItemSide -
			                   ((float) _config.UI.ItemOnString / 2 - 1) * _config.UI.ItemMargin;

			var curYPosition = topYPosition - currentString * _config.UI.ItemSide - currentString *
				(_config.UI.ItemMargin + (_config.UI.TextShow ? 20 : 0));
			var curXPosition = topXPosition + currentPosition * _config.UI.ItemSide +
			                   currentPosition * _config.UI.ItemMargin;

			xSwitch = curXPosition;
			ySwitch = curYPosition;
		}

		#endregion

		#region UI.Helpers

		private static void UpdateUI(BasePlayer player, Action<CuiElementContainer> callback)
		{
			if (player == null) return;

			var container = new CuiElementContainer();

			callback?.Invoke(container);

			CuiHelper.AddUi(player, container);
		}

		#endregion

		#endregion

		#region Utils

		#region Player Basket

		#region Classes

		private class PlayerBasket
		{
			public Dictionary<int, WItem> BasketItems = new();

			public PlayerBasket(List<object> data)
			{
				foreach (Dictionary<string, object> product in data)
				{
					if (!product.TryGetValue("basketId", out var basketIdObj) ||
					    !int.TryParse(basketIdObj.ToString(), out var basketId))
						continue;

					var item = new WItem(product);

					BasketItems[basketId] = item;

					var leftTime = Instance?.WB_GetLeftTime(item.productId, item.ItemID, item.IsBlueprint) ?? 0;
					if (leftTime > 0)
					{
						item.IsBlocked = true;
						item.LeftTime = leftTime;
					}
				}
			}

			public void Clear()
			{
				BasketItems.Clear();
			}

			public List<WItem> GetItems(int page, int count)
			{
				return new List<WItem>(BasketItems.Values.Skip(page * count).Take(count));
			}

			public int GetCount()
			{
				return BasketItems.Count;
			}
		}

		#endregion

		#endregion

		#region Blocks

		private bool NE_IsCombatBlocked(BasePlayer player)
		{
			return Convert.ToBoolean(NoEscape?.Call("IsCombatBlocked", player));
		}

		private bool NE_IsRaidBlocked(BasePlayer player)
		{
			return Convert.ToBoolean(NoEscape?.Call("IsRaidBlocked", player));
		}

		private double WB_GetLeftTime(string productId, int itemID, bool isBlueprint)
		{
			return Convert.ToDouble(GameStoresWipeBlock?.Call("GetLeftTime", productId, itemID, isBlueprint));
		}

		#endregion

		#region Plugin Loading

		private void LoadHeaderParams()
		{
			reqHeaders.Add("X-Plugin-Version", Version.ToString());
			reqHeaders.Add("storeId", _config.API.ShopID);
			reqHeaders.Add("secretKey", _config.API.SecretKey);
			reqHeaders.Add("serverId", _config.API.ServerID);
		}
		
		private void RegisterCommands()
		{
			AddCovalenceCommand(_config.Plugin.Commands, nameof(CmdChatStore));
		}

		private bool InitializeServerSettings()
		{
			if (_config.API.ServerID == "UNDEFINED")
			{
				LogAction(null, "Incorrect ServerID, automatic command issuance is disabled");
				PrintError("Incorrect ServerID, receiving auto commands (Products) disabled");
				return false;
			}

			if (_config.API.ServerID != "0")
				StartInstantTimer();

			return true;
		}

		private void InitializeTimeoutCommands()
		{
			ListTimeOutCommand[0] = new Dictionary<ulong, int>();
			ListTimeOutCommand[1] = new Dictionary<ulong, int>();
			ListTimeOutCommand[2] = new Dictionary<ulong, int>();

			var totalTick = 0;
			var 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 void InitializePlayers()
		{
			for (var i = 0; i < BasePlayer.activePlayerList.Count; i++)
				OnPlayerConnected(BasePlayer.activePlayerList[i]);
		}

		private IEnumerator WaitForLoad()
		{
			while (Instance?.HasImage(ImageBucket) != true)
			{
				PrintError("Image of bucket is loading!");
				yield return new WaitForSeconds(1);
			}

			PrintWarning("Image of bucket loaded correctly!");
			InitializePlayers();

			yield return 0;
		}

		#endregion

		#region Image Loading

		#region Image Helpers

		private string GetImage(string name)
		{
#if CARBON
			return imageDatabase.GetImageString(name);
#else
			return Convert.ToString(ImageLibrary?.Call("GetImage", name));
#endif
		}

		private void AddImage(string url, string fileName, ulong imageId = 0)
		{
#if CARBON
			imageDatabase.Queue(true, new Dictionary<string, string>
			{
				[fileName] = url
			});
#else
			ImageLibrary?.Call("AddImage", url, fileName, imageId);
#endif
		}

		private bool HasImage(string name)
		{
#if CARBON
			return Convert.ToBoolean(imageDatabase.HasImage(name));
#else
			return Convert.ToBoolean(ImageLibrary?.Call("HasImage", name));
#endif
		}

		#endregion

		private const int maxImageCheck = 3;
		private int TryImageCounter;

		private void InitializeImages()
		{
#if CARBON
			imageDatabase.Queue(true, new Dictionary<string, string>
			{
				["NONE"] = "https://gspics.org/images/2024/03/29/0NOj7D.png",
				["LOADING"] = "https://gspics.org/images/2024/03/29/0NOxFI.png"
			});
#else
			if (ImageLibrary?.IsLoaded == true)
			{
				NoImageID = GetImage("NONE");
				LoadingImageID = GetImage("LOADING");
			}
#endif
		}

		private void InitializeBucketImage()
		{
			AddImage(_config.UI.BucketURL, ImageBucket);

			_loadingCoroutine = ServerMgr.Instance.StartCoroutine(WaitForLoad());
		}

		#endregion

		#region Take Item

		private void ProcessTake(BasePlayer player, Dictionary<string, object> obj)
		{
			LogAction(player, "Начало обработки товара");
			var itemInfo = new WItem(obj);

			try
			{
				if (!itemInfo.IsValid)
				{
					LogAction(player, $"Ошибка получения предмета: {itemInfo.Name}");
					return;
				}

				if (itemInfo.IsItem)
					ProcessItem(player, itemInfo);

				if (itemInfo.IsCommand)
					ProcessCommand(player, itemInfo);

				if (itemInfo.IsBlueprint)
					ProcessBlueprint(player, itemInfo);
			}
			catch (Exception e)
			{
				HandleItemProcessingError(player, itemInfo, e);
			}
		}

		private void ProcessItem(BasePlayer player, WItem itemInfo)
		{
			LogAction(player, $"Попытка получения предмета: {itemInfo.itemDefinition.shortname} [{itemInfo.Amount}]");

			var item = ItemManager.Create(itemInfo.itemDefinition, itemInfo.Amount);

			if (!player.inventory.GiveItem(item))
			{
				HandleItemGiveError(player, item, itemInfo);
			}
			else
			{
				LogAction(player, "Предмет выдан игроку в инвентарь");
				ShowNotify(player, Msg(player, MsgTakeGiveInventory, itemInfo.itemDefinition.displayName.english));
			}
		}

		private void ProcessInstantCommand(WItem itemInfo)
		{
			ExecuteCommands(null, itemInfo.commands, itemInfo.SteamID.ToString());
		}

		private void ProcessCommand(BasePlayer player, WItem itemInfo)
		{
			if (player == null)
			{
				ExecuteCommands(null, itemInfo.commands, itemInfo.SteamID.ToString());
				return;
			}

			LogAction(player, "Attempting to execute commands");

			ExecuteCommands(player, itemInfo.commands, player.UserIDString, player.displayName);

			ShowNotify(player, Msg(player, MsgTakeGiveCommand, itemInfo.Name));
		}

		private void ExecuteCommands(BasePlayer player, List<object> commands, string steamId, string username = null)
		{
			foreach (string command in commands)
			{
				var selfCommand = ReplacePlaceholders(command, steamId, username);

				ExecuteCommandSequence(selfCommand, player);
			}
		}

		private string ReplacePlaceholders(string command, string steamId, string username = null)
		{
			return command.Replace("%steamid%", steamId, StringComparison.OrdinalIgnoreCase).Replace("%username%", username ?? string.Empty, StringComparison.OrdinalIgnoreCase);
		}

		private void ProcessBlueprint(BasePlayer player, WItem itemInfo)
		{
			LogAction(player, $"Попытка получения рецепта {itemInfo.itemDefinition.shortname}");

			var create = ItemManager.Create(ItemManager.blueprintBaseDef);
			create.blueprintTarget = itemInfo.itemDefinition.itemid;

			if (!player.inventory.GiveItem(create))
			{
				HandleItemGiveError(player, create, itemInfo);
			}
			else
			{
				LogAction(player, "Рецепт выдан игроку в инвентарь");

				ShowNotify(player,
					Msg(player, MsgTakeGiveBlueprintInventory, itemInfo.itemDefinition.displayName.english));
			}
		}

		private void ExecuteCommandSequence(string command, BasePlayer player = null)
		{
			LogAction(player, $"Исполнение команды: {command}");
			Server.Command(command);
		}

		#endregion

		#region Instant

		private void StartInstantTimer()
		{
			_checkInstant = timer.Every(60, HandleInstantCommands);
		}

		private void DestroyInstantTimer()
		{
			_checkInstant?.Destroy();
		}

		private void TakeInstant(int basketID)
		{
			LogAction(null, "---------------------------------");
			LogAction(null, $"[AutoCommands] Запрос на получение товара [{basketID}]");

			RequestGetItem(basketID, true);
		}

		#region Handle

		private void HandleInstantCommands()
		{
			Request("baskets.instantCommands", null, (code, response) =>
			{
				switch (code)
				{
					case 200:
						HandleInstantRequestSuccess(response);
						break;
					default:
						LogAction(null, "Ошибка выполнения запроса для выдачи автоматических команд");
						break;
				}
			});
		}

		private void HandleInstantRequestSuccess(string response)
		{
			var firstInfo =
				JsonConvert.DeserializeObject<Dictionary<string, object>>(response, new KeyValuesConverter());
			if (firstInfo.ContainsKey("result"))
			{
				if (firstInfo["result"].ToString() == "success")
				{
					var data = firstInfo["data"] as List<object>;
					if (data == null)
					{
						LogAction(null, $"Ошибка получения данных от сервера: {response}");
						return;
					}

					var i = 1;
					foreach (Dictionary<string, object> product in data)
					{
						if (!product.TryGetValue("basketId", out var basketId)) continue;

						var basketID = Convert.ToInt32(basketId);

						if (!_config.Plugin.ExecuteInstantCommandsWhenNotInServer)
							if (product.TryGetValue("steamId", out var value))
							{
								var steamId = Convert.ToString(value);
								if (!string.IsNullOrEmpty(steamId) && steamId.IsSteamId() &&
								    covalence.Players.FindPlayerById(steamId) == null)
									continue;
							}

						timer.In(i, () => TakeInstant(basketID));

						i++;
					}

					return;
				}

				if (firstInfo["result"].ToString() == "fail")
					if (firstInfo.TryGetValue("message", out var value))
					{
						var message = Convert.ToString(value);
						if (!string.IsNullOrEmpty(message))
						{
							LogAction(null, $"Ошибка получения данных от сервера: {message}", true, true);
							return;
						}
					}
			}

			LogAction(null, "Ошибка получения данных от сервера");
		}

		private void HandleTakeInstantResponse(int code, string response, int basketID)
		{
			switch (code)
			{
				case 0:
					LogAction(null, $"[AutoCommands] API не ответило на запрос: {basketID}");
					PrintError("Api does not responded to a request");
					break;
				case 200:
					HandleTakeInstantSuccess(response, basketID);
					break;
				case 404:
					LogAction(null, $"[AutoCommands] Api не ответило на запрос: {basketID}");
					LogAction(null, "Response code: 404, please check your configurations", true);
					break;
			}
		}

		private void HandleTakeInstantSuccess(string response, int basketID)
		{
			var responseData =
				JsonConvert.DeserializeObject<Dictionary<string, object>>(response, new KeyValuesConverter());
			if (responseData == null)
			{
				LogAction(null, $"[AutoCommands] Ошибка получения данных от сервера: {response}");
				return;
			}

			if (!responseData.TryGetValue("data", out var value))
			{
				LogAction(null, $"[AutoCommands] Ошибка получения товара, отсутствует Data [{basketID}]");
				return;
			}

			if (value is not Dictionary<string, object> data) return;

			var itemInfo = new WItem(data);
			if (!itemInfo.IsValid)
			{
				LogAction(null,
					$"[AutoCommands] Ошибка получения товара [{basketID}], отсутствует информация о товаре [{itemInfo.Name}]");
				return;
			}

			if (covalence?.Players?.FindPlayerById(itemInfo.SteamID.ToString()) == null)
			{
				LogAction(null,
					$"[AutoCommands] Ошибка получения товара [{basketID}], отсутствует игрок [{itemInfo.SteamID}]");
				return;
			}

			var leftTime = WB_GetLeftTime(itemInfo.productId,
				itemInfo.ItemID, itemInfo.IsBlueprint);
			if (leftTime > 0)
			{
				LogAction(nul
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху