C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core.Plugins;
using System.Collections;
using UnityEngine.Networking;
using Newtonsoft.Json.Linq;
using System.Linq;
using Oxide.Core;
using System.Globalization;
using UnityEngine;
using System;
using Rust;
using System.Text;
using System.Collections.Generic;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Libraries;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Oxide.Plugins.XDStatisticsExtensionMethods;
namespace System.Runtime.CompilerServices {
public class IsExternalInit {
}
}
namespace Oxide.Plugins.XDStatisticsExtensionMethods {
public static class ExtensionMethods {
public static List<TSource> XDToList<TSource>(this IEnumerable<TSource> source) {
List<TSource> result = new();
using IEnumerator<TSource> enumerator = source.GetEnumerator();
while (enumerator.MoveNext()) result.Add(enumerator.Current);
return result;
}
public static TSource XDLast<TSource>(this IList<TSource> source) => source[^1];
public static HashSet<TSource> XDWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
HashSet<TSource> result = new();
using IEnumerator<TSource> enumerator = source.GetEnumerator();
while (enumerator.MoveNext()) if (predicate(enumerator.Current)) result.Add(enumerator.Current);
return result;
}
}
}
/// - Исправлена проблема с засчетом ракет
/// - Исправлена проблема с NRE при сбитии вертолета
/// - Исправлена NRE при Unsubscribe
/// - Небольшой рефакторинг и улучшения кода
/// - Это лишь некоторые исправления и улучшения перед следующим важным и большим обновлением./// - Если вы нашли какие то проблемы не стесняйтесь говорить о них.namespace Oxide.Plugins
{
[Info("XDStatistics", "DezLife", "2.8.2")]
[Description("Multifunctional statistics for your server!")]
class XDStatistics : RustPlugin {
private record ItemName(string ShortName, string ENDisplayName, string RUDisplayName);
private void STCanReceiveYield(BasePlayer player, GrowableEntity entity, Item item) {
if (player == null || item == null || item.info == null) return;
if (_alowedSeedId.Contains(item.info.itemid)) {
NextTick(() => {
PlayerInfo playerStat = PlayerInfo.Find(player.userID.Get());
if (!playerStat.harvesting.HarvestingList.TryGetValue(item.info.shortname, out int currentAmount)) {
playerStat.harvesting.HarvestingList[item.info.shortname] = item.amount;
}
else {
playerStat.harvesting.HarvestingList[item.info.shortname] = currentAmount + item.amount;
}
playerStat.harvesting.AllHarvesting += item.amount;
playerStat.Score += _config.settingsScore.PlantScore;
}
);
}
}
private void OnItemCraftFinished(ItemCraftTask task, Item item, ItemCrafter crafter) {
if(_config.settingsScore.blackListedCraft.Contains(item.info.shortname)) return;
PlayerInfo playerInfo = PlayerInfo.Find(crafter.owner.userID.Get());
playerInfo.otherStat.AllCraft += item.amount;
playerInfo.Score += _config.settingsScore.craftScore;
}
private void ExplosionProgressAdd(BasePlayer player, BaseEntity entity, string shortname = "") {
string weaponName = string.IsNullOrWhiteSpace(shortname) ? string.Empty : shortname;
if (entity != null) {
if (!_prefabID2Item.TryGetValue(entity.prefabID, out weaponName)) {
_prefabNameItem.TryGetValue(entity.ShortPrefabName, out weaponName);
}
}
if (!string.IsNullOrEmpty(weaponName)) {
PlayerInfo playerstat = PlayerInfo.Find(player.userID.Get());
if (playerstat.explosion.ExplosionUsed.ContainsKey(weaponName) && !_config.settingsScore.blackListed.Contains(weaponName)) {
playerstat.explosion.ExplosionUsed[weaponName]++;
playerstat.explosion.AllExplosionUsed++;
playerstat.Score += _config.settingsScore.ExplosionScore[weaponName];
}
}
}
private void OnEntityDeath(BradleyAPC entity, HitInfo info) {
if (entity == null || info is null) return;
BasePlayer player = info.InitiatorPlayer;
if (player != null && player.userID.IsSteamId() && !player.IsNpc && entity.ToPlayer() != player) {
PlayerInfo playerstat = PlayerInfo.Find(player.userID.Get());
playerstat.pVP.BradleyKill++;
playerstat.Score += _config.settingsScore.BradleyScore;
}
}
private void OnEntityDeath(BaseAnimalNPC entity, HitInfo info) {
if (entity == null || info is null) return;
BasePlayer player = info.InitiatorPlayer;
if (player != null && player.userID.IsSteamId() && !player.IsNpc && entity.ToPlayer() != player) {
PlayerInfo playerstat = PlayerInfo.Find(player.userID.Get());
playerstat.otherStat.AnimalsKill++;
playerstat.Score += _config.settingsScore.AnimalScore;
}
}
private void WeaponProgressAdd(PlayerInfo player, HitInfo hitinfo, bool kill = false) {
if (hitinfo == null || hitinfo.WeaponPrefab == null) return;
string weaponName = null;
if (hitinfo.Weapon != null && hitinfo.Weapon.GetItem() != null && hitinfo.Weapon.GetItem().info != null) {
weaponName = hitinfo.Weapon.GetItem().info.shortname;
}
if (weaponName is null && !_prefabID2Item.TryGetValue(hitinfo.WeaponPrefab.prefabID, out weaponName) && !_prefabNameItem.TryGetValue(hitinfo.WeaponPrefab.ShortPrefabName, out weaponName)) {
return;
}
if (string.IsNullOrEmpty(weaponName)) return;
weaponName = weaponName switch {
"rifle.ak.ice" or "rifle.ak.diver" => "rifle.ak", _ => weaponName
}
;
if (!player.weapon.WeaponUsed.TryGetValue(weaponName, out PlayerInfo.Weapon.WeaponInfo weapon)) {
player.weapon.WeaponUsed[weaponName] = new PlayerInfo.Weapon.WeaponInfo {
Kills = kill ? 1 : 0, Headshots = hitinfo.isHeadshot ? 1 : 0, Shots = 1
}
;
return;
}
if (hitinfo.isHeadshot) weapon.Headshots++;
weapon.Shots++;
if (kill) weapon.Kills++;
}
private bool HasImage(string imageName, ulong imageId = 0) => (bool)ImageLibrary.Call("HasImage", imageName, imageId);
private void OnZLevelDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item, int prevAmount, int newAmount, bool isPowerTool) {
if (player == null || item == null || item.info == null) return;
ProgressAdd(player, item.info.shortname, item.amount);
}
private void OnEntityDeath(PatrolHelicopter entity, HitInfo info) {
if (entity == null || info is null) return;
BasePlayer player = info.InitiatorPlayer != null ? info.InitiatorPlayer : (entity.myAI._targetList is {
Count : > 0
}
? entity.myAI._targetList.XDLast().ply : null);
if (player != null && !player.IsNpc && entity.ToPlayer() != player) {
PlayerInfo playerstat = PlayerInfo.Find(player.userID.Get());
playerstat.pVP.HeliKill++;
playerstat.Score += _config.settingsScore.HeliScore;
}
}
public static StringBuilder sb;
private class Configuration {
public class Settings {
[JsonProperty(RU ? "Чат-команды для открытия статистики" : "Chat commands for opening statistics", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> chatCommandOpenStat = new List<string> {
"stat", "top"
}
;
[JsonProperty(RU ? "Консольная команда для открытия статистики" : "Console command to open statistics")]
public string consoleCommandOpenStat = "stat";
[JsonProperty(RU ? "Отправлять в чат сообщения с топ-5 игроками по разным категориям" : "Send chat messages with top 5 players in various categories")]
public bool chatSendTop = true;
[JsonProperty(RU ? "Как часто (в секундах) отправлять сообщение?" : "How often (in seconds) should the message be sent?")]
public int chatSendTopTime = 600;
[JsonProperty(RU ? "Включить возможность сбросить свою статистику? (требуется XDStatistics.reset)" : "Enable the ability to reset your stats? (requires XDStatistics.reset)")]
public bool dropStatUse = false;
[JsonProperty(RU ? "Включить возможность скрыть свою статистику от других пользователей? (требуется XDStatistics.availability)" : "Enable the ability to hide your statistics from other users? (requires XDStatistics.availability)")]
public bool availabilityUse = true;
[JsonProperty(RU ? "Очищать данные при вайпе" : "Clear data when wiped")]
public bool wipeData = true;
[JsonProperty(RU ? "Как часто (в минутах) будут сохраняться данные?" : "How often (in minutes) will data be saved?")]
public int dataSaveTime = 30;
[JsonProperty(RU ? "Учитывать убийства NPC для выбора любимого оружия?" : "Consider NPC kills for determining a favorite weapon?")]
public bool npsDeathUse = false;
[JsonProperty(RU ? "У вас сервер в режиме PVE?" : "Is your server in PVE mode?")]
public bool pveServerMode = false;
[JsonProperty(RU ? "Список игроков (SteamID), которые не будут включены в статистику" : "List of players (SteamID) who will not be included in the statistics", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ulong> ignoreList = new List<ulong>();
[JsonProperty(RU ? "Используйте хуки коллекции из плагина SkillTree" : "Use the gathering hooks from SkillTree")]
public bool UseSkillTreeHooks;
[JsonProperty(RU ? "Используйте хуки коллекции из плагина ZLevels Remastered" : "Use the gathering hooks from ZLevels Remastered")]
public bool UseZLevelsRemasteredHooks;
}
[JsonProperty(RU ? "Настройки Discord" : "Discord Settings")]
public DiscordMessage discordMessage = new DiscordMessage();
[JsonProperty(RU ? "Настройка начисления очков" : "Points Allocation Settings")]
public SettingsScore settingsScore = new SettingsScore();
public class SettingsInterface {
[JsonProperty(RU ? "Цвет плашки заднего фона в топ 10 за 3 место" : "Background color in the top 10 for 3rd place")]
public string ColorTop3 = "0.80392 0.498033900 0.1960784 0.49";
[JsonProperty(RU ? "Цвет плашки заднего фона в топ 10 за 2 место" : "Background color in the top 10 for 2nd place")]
public string ColorTop2 = "0.7529412 0.7529412 0.7529412 0.49";
[JsonProperty(RU ? "Использовать свой задний фон? (указанный снизу)" : "Use your own background? (indicated at the bottom)")]
public bool UsebackgroundImageUrl = false;
[JsonProperty(RU ? "Цвет плашки заднего фона в топ 10 за 1 место" : "Background color in the top 10 for 1st place")]
public string ColorTop1 = "1 0.8431373 0 0.49";
[JsonProperty(RU ? "Ссылка на свой задний фон (Если нужно)" : "Link to your background (If necessary)")]
public string backgroundImageUrl = "";
}
[JsonProperty(RU ? "Основные настройки плагина" : "Basic Plugin Settings")]
public Settings settings = new Settings();
public class SettingsPrize {
[JsonProperty(RU ? "Использовать выдачу награды после вайпа?" : "Use award distribution after the wipe?")]
public bool prizeUse = false;
[JsonProperty(RU ? "Награда в категории SCORE" : "Award in the SCORE category")]
public List<Prize> prizeScore = new List<Prize>();
[JsonProperty(RU ? "Награда в категории Киллер" : "Award in the Killer category")]
public List<Prize> prizeKiller = new List<Prize>();
[JsonProperty(RU ? "Награда в категории Фармила" : "Award in the Gathering category")]
public List<Prize> prizeFarm = new List<Prize>();
[JsonProperty(RU ? "Награда в категории рейдер" : "Award in the Raider category")]
public List<Prize> prizeRaid = new List<Prize>();
[JsonProperty(RU ? "Награда в категории Большой онлайн" : "Award in the Big Online category")]
public List<Prize> prizeTime = new List<Prize>();
[JsonProperty(RU ? "Награда в категории Убийца НПС" : "Award in the NPC Killer category")]
public List<Prize> prizeNPCKiller = new List<Prize>();
[JsonProperty(RU ? "Награда в категории убийца животных" : "Award in the Animal Killer category")]
public List<Prize> prizeAnimalKiller = new List<Prize>();
[JsonProperty(RU ? "[GameStores] ID магазина" : "[GameStores] Shop ID")]
public string ShopID = "";
[JsonProperty(RU ? "[GameStores] ID сервера" : "[GameStores] Server ID")]
public string ServerID = "";
[JsonProperty(RU ? "[GameStores] Секретный ключ" : "[GameStores] Secret Key")]
public string SecretKey = "";
internal class Prize {
[JsonProperty(RU ? "Использовать команды как награду?" : "Use commands as a prize?")]
public bool commandPrizeUse = true;
[JsonProperty(RU ? "За какое место вручать награду? (от 1 до 3).Если данная категория наград не требуется, удалите все связанные награды." : "Which ranking to award? (from 1 to 3).If you don't need to award this category, remove all related rewards.")]
public int top = 1;
[JsonProperty(RU ? "Использовать магазин GameStore для выдачи награды?" : "Use GameStore for prize distribution?")]
public bool gamestorePrizeUse = false;
[JsonProperty(RU ? "Использовать магазин MoscowOVH для выдачи награды?" : "Use MoscowOVH store for prize distribution?")]
public bool ovhPrizeUse = false;
[JsonProperty(RU ? "Использовать [IQEconomic, Economics или ServerRewards] для выдачи награды" : "Use [IQEconomic, Economics, or ServerRewards] to distribute rewards?")]
public bool economicPrizeUse = false;
[JsonProperty(RU ? "Команды для приза" : "Command for the prize")]
public List<string> commandPrizeList = new List<string>();
[JsonProperty(RU ? "[GameStores] Сообщение для истории покупок в магазине" : "[GameStores] Store purchase history message")]
public string balancePlusMess = "За топ 1!!!";
[JsonProperty(RU ? "[GameStores или MoscowOVH] Количество начисляемых денег на баланс" : "[GameStores or MoscowOVH] Amount of money to be credited")]
public int balancePlus = 30;
[JsonProperty(RU ? "[IQEconomic, Economics или ServerRewards] Количество начисляемых денег на баланс" : "[IQEconomic, Economics, or ServerRewards] Amount of money to credit to the balance")]
public int balanceEconomicsPlus = 100;
public void GiftPrizePlayer(string player) {
if (commandPrizeUse) {
foreach (string cmd in commandPrizeList) Instance.Server.Command(cmd.Replace("%STEAMID%", player));
}
if (gamestorePrizeUse && Instance?.GameStoresRUST) {
string uri = $"https://gamestores.ru/api?shop_id={Instance._config.settingsPrize.ShopID}&secret={Instance._config.settingsPrize.SecretKey}&server={Instance._config.settingsPrize.ServerID}&action=moneys&type=plus&steam_id={player}&amount={balancePlus}&mess={balancePlusMess}";
Instance.webrequest.Enqueue(uri , "", (code, response) => {
switch (code) {
case 0 : {
Instance.PrintError("Api does not responded to a request");
break;
}
case 200 : {
break;
}
case 404 : {
Instance.PrintError($"Please check your configuration! {code}");
break;
}
}
}
, Instance);
}
if (ovhPrizeUse) {
if (Instance?.RustStore) {
Instance.RustStore.CallHook("APIChangeUserBalance", ulong.Parse(player), balancePlus, new Action<string>(result => {
if (result == "SUCCESS") return;
Interface.Oxide.LogDebug($"Баланс игрока {ulong.Parse(player)} не был изменен, ошибка: {result}");
}
));
}
}
if (economicPrizeUse) {
if (Instance?.Economics) {
Instance.Economics.Call("Deposit", ulong.Parse(player), (double)balanceEconomicsPlus);
}
else if (Instance?.IQEconomic) {
Instance.IQEconomic.Call("API_SET_BALANCE", ulong.Parse(player), balanceEconomicsPlus);
}
else if (Instance?.ServerRewards) {
Instance.ServerRewards.Call("AddPoints", ulong.Parse(player), balanceEconomicsPlus);
}
}
}
}
}
[JsonProperty(RU ? "Настройки наград для лидеров по каждой категории" : "Top Player Rewards Settings by Category")]
public SettingsPrize settingsPrize = new SettingsPrize();
public class DiscordMessage {
[JsonProperty(RU ? "Отправлять в Discord топ-5 лучших игроков по разным категориям?" : "Send top 5 best players in various categories to Discord?")]
public bool discordTopFiveUse = false;
[JsonProperty(RU ? "Как часто (в секундах) отправлять сообщение?" : "How often (in seconds) should the message be sent?")]
public int discordSendTopTime = 600;
[JsonProperty(RU ? "WebHook Discord" : "Discord WebHook")]
public string weebHook = string.Empty;
[JsonProperty(RU ? "Цвет линии в сообщении (или несколько цветов)" : "The color(s) of the line in the message", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public int[] colorLines = new int[] {
53380, 9359868, 11253955
}
;
[JsonProperty(RU ? "Дополнительный текст к сообщению" : "Additional text for the message")]
public string message = string.Empty;
}
[JsonProperty(RU ? "Настройки интерфейса" : "Interface Settings")]
public SettingsInterface settingsInterface = new SettingsInterface();
public class SettingsScore {
[JsonProperty(RU ? "Очки за крафт" : "Points for crafting")]
public float craftScore = 1;
[JsonProperty(RU ? "Очки за разбивание бочек" : "Points for breaking barrels")]
public float barrelScore = 1;
[JsonProperty(RU ? "Очки за установку строительных блоков" : "Points for placing building blocks")]
public float BuildingScore = 1;
[JsonProperty(RU ? "Очки за использование взрывчатых предметов" : "Points for using explosive items")]
public Dictionary<string, float> ExplosionScore = new Dictionary<string, float>();
[JsonProperty(RU ? "Очки за добычу ресурсов" : "Points for gathering resources")]
public Dictionary<string, float> GatherScore = new Dictionary<string, float>();
[JsonProperty(RU ? "Очки за найденный скрап" : "Points for collected scrap")]
public float ScrapScore = 0.5f;
[JsonProperty(RU ? "Очки за сбор урожая (с плантации)" : "Points for harvesting (from plantation)")]
public float PlantScore = 0.2f;
[JsonProperty(RU ? "Очки за убийство животных" : "Points for killing animals")]
public float AnimalScore = 1;
[JsonProperty(RU ? "Очки за сбитие вертолета" : "Points for shooting down a helicopter")]
public float HeliScore = 5;
[JsonProperty(RU ? "Очки за взрыв танка" : "Points for blowing up a tank")]
public float BradleyScore = 5;
[JsonProperty(RU ? "Очки за убийство NPC" : "Points for killing NPCs")]
public float NpcScore = 5;
[JsonProperty(RU ? "Очки за убийство игроков" : "Points for killing players")]
public float PlayerScore = 10;
[JsonProperty(RU ? "Очки за проведенное время на сервере (за каждую минуту)" : "Points for time spent on the server (per minute)")]
public float TimeScore = 0.2f;
[JsonProperty(RU ? "Сколько очков отнять за самоубийство?" : "How many points to deduct for suicide?")]
public float SuicideScore = 2;
[JsonProperty(RU ? "Сколько очков отнять за смерть?" : "How many points to deduct for death?")]
public float DeathScore = 1;
[JsonProperty(RU ? "Черный список ресурсов и взрывчатых предметов" : "Blacklist of resources and explosive items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> blackListed = new List<string> {
"ammo.rifle.explosive"
}
;
[JsonProperty(RU ? "Черный список предметов для крафта" : "Blacklist of crafting items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> blackListedCraft = new List<string> {
"photo", "note"
}
;
}
}
private bool IsFriends(ulong userID, ulong targetID) {
if (Friends is not null) return Friends.Call("HasFriend", userID, targetID) is true;
return RelationshipManager.ServerInstance.playerToTeam.TryGetValue(userID, out var team) && team.members.Contains(targetID);
}
private void OnPlayerConnected(BasePlayer player) {
if (!_ignoreReservedPlayer.ContainsKey(player.userID.Get())) {
PlayerInfo dataPlayer = PlayerInfo.Find(player.userID.Get());
dataPlayer.Name = CleanString(player.displayName);
if (dataPlayer.playedTime.DayNumber != DateTime.Now.ToShortDateString()) {
dataPlayer.playedTime.PlayedToday = 0;
dataPlayer.playedTime.DayNumber = DateTime.Now.ToShortDateString();
}
}
if (_prizePlayerData.ContainsKey(player.userID.Get())) SendMsgRewardWipe(player);
SteamAvatarAdd(player.UserIDString);
}
private void CategoryStatUser(BasePlayer player, ulong target = 0, int cat = 0) {
var container = new CuiElementContainer();
PlayerInfo statInfo = PlayerInfo.Find(target == 0 ? player.userID.Get() : target);
Dictionary<string, int> list = GetCategory(statInfo, cat);
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0.5803922 0.572549 0.6117647 0.4313726"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = $"151.69 {181.046 - ((list.Count - 1) * 50.729)}", OffsetMax = $"153.21 225.49"
}
}
, UI_USER_STAT_INFO, "STAT_LINE");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0.5803922 0.572549 0.6117647 1"
}
, RectTransform = {
AnchorMin = "0.5 1", AnchorMax = "0.5 1", OffsetMin = $"-0.761 {-23.343 - ((list.Count - 1) * 30.729)}", OffsetMax = "0.761 0.17"
}
}
, "STAT_LINE", "STAT_LINE_CHILD");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.5 1", AnchorMax = "0.5 1", OffsetMin = "-146.988 -71.4", OffsetMax = "146.388 -53.16"
}
}
, UI_USER_STAT_INFO, "MENU_USER_STAT");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "0.312 -9.12", OffsetMax = "84.704 9.121"
}
, Button = {
Command = $"UI_HandlerStat changeCategory {target} 0", Color = "0 0 0 0"
}
, Text = {
Text = GetLang("STAT_UI_CATEGORY_GATHER", player.UserIDString), Font = "robotocondensed-regular.ttf", FontSize = 10, Align = TextAnchor.MiddleCenter,
}
}
, "MENU_USER_STAT", "Panel_5655");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = cat == 0 ? "0.2988604 0.6886792 0.120194 0.6431373" : "0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.5 0", AnchorMax = "0.5 0", OffsetMin = "-42.347 0", OffsetMax = "42.196 1.871"
}
}
, "Panel_5655", "Panel_8052");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-61.983 -9.121", OffsetMax = "31.232 9.12"
}
, Button = {
Command = $"UI_HandlerStat changeCategory {target} 1", Color = "0 0 0 0"
}
, Text = {
Text = GetLang("STAT_UI_CATEGORY_EXPLOSED", player.UserIDString), Font = "robotocondensed-regular.ttf", FontSize = 10, Align = TextAnchor.MiddleCenter,
}
}
, "MENU_USER_STAT", "Panel_56551");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = cat == 1 ? "0.2988604 0.6886792 0.120194 0.6431373" : "0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.5 0", AnchorMax = "0.5 0", OffsetMin = "-46.608 0", OffsetMax = "46.608 1.871"
}
}
, "Panel_56551", "Panel_8052");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-115.459 -9.12", OffsetMax = "0.001 9.121"
}
, Button = {
Command = $"UI_HandlerStat changeCategory {target} 2", Color = "0 0 0 0"
}
, Text = {
Text = GetLang("STAT_UI_CATEGORY_PLANT", player.UserIDString), Font = "robotocondensed-regular.ttf", FontSize = 10, Align = TextAnchor.MiddleCenter,
}
}
, "MENU_USER_STAT", "Panel_56553");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = cat == 2 ? "0.2988604 0.6886792 0.120194 0.6431373" : "0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.5 0", AnchorMax = "0.5 0", OffsetMin = "-57.73 0", OffsetMax = "57.73 1.871"
}
}
, "Panel_56553", "Panel_8052");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0 0 0 0"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-146.991 -124.121", OffsetMax = "146.389 226.031"
}
}
, "USER_STAT_INFO", "MAIN_LIST_STAT_USER");
int y = 0;
string userLang = lang.GetLanguage(player.UserIDString);
foreach (KeyValuePair<string, int> item in list) {
if (_config.settingsScore.blackListed.Contains(item.Key)) continue;
float fade = 0.15f * y;
string itemName;
if (_itemName.ContainsKey(item.Key)) itemName = userLang == "ru" ? _itemName[item.Key].Ru : _itemName[item.Key].En;
else {
itemName = "";
ItemDefinition itemDefinition = ItemManager.FindItemDefinition(item.Key);
if (itemDefinition != null && itemDefinition.displayName is {
english : not null
}
) {
itemName = itemDefinition.displayName.english;
}
}
container.Add(new CuiElement {
Name = "STAT_USER_LINE", Parent = "MAIN_LIST_STAT_USER", Components = {
new CuiRawImageComponent {
Color = "1 1 1 0.03", Png = item.Key == "all" ? _imageUI.GetImage("10") : _imageUI.GetImage("9"), FadeIn = fade
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 1", AnchorMax = "0.5 1", OffsetMin = $"-146.118 {-44.977 - (y * 50.729)}", OffsetMax = $"146.692 {-0.765 - (y * 50.729)}"
}
}
}
);
string name = cat == 0 ? item.Value.ToString("0,0", CultureInfo.InvariantCulture) : item.Value.ToString();
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "26.03 -10.534", OffsetMax = "126.03 12.574"
}
, Text = {
Text = name, Font = "robotocondensed-regular.ttf", FontSize = 10, Align = TextAnchor.MiddleRight, Color = "0.8538514 0.8491456 0.8867924 1", FadeIn = fade
}
}
, "STAT_USER_LINE", "STAT_USER_AMOUNT");
if (item.Key == "all") {
string langGet = cat switch {
0 => "STAT_USER_TOTAL_GATHERED", 1 => "STAT_USER_TOTAL_EXPLODED", _ => "STAT_USER_TOTAL_GROWED"
}
;
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-128 -10.534", OffsetMax = "50 12.574"
}
, Text = {
Text = GetLang(langGet, player.UserIDString), Font = "robotocondensed-regular.ttf", FontSize = 11, Align = TextAnchor.MiddleLeft, Color = "1 1 1 1", FadeIn = fade
}
}
, "STAT_USER_LINE", "ALL_TOTAL");
}
else {
container.Add(new CuiElement {
Name = "IMAGE_ITEM", Parent = "STAT_USER_LINE", Components = {
new CuiImageComponent {
ItemId = ItemManager.FindItemDefinition(item.Key).itemid, FadeIn = fade
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-128 -17.5", OffsetMax = "-93 17.5"
}
}
}
);
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-73.17 -10.534", OffsetMax = "50 12.574"
}
, Text = {
Text = itemName, Font = "robotocondensed-regular.ttf", FontSize = 10, Align = TextAnchor.MiddleLeft, Color = "0.8538514 0.8491456 0.8867924 1" , FadeIn = fade
}
}
, "STAT_USER_LINE");
}
y++;
}
CuiHelper.DestroyUi(player, "MENU_USER_STAT");
CuiHelper.DestroyUi(player, "MAIN_LIST_STAT_USER");
CuiHelper.DestroyUi(player, "STAT_LINE");
CuiHelper.AddUi(player, container);
}
private void SteamAvatarAdd(string userid) {
if (ImageLibrary is null || HasImage(userid)) return;
webrequest.Enqueue($"https://steamcommunity.com/profiles/{userid}?xml=1", null, (code, response) => {
if (code != 200 || response is null) return;
string avatarUrl = _avatarRegex.Match(response).Groups[1].ToString();
if (!string.IsNullOrEmpty(avatarUrl)) {
AddImage(avatarUrl, userid);
}
}
, this);
}
public const string UI_TOP_TEN_USER = "TOP_TEN_USER";
[ConsoleCommand("stat.ignore")]
private void CmdIgnorePlayer(ConsoleSystem.Arg arg) {
if (arg == null) return;
BasePlayer player = arg.Player();
if (player != null && !permission.UserHasPermission(player.UserIDString, PermAdmin)) {
PrintToConsole(player, GetLang("STAT_CMD_1", player.UserIDString));
return;
}
if (arg.Args == null || arg.Args.Count() == 0) {
arg.ReplyWith(GetLang("STAT_CMD_2"));
return;
}
ulong steamid;
if (!ulong.TryParse(arg.Args[1], out steamid)) {
List<KeyValuePair<ulong, PlayerInfo>> players = FindPlayers(arg.Args[1].ToLower());
if (players.Count == 0) {
arg.ReplyWith(GetLang("STAT_CMD_3"));
return;
}
if (players.Count > 1) {
string playersMore = "";
foreach (KeyValuePair<ulong, PlayerInfo> plr in players) playersMore = playersMore + "\n" + plr.Value.Name + " - " + plr.Key;
arg.ReplyWith(GetLang("STAT_CMD_4", null, playersMore));
return;
}
steamid = players[0].Key;
}
string name = "";
for (int ii = 1; ii < arg.Args.Count();
ii++) name += arg.Args[ii] + " ";
name = name.Trim(' ');
if (string.IsNullOrEmpty(name)) {
arg.ReplyWith(GetLang("STAT_CMD_2"));
return;
}
if (!_players.ContainsKey(steamid) && !_ignoreReservedPlayer.ContainsKey(steamid)) {
arg.ReplyWith(GetLang("STAT_CMD_5"));
return;
}
PlayerInfo playerInfo = _players.TryGetValue(steamid, out PlayerInfo player1) ? player1 : _ignoreReservedPlayer[steamid];
switch (arg.Args[0]) {
case "add" : case "a" : {
if (_ignoreReservedPlayer.ContainsKey(steamid)) {
arg.ReplyWith(GetLang("STAT_CMD_6", null, playerInfo.Name));
break;
}
_ignoreReservedPlayer.Add(steamid, playerInfo);
_players.Remove(steamid);
arg.ReplyWith(GetLang("STAT_CMD_7", null, playerInfo.Name));
break;
}
case "r" : case "remove" : {
if (!_ignoreReservedPlayer.ContainsKey(steamid)) {
arg.ReplyWith(GetLang("STAT_CMD_8", null, playerInfo.Name));
break;
}
PlayerInfo info = _ignoreReservedPlayer[steamid];
_players.Add(steamid, info);
_ignoreReservedPlayer.Remove(steamid);
arg.ReplyWith(GetLang("STAT_CMD_9", null, playerInfo.Name));
break;
}
}
}
private const string PermAvailability = "XDStatistics.availability";
private Dictionary<string, int> API_GetGathered(ulong id) => PlayerInfo.Find(id)?.gather.GatheredTotal;
private int GetTopScore(ulong userid) {
if (_config.settings.ignoreList.Contains(userid)) return -1;
int top = 1;
float userScore = _players[userid].Score;
foreach (KeyValuePair<ulong, PlayerInfo> player in _players) {
if (!_config.settings.ignoreList.Contains(player.Key) && player.Value.Score > userScore) {
top++;
}
}
return top;
}
private void OnPluginLoaded(Plugin name) {
if (IsObjectNull(Instance) || IsObjectNull(name) || name == Instance) return;
if (name.ToString() == "ZLevelsRemastered" || name.ToString() == "SkillTree") {
foreach (string hook in _gatherHooks) Unsubscribe(hook);
}
NextTick(ToggleGatherHooks);
}
private void DiscordPrintTopFive() {
(string, string) data = GetRandomTopPlayer();
SendDiscordMessage(CleanUpString(lang.GetMessage(data.Item1, this)), new List<string> {
data.Item2
}
, false);
timer.Once(_config.discordMessage.discordSendTopTime, DiscordPrintTopFive);
}
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["STAT_TOP_FIVE_KILL"]
= "Top 5 <color=#4286f4>Killers</color>\n{0}</size>", ["STAT_TOP_FIVE_KILL_NPC"] = "Top 5 <color=#4286f4>NPC killers</color>\n{0}</size>", ["STAT_TOP_FIVE_FARM"] = "Top 5 <color=#4286f4>Farmers</color>\n{0}</size>", ["STAT_TOP_FIVE_EXPLOSION"] = "Top 5 <color=#4286f4>Explosions</color>\n{0}</size>", ["STAT_TOP_FIVE_TIMEPLAYED"] = "Top 5 <color=#4286f4>Most Time Played</color>\n{0}</size>", ["STAT_TOP_FIVE_BUILDINGS"] = "Top 5 <color=#4286f4>Builders</color>\n{0}</size>", ["STAT_TOP_FIVE_SCORE"] = "Top 5 <color=#4286f4>Most points</color>\n{0}</size>", ["STAT_TOP_FIVE_FERMER"] = "Top 5 <color=#4286f4>Farmers</color>\n{0}</size>", ["STAT_USER_TOTAL_GATHERED"] = "Total Gathered:", ["STAT_USER_TOTAL_EXPLODED"] = "Total Explosions:", ["STAT_USER_TOTAL_GROWED"] = "Total Farmed:", ["STAT_UI_MY_STAT"] = "My Statistics", ["STAT_UI_TOP_TEN"] = "Top 10 Players", ["STAT_UI_SEARCH"] = "Search", ["STAT_UI_INFO"] = "Player Information {0}", ["STAT_UI_ACTIVITY"] = "Activity", ["STAT_UI_ACTIVITY_TODAY"] = "Today: {0}", ["STAT_UI_ACTIVITY_TOTAL"] = "All Time: {0}", ["STAT_UI_SETTINGS"] = "Settings", ["STAT_UI_PLACE_TOP"] = "Place On Top: {0}", ["STAT_UI_SCORE"] = "Score: {0}", ["STAT_UI_PVP"] = "PvP Statistics", ["STAT_UI_FAVORITE_WEAPON"] = "Favorite Weapon", ["STAT_UI_PVP_KILLS"] = "Kills", ["STAT_UI_PVP_KILLS_NPC"] = "Kills NPC", ["STAT_UI_PVP_DEATH"] = "Deaths", ["STAT_UI_PVP_KDR"] = "K/D", ["STAT_UI_FAVORITE_WEAPON_KILLS"] = "Kills: {0}\nHits: {1}", ["STAT_UI_FAVORITE_WEAPON_NOT_DATA"] = "Data is still being calculated..", ["STAT_UI_OTHER_STAT"] = "Other Statistics", ["STAT_UI_HIDE_STAT"] = "Public Profile", ["STAT_UI_CONFIRM"] = "Are You Sure?", ["STAT_UI_CONFIRM_YES"] = "Yes", ["STAT_UI_CONFIRM_NO"] = "No", ["STAT_UI_RESET_STAT"] = "Reset Statistics", ["STAT_UI_CRATE_OPEN"] = "Crates Opened: {0}", ["STAT_UI_BARREL_KILL"] = "Barrels Destroyed: {0}", ["STAT_UI_ANIMAL_KILL"] = "Animal Kills: {0}", ["STAT_UI_HELI_KILL"] = "Helicopter Kills: {0}", ["STAT_UI_BRADLEY_KILL"] = "Bradley Kills: {0}", ["STAT_UI_NPC_KILL"] = "NPC Kills: {0}", ["STAT_UI_BTN_MORE"] = "Show More", ["STAT_UI_CATEGORY_GATHER"] = "Gather", ["STAT_UI_CATEGORY_EXPLOSED"] = "Explosions", ["STAT_UI_CATEGORY_PLANT"] = "Farming", ["STAT_UI_CATEGORY_TOP_KILLER"] = "Top 10 Killers", ["STAT_UI_CATEGORY_TOP_KILLER_ANIMALS"] = "Top 10 Animal Killers", ["STAT_UI_CATEGORY_TOP_NPCKILLER"] = "Top 10 NPC Killers", ["STAT_UI_CATEGORY_TOP_TIME"] = "Top 10 Most Time Played", ["STAT_UI_CATEGORY_TOP_GATHER"] = "Top 10 Gatherers", ["STAT_UI_CATEGORY_TOP_SCORE"] = "Top 10 Most Score", ["STAT_UI_CATEGORY_TOP_EXPLOSED"] = "Top 10 Explosions", ["STAT_PRINT_WIPE"] = "Wipe Detected.Data was successfully cleared!", ["STAT_CMD_1"] = "No Permission!!", ["STAT_CMD_2"] = "Usage: stat.ignore <add/remove> <Steam ID|Name>", ["STAT_CMD_3"] = "The specified playername could not be found.Please use their SteamID.", ["STAT_CMD_4"] = "Found several players with similar names: {0}", ["STAT_CMD_5"] = "Player not found!", ["STAT_CMD_6"] = "Player {0} is already ignored", ["STAT_CMD_7"] = "You have successfully added a player {0} to the ignore list", ["STAT_CMD_8"] = "The player {0} is not in the ignore list", ["STAT_CMD_9"] = "You have successfully removed the player {0} from the ignore list", ["STAT_CMD_10"] = "Player {0} successfully credited {1} score", ["STAT_CMD_11"] = "Player {0} successfully removed {1} score", ["STAT_COMMAND_SYNTAX_ERROR"] = "Incorrect syntax! Use: {0}", ["STAT_INVALID_PLAYER_ID_INPUT"] = "Invalid input! Please enter a valid player ID.", ["STAT_NOT_A_STEAM_ID"] = "The entered ID is not a SteamID.Please check and try again.", ["STAT_PLAYER_NOT_FOUND_BY_STEAMID"] = "Player with the specified Steam ID not found.", ["STAT_ADMIN_HIDE_STAT"] = "You've been added to the ignore list.You will not have access to the statistics.If this is an error, Please contact the Administrator!", ["STAT_TOP_PLAYER_WIPE_SCORE"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>HIGHEST SCORE</color>\nYou received a well deserved Reward!", ["STAT_TOP_PLAYER_WIPE_TIME"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>MOST TIME PLAYED</color>\nYou received a well deserved Reward!", ["STAT_TOP_PLAYER_WIPE_EXP"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>MOST EXPLOSIONS</color>\nYou received a well deserved Reward!", ["STAT_TOP_PLAYER_WIPE_FARM"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>MOST CROPS FARMED</color>\nYou received a well deserved Reward!", ["STAT_TOP_PLAYER_WIPE_KILL"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>MOST KILLS</color>\nYou received a well deserved Reward!", ["STAT_TOP_PLAYER_WIPE_KILL_NPC"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>NPC Killer</color>\nYou received a well deserved Reward!", ["STAT_TOP_PLAYER_WIPE_KILL_ANIMAL"] = "Congratulations!\nYou successfully held the {0} position in the previous wipe in the category <color=#4286f4>ANIMAL Killer</color>\nYou received a well deserved Reward!", ["STAT_TOP_VK_SCORE"] = "Топ {0} игрока по очкам\n {1}", ["STAT_TOP_VK_KILLER"] = "Топ {0} игрока по убийствам\n {1}", ["STAT_TOP_VK_TIME"] = "Топ {0} игрока по онлайну\n {1}", ["STAT_TOP_VK_FARM"] = "Топ {0} игрока по фарму\n {1}", ["STAT_TOP_VK_RAID"] = "Топ {0} игрока по рейдам\n {1}", ["STAT_TOP_VK_KILLER_NPC"] = "Топ {0} игрока по убийствам NPC\n {1}", ["STAT_TOP_VK_KILLER_ANIMAL"] = "Топ {0} игрока по убийствам животных\n {1}",
}
, this);
lang.RegisterMessages(new Dictionary<string, string> {
["STAT_TOP_FIVE_KILL"]
= "Топ 5 <color=#4286f4>киллеры</color>\n{0}</size>", ["STAT_TOP_FIVE_KILL_NPC"] = "Топ 5 <color=#4286f4>убийцы NPC</color>\n{0}</size>", ["STAT_TOP_FIVE_FARM"] = "Топ 5 <color=#4286f4>фармеры</color>\n{0}</size>", ["STAT_TOP_FIVE_EXPLOSION"] = "Топ 5 <color=#4286f4>рейдеры</color>\n{0}</size>", ["STAT_TOP_FIVE_TIMEPLAYED"] = "Топ 5 <color=#4286f4>долгожителей</color>\n{0}</size>", ["STAT_TOP_FIVE_BUILDINGS"] = "Топ 5 <color=#4286f4>строители</color>\n{0}</size>", ["STAT_TOP_FIVE_SCORE"] = "Топ 5 по <color=#4286f4>очкам</color>\n{0}</size>", ["STAT_TOP_FIVE_FERMER"] = "Топ 5 <color=#4286f4>фермеров</color>\n{0}</size>", ["STAT_USER_TOTAL_GATHERED"] = "Всего добыто:", ["STAT_USER_TOTAL_EXPLODED"] = "Всего взорвано:", ["STAT_USER_TOTAL_GROWED"] = "Всего выращено:", ["STAT_UI_MY_STAT"] = "Моя Статистика", ["STAT_UI_TOP_TEN"] = "Топ 10 игроков", ["STAT_UI_SEARCH"] = "Поиск", ["STAT_UI_INFO"] = "Информация о профиле {0}", ["STAT_UI_ACTIVITY"] = "Активность", ["STAT_UI_ACTIVITY_TODAY"] = "Сегодня: {0}", ["STAT_UI_ACTIVITY_TOTAL"] = "За все время: {0}", ["STAT_UI_SETTINGS"] = "Настройки", ["STAT_UI_PLACE_TOP"] = "Место в топе: {0}", ["STAT_UI_SCORE"] = "SCORE: {0}", ["STAT_UI_PVP"] = "PVP статистика", ["STAT_UI_FAVORITE_WEAPON"] = "Фаворитное оружие", ["STAT_UI_PVP_KILLS"] = "Убийств", ["STAT_UI_PVP_KILLS_NPC"] = "Убийств NPC", ["STAT_UI_PVP_DEATH"] = "Смертей", ["STAT_UI_PVP_KDR"] = "K/D", ["STAT_UI_FAVORITE_WEAPON_KILLS"] = "Убийств: {0}\nПопаданий: {1}", ["STAT_UI_FAVORITE_WEAPON_NOT_DATA"] = "Данные еще собираются...", ["STAT_UI_OTHER_STAT"] = "Другая статистика", ["STAT_UI_HIDE_STAT"] = "Общедоступный профиль", ["STAT_UI_CONFIRM"] = "Вы уверены ?", ["STAT_UI_CONFIRM_YES"] = "Да", ["STAT_UI_CONFIRM_NO"] = "Нет", ["STAT_UI_RESET_STAT"] = "Обнулить статистику", ["STAT_UI_CRATE_OPEN"] = "Открыто ящиков: {0}", ["STAT_UI_BARREL_KILL"] = "Разбито бочек: {0}", ["STAT_UI_ANIMAL_KILL"] = "Убито животных: {0}", ["STAT_UI_H
// ... [Code preview truncated due to length. Full source in attached file] ...