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

FREE Economics : 1.0.0 1.0.0

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

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using UnityEngine;

// TODO: Add SQLite and MySQL database support

namespace Oxide.Plugins
{
    [Info("Economics", "Enilgles", "1.0.0")]
    [Description("Basic economics system and economy API")]
    public class Economics : CovalencePlugin
    {
        #region Configuration

        private Configuration config;

        private sealed class Configuration
        {
            [JsonProperty("Allow negative balance for accounts")]
            public bool AllowNegativeBalance;

            [JsonProperty("Balance limit for accounts (0 to disable)")]
            public int BalanceLimit;

            [JsonProperty("Maximum balance for accounts (0 to disable)")] // TODO: From version 3.8.6; remove eventually
            private int BalanceLimitOld { set => BalanceLimit = value; }

            [JsonProperty("Negative balance limit for accounts (0 to disable)")]
            public int NegativeBalanceLimit;

            [JsonProperty("Remove unused accounts")]
            public bool RemoveUnused = true;

            [JsonProperty("Log transactions to file")]
            public bool LogTransactions;

            [JsonProperty("Starting account balance (0 or higher)")]
            public int StartingBalance = 1000;

            [JsonProperty("Starting money amount (0 or higher)")] // TODO: From version 3.8.6; remove eventually
            private int StartingBalanceOld { set => StartingBalance = value; }

            [JsonProperty("Wipe balances on new save file")]
            public bool WipeOnNewSave;

            [JsonProperty("Show balance in HUD")]
            public bool ShowBalanceHUD = true;

            [JsonProperty("HUD text color (RGBA format)")]
            public string HUDTextColor = "1 1 1 1";

            [JsonProperty("HUD background color (RGBA format)")]
            public string HUDBackgroundColor = "0 0 0 0.5";

            [JsonProperty("Currency name")]
            public string CurrencyName = "Coins";

            [JsonProperty("Настройка получение валюты за убийство игроков")]
            public CurrencySettings PlayerKillSettings = new()
            {
                Permission = "",
                Enabled = true,
                Rewards = new RewardSettings
                {
                    Chance = 35,
                    Amount = 10
                }
            };

            [JsonProperty("Настройка получение валюты за убийство животных")]
            public CurrencySettings AnimalKillSettings = new()
            {
                Permission = "",
                Enabled = true,
                Rewards = new RewardSettings
                {
                    Chance = 53,
                    Amount = 2
                }
            };

            [JsonProperty("Настройка получение валюты за убийство NPC")]
            public CurrencySettings NPCKillSettings = new()
            {
                Permission = "",
                Enabled = true,
                Rewards = new RewardSettings
                {
                    Chance = 10,
                    Amount = 15
                }
            };

            [JsonProperty("Настройка получение валюты за уничтожение танка")]
            public CurrencySettings BradleyKillSettings = new()
            {
                Permission = "",
                Enabled = true,
                Rewards = new RewardSettings
                {
                    Chance = 44,
                    Amount = 100
                }
            };

            [JsonProperty("Настройка получение валюты за уничтожение вертолета")]
            public CurrencySettings HelicopterKillSettings = new()
            {
                Permission = "",
                Enabled = true,
                Rewards = new RewardSettings
                {
                    Chance = 80,
                    Amount = 200
                }
            };

            [JsonProperty("Настройка получение валюты за уничтожение бочек")]
            public CurrencySettings BarrelDestroySettings = new()
            {
                Permission = "",
                Enabled = true,
                Rewards = new RewardSettings
                {
                    Chance = 23,
                    Amount = 5
                }
            };

            [JsonProperty("Настройка получение валюты за добычу ресурсов")]
            public ResourceCurrencySettings ResourceGatherSettings = new()
            {
                Permission = "",
                Enabled = true,
                ResourceRewards = new Dictionary<string, RewardSettings>
                {
                    ["sulfur.ore"] = new RewardSettings
                    {
                        Chance = 10,
                        Amount = 10
                    },
                    ["stones"] = new RewardSettings
                    {
                        Chance = 20,
                        Amount = 1
                    }
                }
            };

            [JsonProperty("Настройка получение валюты за поднятие ресурсов с земли (грибы, ягоды, дерево и т.д)")]
            public ResourceCurrencySettings ResourcePickupSettings = new()
            {
                Permission = "",
                Enabled = true,
                ResourceRewards = new Dictionary<string, RewardSettings>
                {
                    ["sulfur.ore"] = new RewardSettings
                    {
                        Chance = 10,
                        Amount = 10
                    },
                    ["stones"] = new RewardSettings
                    {
                        Chance = 20,
                        Amount = 3
                    }
                }
            };

            [JsonProperty("Настройка получение валюты за проведенное время на сервере")]
            public TimeCurrencySettings TimeOnServerSettings = new()
            {
                Permission = "",
                Enabled = true,
                TimeRequired = 3600,
                Amount = 10
            };

            [JsonProperty("IQSphereEvent : Настройка получение валюты за убийство NPC (Under - под сферой, Around - вокруг сферы, Tier1 - 1 этаж сферы, Tier2 - 2 этаж сферы, Tier3 - 3 этаж сферы)")]
            public IQSphereSettings SphereEventSettings = new()
            {
                Under = new CurrencySettings
                {
                    Permission = "",
                    Enabled = true,
                    Rewards = new RewardSettings
                    {
                        Chance = 50,
                        Amount = 5
                    }
                },
                Around = new CurrencySettings
                {
                    Permission = "",
                    Enabled = true,
                    Rewards = new RewardSettings
                    {
                        Chance = 30,
                        Amount = 5
                    }
                },
                Tier1 = new CurrencySettings
                {
                    Permission = "",
                    Enabled = true,
                    Rewards = new RewardSettings
                    {
                        Chance = 30,
                        Amount = 10
                    }
                },
                Tier2 = new CurrencySettings
                {
                    Permission = "",
                    Enabled = true,
                    Rewards = new RewardSettings
                    {
                        Chance = 45,
                        Amount = 12
                    }
                },
                Tier3 = new CurrencySettings
                {
                    Permission = "",
                    Enabled = true,
                    Rewards = new RewardSettings
                    {
                        Chance = 70,
                        Amount = 15
                    }
                }
            };

            public string ToJson()
            {
                return JsonConvert.SerializeObject(this);
            }

            public Dictionary<string, object> ToDictionary()
            {
                return JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
            }
        }

        [Serializable]
        public class CurrencySettings
        {
            [JsonProperty("Права для использования данной возможности (Если вам требуется сделать ее доступной всем по стандарту - оставьте поле пустым)")]
            public string Permission = "";

            [JsonProperty("Использовать эту возможность получения валюты")]
            public bool Enabled = true;

            [JsonProperty("Настройка получения валюты")]
            public RewardSettings Rewards = new();
        }

        [Serializable]
        public class RewardSettings
        {
            [JsonProperty("Шанс получить валюту")]
            public int Chance = 100;

            [JsonProperty("Сколько выдавать валюты")]
            public int Amount = 10;
        }

        [Serializable]
        public class ResourceCurrencySettings
        {
            [JsonProperty("Права для использования данной возможности (Если вам требуется сделать ее доступной всем по стандарту - оставьте поле пустым)")]
            public string Permission = "";

            [JsonProperty("Использовать эту возможность получения валюты")]
            public bool Enabled = true;

            [JsonProperty("Сколько начислять валюты за ресурсы ( [за какой ресурс давать] = { остальная настройка }")]
            public Dictionary<string, RewardSettings> ResourceRewards = new();
        }

        [Serializable]
        public class TimeCurrencySettings
        {
            [JsonProperty("Права для использования данной возможности (Если вам требуется сделать ее доступной всем по стандарту - оставьте поле пустым)")]
            public string Permission = "";

            [JsonProperty("Использовать эту возможность получения валюты")]
            public bool Enabled = true;

            [JsonProperty("Сколько нужно провести времени,чтобы выдали награду")]
            public int TimeRequired = 3600;

            [JsonProperty("Сколько начислять валюты за проведенное время на сервере")]
            public int Amount = 10;
        }

        [Serializable]
        public class IQSphereSettings
        {
            [JsonProperty("Under")]
            public CurrencySettings Under = new();

            [JsonProperty("Around")]
            public CurrencySettings Around = new();

            [JsonProperty("Tier1")]
            public CurrencySettings Tier1 = new();

            [JsonProperty("Tier2")]
            public CurrencySettings Tier2 = new();

            [JsonProperty("Tier3")]
            public CurrencySettings Tier3 = new();
        }

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

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null)
                {
                    throw new JsonException();
                }

                if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
                {
                    LogWarning("Configuration appears to be outdated; updating and saving");
                    SaveConfig();
                }
            }
            catch
            {
                LogWarning($"Configuration file {Name}.json is invalid; using defaults");
                LoadDefaultConfig();
            }
        }

        protected override void SaveConfig()
        {
            LogWarning($"Configuration changes saved to {Name}.json");
            Config.WriteObject(config, true);
        }

        #endregion Configuration

        #region Stored Data

        private DynamicConfigFile data;
        private StoredData storedData;
        private bool changed;

        private sealed class StoredData
        {
            public readonly Dictionary<string, double> Balances = new();
        }

        private void SaveData()
        {
            if (changed)
            {
                Puts("Saving balances for players...");
                Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
            }
        }

        private void OnServerSave()
        {
            SaveData();
        }

        private void Unload()
        {
            SaveData();

            // Destroy all UI elements for all players
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                if (player?.IsConnected != true)
                {
                    continue;
                }

                // Force destroy all UI elements with this plugin's prefix
                DestroyUI(player);
                _ = CuiHelper.DestroyUi(player, HUD_PANEL_NAME); // Direct call as a fallback
            }
        }

        #endregion Stored Data

        #region Localization

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NotAllowed"] = "У вас нет прав на использование команды {0}",
                ["UsageBalance"] = "Использование: {0} <игрок>",
                ["UsageBalanceOthers"] = "Использование: {0} <игрок>",
                ["UsageDeposit"] = "Использование: {0} <игрок> <сумма>",
                ["UsageSetBalance"] = "Использование: {0} <игрок> <сумма>",
                ["UsageTransfer"] = "Использование: {0} <игрок> <сумма>",
                ["UsageWithdraw"] = "Использование: {0} <игрок> <сумма>",
                ["UsageWipe"] = "Использование: {0}",
                ["ZeroAmount"] = "Сумма должна быть больше 0",
                ["NegativeBalance"] = "Баланс не может быть отрицательным",
                ["PlayerBalance"] = "Баланс игрока {0}: {1} {2}",
                ["YourBalance"] = "Ваш баланс: {0} {1}",
                ["DepositedToAll"] = "Внесено {0} {1} на счета {2} игроков",
                ["SetBalanceForAll"] = "Установлен баланс {0} {1} для {2} игроков",
                ["TransferedToAll"] = "Переведено {0} {1} на счета {2} игроков",
                ["WithdrawnForAll"] = "Снято {0} {1} со счета {2} игрока",
                ["TransactionFailed"] = "Не удалось выполнить транзакцию для игрока {0}",
                ["YouLackMoney"] = "У вас недостаточно средств",
                ["TransferToSelf"] = "Вы не можете перевести деньги самому себе",
                ["TransferredTo"] = "Переведено {0} {1} игроку {2}",
                ["ReceivedFrom"] = "Вы получили {0} {1} от игрока {2}",
                ["DataWiped"] = "Все данные экономики были удалены",
                ["PlayersFound"] = "Найдено несколько игроков: {0}",
                ["NoPlayersFound"] = "Игрок {0} не найден",
                ["YouReceivedMoney"] = "Вы получили: {0} монет",
                ["YouReceivedMoneyForKill"] = "Вы получили: {0} монет за убийство игрока",
                ["YouReceivedMoneyForAnimal"] = "Вы получили: {0} монет за убийство животного",
                ["YouReceivedMoneyForNPC"] = "Вы получили: {0} монет за убийство NPC",
                ["YouReceivedMoneyForBradley"] = "Вы получили: {0} монет за уничтожение танка",
                ["YouReceivedMoneyForHeli"] = "Вы получили: {0} монет за уничтожение вертолета",
                ["YouReceivedMoneyForBarrel"] = "Вы получили: {0} монет за уничтожение бочки",
                ["YouReceivedMoneyForResource"] = "Вы получили: {0} монет за добычу ресурса {2}",
                ["YouReceivedMoneyForPickup"] = "Вы получили: {0} монет за подбор {2}",
                ["YouReceivedMoneyForTime"] = "Вы получили: {0} монет за время на сервере",
                ["YouReceivedMoneyForIQSphere"] = "Вы получили: {0} монет за убийство NPC в {2}",
                ["LogDeposit"] = "Внесение: {0} {1} на счет игрока {2}",
                ["LogSetBalance"] = "Установка баланса: {0} {1} для игрока {2}",
                ["LogTransfer"] = "Перевод: {0} {1} от игрока {2} игроку {3}",
                ["LogWithdrawl"] = "Снятие: {0} {1} со счета игрока {2}"
            }, this);
        }

        #endregion Localization

        #region Initialization

        private const string permissionBalance = "economics.balance";
        private const string permissionDeposit = "economics.deposit";
        private const string permissionDepositAll = "economics.depositall";
        private const string permissionSetBalance = "economics.setbalance";
        private const string permissionSetBalanceAll = "economics.setbalanceall";
        private const string permissionTransfer = "economics.transfer";
        private const string permissionTransferAll = "economics.transferall";
        private const string permissionWithdraw = "economics.withdraw";
        private const string permissionWithdrawAll = "economics.withdrawall";
        private const string permissionWipe = "economics.wipe";

        /// <summary>
        /// UI constants
        /// </summary>
        private const string HUD_PANEL_NAME = "EconomicsHUD";
        private const string BALANCE_BUTTON_NAME = "EconomicsBalanceButton";
        private readonly Dictionary<BasePlayer, string> uiElements = new();
        private readonly string BalanceIconUrl = "https://i.imgur.com/5ALJG2t.png";

        /// <summary>
        /// Таймеры для времени на сервере
        /// </summary>
        private readonly Dictionary<string, Timer> playerTimeRewardTimers = new();
        /// <summary>
        /// Информация о последних убийствах для предотвращения спама
        /// </summary>
        private readonly Dictionary<string, Dictionary<string, float>> lastPlayerKills = new();
        /// <summary>
        /// 5 минут кулдаун между убийствами одного и того же игрока
        /// </summary>
        private const float PlayerKillCooldown = 300f;

        private void Init()
        {
            // Register universal chat/console commands
            AddLocalizedCommand(nameof(CommandBalance));
            AddLocalizedCommand(nameof(CommandDeposit));
            AddLocalizedCommand(nameof(CommandSetBalance));
            AddLocalizedCommand(nameof(CommandTransfer));
            AddLocalizedCommand(nameof(CommandWithdraw));
            AddLocalizedCommand(nameof(CommandWipe));

            // Register permissions for commands
            permission.RegisterPermission(permissionBalance, this);
            permission.RegisterPermission(permissionDeposit, this);
            permission.RegisterPermission(permissionDepositAll, this);
            permission.RegisterPermission(permissionSetBalance, this);
            permission.RegisterPermission(permissionSetBalanceAll, this);
            permission.RegisterPermission(permissionTransfer, this);
            permission.RegisterPermission(permissionTransferAll, this);
            permission.RegisterPermission(permissionWithdraw, this);
            permission.RegisterPermission(permissionWithdrawAll, this);
            permission.RegisterPermission(permissionWipe, this);

            // Set default language to Russian
            lang.SetServerLanguage("ru");

            // Load existing data and migrate old data format
            data = Interface.Oxide.DataFileSystem.GetFile(Name);
            try
            {
                Dictionary<ulong, double> temp = data.ReadObject<Dictionary<ulong, double>>();
                try
                {
                    storedData = new StoredData();
                    foreach (KeyValuePair<ulong, double> old in temp)
                    {
                        if (!storedData.Balances.ContainsKey(old.Key.ToString()))
                        {
                            storedData.Balances.Add(old.Key.ToString(), old.Value);
                        }
                    }
                    changed = true;
                }
                catch
                {
                    // Ignored
                }
            }
            catch
            {
                storedData = data.ReadObject<StoredData>();
                changed = true;
            }

            List<string> playerData = new(storedData.Balances.Keys);

            // Check for and set any balances over maximum allowed
            if (config.BalanceLimit > 0)
            {
                foreach (string p in playerData)
                {
                    if (storedData.Balances[p] > config.BalanceLimit)
                    {
                        storedData.Balances[p] = config.BalanceLimit;
                        changed = true;
                    }
                }
            }

            // Check for and remove any inactive player balance data
            if (config.RemoveUnused)
            {
                foreach (string p in playerData)
                {
                    if (storedData.Balances[p].Equals(config.StartingBalance))
                    {
                        _ = storedData.Balances.Remove(p);
                        changed = true;
                    }
                }
            }

            // Регистрируем пермишены для получения валюты
            if (!string.IsNullOrEmpty(config.PlayerKillSettings.Permission))
            {
                permission.RegisterPermission(config.PlayerKillSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.AnimalKillSettings.Permission))
            {
                permission.RegisterPermission(config.AnimalKillSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.NPCKillSettings.Permission))
            {
                permission.RegisterPermission(config.NPCKillSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.BradleyKillSettings.Permission))
            {
                permission.RegisterPermission(config.BradleyKillSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.HelicopterKillSettings.Permission))
            {
                permission.RegisterPermission(config.HelicopterKillSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.BarrelDestroySettings.Permission))
            {
                permission.RegisterPermission(config.BarrelDestroySettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.ResourceGatherSettings.Permission))
            {
                permission.RegisterPermission(config.ResourceGatherSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.ResourcePickupSettings.Permission))
            {
                permission.RegisterPermission(config.ResourcePickupSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.TimeOnServerSettings.Permission))
            {
                permission.RegisterPermission(config.TimeOnServerSettings.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.SphereEventSettings.Under.Permission))
            {
                permission.RegisterPermission(config.SphereEventSettings.Under.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.SphereEventSettings.Around.Permission))
            {
                permission.RegisterPermission(config.SphereEventSettings.Around.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.SphereEventSettings.Tier1.Permission))
            {
                permission.RegisterPermission(config.SphereEventSettings.Tier1.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.SphereEventSettings.Tier2.Permission))
            {
                permission.RegisterPermission(config.SphereEventSettings.Tier2.Permission, this);
            }

            if (!string.IsNullOrEmpty(config.SphereEventSettings.Tier3.Permission))
            {
                permission.RegisterPermission(config.SphereEventSettings.Tier3.Permission, this);
            }
        }

        private void OnServerInitialized()
        {
            // Clean up any existing UI elements that might be leftover from a plugin reload
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                if (player?.IsConnected == true)
                {
                    // Try to destroy any existing UI elements
                    DestroyUI(player);
                    _ = CuiHelper.DestroyUi(player, HUD_PANEL_NAME);
                    _ = CuiHelper.DestroyUi(player, BALANCE_BUTTON_NAME);
                }
            }

            // Create UI for all active players
            _ = timer.Once(0.5f, () =>
            {
                foreach (BasePlayer player in BasePlayer.activePlayerList)
                {
                    if (player?.IsConnected == true)
                    {
                        if (config.ShowBalanceHUD)
                        {
                            CreateBalanceHUD(player);
                        }

                        // Всегда создаем кнопку
                        CreateBalanceButton(player);

                        // Перезапускаем таймер начисления валюты за время на сервере
                        StartTimeRewardTimer(player.UserIDString);
                    }
                }
            });
        }

        private void OnNewSave()
        {
            if (config.WipeOnNewSave)
            {
                storedData.Balances.Clear();
                changed = true;
                _ = Interface.Call("OnEconomicsDataWiped");
            }
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (config.ShowBalanceHUD)
            {
                CreateBalanceHUD(player);
            }

            // Всегда создаем кнопку, независимо от настроек HUD
            CreateBalanceButton(player);

            // Запускаем таймер начисления валюты за время на сервере
            StartTimeRewardTimer(player.UserIDString);
        }

        private void OnPlayerDisconnected(BasePlayer player)
        {
            if (uiElements.ContainsKey(player))
            {
                DestroyUI(player);
                _ = uiElements.Remove(player);
            }

            // Останавливаем таймер начисления валюты за время на сервере
            StopTimeRewardTimer(player.UserIDString);
        }

        #endregion Initialization

        #region API Methods

        private double Balance(string playerId)
        {
            if (string.IsNullOrEmpty(playerId))
            {
                LogWarning("Balance method called without a valid player ID");
                return 0.0;
            }

            return storedData.Balances.TryGetValue(playerId, out double playerData) ? playerData : config.StartingBalance;
        }

        private double Balance(object playerId)
        {
            return Balance(GetUserId(playerId));
        }

        private string GetUserId(object playerId)
        {
            if (playerId is ulong)
            {
                return playerId.ToString();
            }

            // Support Rusts BasePlayer.userID type
            string userId = playerId.ToString();
            if (string.IsNullOrEmpty(userId) || !userId.IsSteamId())
            {
                throw new ArgumentException("Invalid player ID, playerId must be a valid SteamID of type ulong or string");
            }

            return userId;
        }

        private bool Deposit(string playerId, double amount)
        {
            if (string.IsNullOrEmpty(playerId))
            {
                LogWarning("Deposit method called without a valid player ID");
                return false;
            }

            if (amount > 0 && SetBalance(playerId, amount + Balance(playerId)))
            {
                _ = Interface.Call("OnEconomicsDeposit", playerId, amount);

                if (config.LogTransactions)
                {
                    LogToFile("transactions", $"[{DateTime.Now}] {GetLang("LogDeposit", null, amount, playerId)}", this);
                }

                return true;
            }

            return false;
        }

        private bool Deposit(object playerId, double amount)
        {
            return Deposit(GetUserId(playerId), amount);
        }

        private bool SetBalance(string playerId, double amount)
        {
            if (string.IsNullOrEmpty(playerId))
            {
                LogWarning("SetBalance method called without a valid player ID");
                return false;
            }

            if (amount >= 0 || config.AllowNegativeBalance)
            {
                amount = Math.Round(amount, 2);
                if (config.BalanceLimit > 0 && amount > config.BalanceLimit)
                {
                    amount = config.BalanceLimit;
                }
                else if (config.AllowNegativeBalance && config.NegativeBalanceLimit < 0 && amount < config.NegativeBalanceLimit)
                {
                    amount = config.NegativeBalanceLimit;
                }

                storedData.Balances[playerId] = amount;
                changed = true;

                _ = Interface.Call("OnEconomicsBalanceUpdated", playerId, amount);
                _ = Interface.CallDeprecatedHook("OnBalanceChanged", "OnEconomicsBalanceUpdated", new DateTime(2022, 7, 1), playerId, amount);

                if (config.LogTransactions)
                {
                    LogToFile("transactions", $"[{DateTime.Now}] {GetLang("LogSetBalance", null, amount, playerId)}", this);
                }

                return true;
            }

            return false;
        }

        private bool SetBalance(object playerId, double amount)
        {
            return SetBalance(GetUserId(playerId), amount);
        }

        private bool Transfer(string playerId, string targetId, double amount)
        {
            if (string.IsNullOrEmpty(playerId))
            {
                LogWarning("Transfer method called without a valid player ID");
                return false;
            }

            if (Withdraw(playerId, amount) && Deposit(targetId, amount))
            {
                _ = Interface.Call("OnEconomicsTransfer", playerId, targetId, amount);

                if (config.LogTransactions)
                {
                    LogToFile("transactions", $"[{DateTime.Now}] {GetLang("LogTransfer", null, amount, targetId, playerId)}", this);
                }

                return true;
            }

            return false;
        }

        private bool Transfer(object playerId, ulong targetId, double amount)
        {
            return Transfer(GetUserId(playerId), targetId.ToString(), amount);
        }

        private bool Withdraw(string playerId, double amount)
        {
            if (string.IsNullOrEmpty(playerId))
            {
                LogWarning("Withdraw method called without a valid player ID");
                return false;
            }

            if (amount >= 0 || config.AllowNegativeBalance)
            {
                double balance = Balance(playerId);
                if ((balance >= amount || (config.AllowNegativeBalance && balance + amount > config.NegativeBalanceLimit)) && SetBalance(playerId, balance - amount))
                {
                    _ = Interface.Call("OnEconomicsWithdrawl", playerId, amount);

                    if (config.LogTransactions)
                    {
                        LogToFile("transactions", $"[{DateTime.Now}] {GetLang("LogWithdrawl", null, amount, playerId)}", this);
                    }

                    return true;
                }
            }

            return false;
        }

        private bool Withdraw(object playerId, double amount)
        {
            return Withdraw(GetUserId(playerId), amount);
        }

        #endregion API Methods

        #region Commands

        #region Balance Command

        private void CommandBalance(IPlayer player, string command, string[] args)
        {
            if (args?.Length > 0)
            {
                if (!player.HasPermission(permissionBalance))
                {
                    Message(player, "NotAllowed", command);
                    return;
                }

                IPlayer target = FindPlayer(args[0], player);
                if (target == null)
                {
                    Message(player, "UsageBalance", command);
                    return;
                }

                Message(player, "PlayerBalance", target.Name, Balance(target.Id));
                return;
            }

            if (player.IsServer)
            {
                Message(player, "UsageBalanceOthers", command);
            }
            else
            {
                Message(player, "YourBalance", Balance(player.Id));
            }
        }

        #endregion Balance Command

        #region Deposit Command

        private void CommandDeposit(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(permissionDeposit))
            {
                Message(player, "NotAllowed", command);
                return;
            }

            if (args == null || args.Length <= 1)
            {
                Message(player, "UsageDeposit", command);
                return;
            }

            _ = double.TryParse(args[1], out double amount);
            if (amount <= 0)
            {
                Message(player, "ZeroAmount");
                return;
            }

            if (args[0] == "*")
            {
                if (!player.HasPermission(permissionDepositAll))
                {
                    Message(player, "NotAllowed", command);
                    return;
                }

                int receivers = 0;
                foreach (string targetId in storedData.Balances.Keys.ToList())
                {
                    if (Deposit(targetId, amount))
                    {
                        receivers++;
                    }
                }
                Message(player, "DepositedToAll", amount * receivers, amount, receivers);
            }
            else
            {
                IPlayer target = FindPlayer(args[0], player);
                if (target == null)
                {
                    return;
                }

                if (Deposit(target.Id, amount))
                {
                    Message(player, "PlayerBalance", target.Name, Balance(target.Id));
                }
                else
                {
                    Message(player, "TransactionFailed", target.Name);
                }
            }
        }

        #endregion Deposit Command

        #region Set Balance Command

        private void CommandSetBalance(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(permissionSetBalance))
            {
                Message(player, "NotAllowed", command);
                return;
            }

            if (args == null || args.Length <= 1)
            {
                Message(player, "UsageSetBalance", command);
                return;
            }

            _ = double.TryParse(args[1], out double amount);

            if (amount < 0)
            {
                Message(player, "NegativeBalance");
                return;
            }

            if (args[0] == "*")
            {
                if (!player.HasPermission(permissionSetBalanceAll))
                {
                    Message(player, "NotAllowed", command);
                    return;
                }

                int receivers = 0;
                foreach (string targetId in storedData.Balances.Keys.ToList())
                {
                    if (SetBalance(targetId, amount))
                    {
                        receivers++;
                    }
                }
                Message(player, "SetBalanceForAll", amount, receivers);
            }
            else
            {
                IPlayer target = FindPlayer(args[0], player);
                if (target == null)
                {
                    return;
                }

                if (SetBalance(target.Id, amount))
                {
                    Message(player, "PlayerBalance", target.Name, Balance(target.Id));
                }
                else
                {
                    Message(player, "TransactionFailed", target.Name);
                }
            }
        }

        #endregion Set Balance Command

        #region Transfer Command

        private void CommandTransfer(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(permissionTransfer))
            {
                Message(player, "NotAllowed", command);
                return;
            }

            if (args == null || args.Length <= 1)
            {
                Message(player, "UsageTransfer", command);
                return;
            }

            _ = double.TryParse(args[1], out double amount);

            if (amount <= 0)
            {
                Message(player, "ZeroAmount");
                return;
            }

            if (args[0] == "*")
            {
                if (!player.HasPermission(permissionTransferAll))
                {
                    Message(player, "NotAllowed", command);
                    return;
                }

                if (!Withdraw(player.Id, amount))
                {
                    Message(player, "YouLackMoney");
                    return;
                }

                int receivers = players.Connected.Count();
                double splitAmount = amount /= receivers;

                foreach (IPlayer target in players.Connected)
                {
                    if (Deposit(target.Id, splitAmount) && target.IsConnected)
                    {
                        Message(target, "ReceivedFrom", splitAmount, player.Name);
                    }
                }
                Message(player, "TransferedToAll", amount, splitAmount, receivers);
            }
            else
            {
                IPlayer target = FindPlayer(args[0], player);
                if (target == null)
                {
                    return;
                }

                if (target.Equals(player))
                {
                    Message(player, "TransferToSelf");
                    return;
                }

                if (!Withdraw(player.Id, amount))
                {
                    Message(player, "YouLackMoney");
                    return;
                }

                if (Deposit(target.Id, amount))
                {
                    Message(player, "TransferredTo", amount, target.Name);
                    Message(target, "ReceivedFrom", amount, player.Name);
                }
                else
                {
                    Message(player, "TransactionFailed", target.Name);
                }
            }
        }

        #endregion Transfer Command

        #region Withdraw Command

        private void CommandWithdraw(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(permissionWithdraw))
            {
                Message(player, "NotAllowed", command);
                return;
            }

            if (args == null || args.Length <= 1)
            {
                Message(player, "UsageWithdraw", command);
                return;
            }

            _ = double.TryParse(args[1], out double amount);

            if (amount <= 0)
            {
                Message(player, "ZeroAmount");
                return;
            }

            if (args[0] == "*")
            {
                if (!player.HasPermission(permissionWithdrawAll))
                {
                    Message(player, "NotAllowed", command);
                    return;
                }

                int receivers = 0;
                foreach (string targetId in storedData.Balances.Keys.ToList())
                {
                    if (Withdraw(targetId, amount))
                    {
                        receivers++;
                    }
                }
                Message(player, "WithdrawnForAll", amount * receivers, amount, receivers);
            }
            else
            {
                IPlayer target = FindPlayer(args[0], player);
                if (target == null)
                {
                    return;
                }

                if (Withdraw(target.Id, amount))
                {
                    Message(player, "PlayerBalance", target.Name, Balance(target.Id));
                }
                else
                {
                    Message(player, "YouLackMoney", target.Name);
                }
            }
        }

        #endregion Withdraw Command

        #region Wipe Command

        private void CommandWipe(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission(permissionWipe))
            {
                Message(player, "NotAllowed", command);
                return;
            }

            storedData = new StoredData();
            changed = true;
            SaveData();

            Message(player, "DataWiped");
            _ = Interface.Call("OnEconomicsDataWiped", player);
        }

        #endregion Wipe Command

        #endregion Commands

        #region Helpers

        private IPlayer FindPlayer(string playerNameOrId, IPlayer player)
        {
            IPlayer[] foundPlayers = players.FindPlayers(playerNameOrId).ToArray();
            if (foundPlayers.Length > 1)
            {
                Message(player, "PlayersFound", string.Join(", ", foundPlayers.Select(p => p.Name).Take(10).ToArray()).Truncate(60));
                return null;
            }

            IPlayer target = foundPlayers.Length == 1 ? foundPlayers[0] : null;
            if (target == null)
            {
                Message(player, "NoPlayersFound", playerNameOrId);
                return null;
            }

            return target;
        }

        private void AddLocalizedCommand(string command)
        {
            foreach (string language in lang.GetLanguages(this))
            {
                foreach (KeyValuePair<string, string> message in (Dictionary<string, string>)lang.GetMessages(language, this))
                {
                    if (message.Key.Equals(command, StringComparison.Ordinal) && !string.IsNullOrEmpty(message.Value))
                    {
                        AddCovalenceCommand(message.Value, command);
                    }
                }
            }
        }

        private string GetLang(string langKey, string playerId = null, params object[] args)
        {
            return string.Format(System.Globalization.CultureInfo.InvariantCulture, lang.GetMessage(langKey, this, playerId), args);
        }

        private void Message(IPlayer player, string textOrLang, params object[] args)
        {
            if (player.IsConnected)
            {
                string message = GetLang(textOrLang, player.Id, args);
                player.Reply(message != textOrLang ? message : textOrLang);
            }
        }

        #endregion Helpers

        #region UI

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

            // Не вызываем DestroyUI, чтобы не убрать панель баланса
            // Уничтожаем только кнопку, если она существует
            _ = CuiHelper.DestroyUi(player, BALANCE_BUTTON_NAME);

            CuiElementContainer container = new();

            // Создаем фоновую круглую панель с прозрачностью
            _ = container.Add(new CuiPanel
            {
                RectTransform =
                {
                    AnchorMin = "0.86 0.0462",
                    AnchorMax = "0.8765 0.071"
                },
                Image =
                {
                    // Используем темный фон с прозрачностью для круглой кнопки
                    Color = "0.42 0.42 0.42 0.5",
                    // Используем скругленный фон
                    Sprite = "assets/content/ui/ui.background.transparent.radial.psd"
                }
            }, "Hud", BALANCE_BUTTON_NAME);

            // Добавляем кнопку над фоном для обработки клика
            string buttonName = container.Add(new CuiButton
            {
                Button =
                {
                    Command = "economics.showbalance",
                    Color = "0 0 0 0" // Полностью прозрачный цвет для кнопки
                },
                RectTransform =
                {
                    AnchorMin = "0 0",
                    AnchorMax = "1 1"
                },
                Text =
                {
                    Text = ""
                }
            }, BALANCE_BUTTON_NAME);

            // Добавляем иконку с немного меньшим размером для красивого отображения
            container.Add(new CuiElement
            {
                Parent = buttonName,
                Components =
                {
                    new CuiRawImageComponent
                    {
                        Url = BalanceIconUrl,
                        Color = "1 1 1 1"
                    },
                    new CuiRectTransformComponent
                    {
                        AnchorMin = "0.01 0.01",
                        AnchorMax = "0.9 0.9"
                    }
                }
            });

            _ = CuiHelper.AddUi(player, container);
            // Не обновляем uiElements, чтобы не перезаписать текущий активный элемент
        }

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

            // Уничтожаем только панель баланса, но не кнопку
            _ = CuiHelper.DestroyUi(player, HUD_PANEL_NAME);

            double balance = Balance(player.UserIDString);
            string formattedBalance = GetLang("BalanceHUD", player.UserIDString, balance);

            CuiElementContainer container = new();
            _ = container.Add(new CuiPanel
            {
                RectTransform = { AnchorMin = "0.802 0.0462", AnchorMax = "0.859 0.071", OffsetMin = "0 0", OffsetMax = "0 0" },
                Image = { Color = "0.42 0.42 0.42 0.5" }
            }, "Hud", HUD_PANEL_NAME);

            _ = container.Add(new CuiLabel
            {
                RectTransform = { AnchorMin = "0 0", AnchorMax = "0.77 1" },
                Text = { Text = formattedBalance, FontSize = 14, Align = TextAnchor.MiddleCenter, Color = config.HUDTextColor }
            }, HUD_PANEL_NAME);

            _ = CuiHelper.AddUi(player, container);
            uiElements[player] = HUD_PANEL_NAME;
        }

        [Command("economics.showbalance")]
        private void CommandShowBalance(IPlayer player, string command, string[] args)
        {
            if (player?.Object == null)
            {
                return;
            }

            if (player.Object is not BasePlayer basePlayer)
            {
                return;
            }

            // Проверяем, показана ли панель баланса в данный момент
            if (uiElements.TryGetValue(basePlayer, out string uiName) && uiName == HUD_PANEL_NAME)
            {
                // Если панель баланса уже показана, скрываем её
                // Уничтожаем только панель баланса, но не кнопку
        
// ... [Code preview truncated due to length. Full source in attached file] ...

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