C#:
// #define TESTING
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using ConVar;
using Facepunch;
using Facepunch.Math;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins.ClansExtensionMethods;
using UnityEngine;
using UnityEngine.UI;
using Debug = UnityEngine.Debug;
using Pool = Facepunch.Pool;
using Random = UnityEngine.Random;
#if TESTING
using System.Diagnostics;
#endif
#if CARBON
using Carbon.Base;
using Carbon.Modules;
#endif
namespace Oxide.Plugins {
[Info("Clans", "Mevent", "1.1.53")]
public class Clans : RustPlugin {
#region Fields
[PluginReference]
private Plugin ImageLibrary = null, Skinner = null, ArenaTournament = null, BetterChat = null, IQChat = null, ZoneManager = null, PlayTimeRewards = null, PlayerDatabase = null, Notify = null, UINotify = null;
private const bool LangRu = false;
private static Clans _instance;
#if CARBON
private ImageDatabaseModule imageDatabase;
#endif
private const string Layer = "UI.Clans", ModalLayer = "UI.Clans.Modal", PermAdmin = "clans.admin", COLORED_LABEL = "<color={0}>{1}</color>";
private Coroutine _actionConvert, _initTopHandle, _topHandle;
private bool _enabledSkins, _enabledImageLibrary;
private Regex _tagFilter, _hexFilter = new("^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$");
private readonly List<ItemDefinition> _defaultItems = new();
private HashSet<ulong> _lootedEntities = new();
private readonly Dictionary<ulong, ulong> _looters = new();
private Dictionary<ulong, string> _playerToClan = new();
private int _lastPlayerTop;
private readonly HashSet<ulong> _openedUI = new();
#region Pages
private const int ABOUT_CLAN = 0, MEMBERS_LIST = 1, CLANS_TOP = 2, PLAYERS_TOP = 3, GATHER_RATES = 4, SKINS_PAGE = 6, PLAYERS_LIST = 5, ALIANCES_LIST = 7;
#endregion
#endregion
#region Config
private static Configuration _config;
private class Configuration {
[JsonProperty(PropertyName = LangRu ? "Работать с Notify?" : "Work with Notify?")]
public bool UseNotify = true;
[JsonProperty(PropertyName = LangRu ? "Настройки аватара" : "Avatar Settings")]
public AvatarSettings Avatar = new() {
DefaultAvatar = "https://i.ibb.co/q97QG6c/image.png", CanOwner = true, CanModerator = false, CanMember = false, PermissionToChange = string.Empty, SteamAPIKey = string.Empty
}
;
[JsonProperty(PropertyName = LangRu ? "Команды" : "Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> ClanCommands = new() {
"clan", "clans"
}
;
[JsonProperty(PropertyName = LangRu ? "Команды информации о клане" : "Clan Info Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] ClanInfoCommands = {
"cinfo"
}
;
[JsonProperty(PropertyName = LangRu ? "Максимальное количество символов описания клана" : "Maximum clan description characters")]
public int DescriptionMax = 256;
[JsonProperty(PropertyName = LangRu ? "Тег клана в имени игрока" : "Clan tag in player name")]
public bool TagInName = true;
[JsonProperty(PropertyName = LangRu ? "Автоматическое создание команды" : "Automatic team creation")]
public bool AutoTeamCreation = true;
[JsonProperty(PropertyName = LangRu ? "Разрешить игрокам покидать свой клан с помощью кнопки выхода из внутриигровых команд" : "Allow players to leave their clan by using Rust's leave team button")]
public bool ClanTeamLeave = true;
[JsonProperty(PropertyName = LangRu ? "Разрешить игрокам исключать участников из своего клана с помощью кнопки исключения участника внутриигровых команд" : "Allow players to kick members from their clan using Rust's kick member button")]
public bool ClanTeamKick = true;
[JsonProperty(PropertyName = LangRu ? "Разрешить игрокам приглашать других игроков в свой клан через систему приглашений внутриигровых команд" : "Allow players to invite other players to their clan via Rust's team invite system")]
public bool ClanTeamInvite = true;
[JsonProperty(PropertyName = LangRu ? "Разрешить игрокам повышать других участников клана через кнопку повышения участника внутриигровых команд" : "Allow players to promote other clan members via Rust's team promote button")]
public bool ClanTeamPromote = true;
[JsonProperty(PropertyName = LangRu ? "Разрешить игрокам принять приглашение в клан с помощью кнопки принятия приглашения внутриигровых команд" : "Allow players to accept a clan invite using the Rust invite accept button")]
public bool ClanTeamAcceptInvite = true;
[JsonProperty(PropertyName = LangRu ? "Показывать интерфейс создания клана при создании команды?" : "Show clan creation interface when creating a team?")]
public bool ClanCreateTeam = false;
[JsonProperty(PropertyName = LangRu ? "Принудительное создание клана при создании команды?" : "Force to create a clan when creating a team?")]
public bool ForceClanCreateTeam = false;
[JsonProperty(PropertyName = LangRu ? "Частота обновления топа" : "Top refresh rate")]
public float TopRefreshRate = 60f;
[JsonProperty(PropertyName = LangRu ? "Значение по умолчанию для нормативов ресурсов" : "Default value for the resource standarts")]
public int DefaultValStandarts = 100000;
[JsonProperty(PropertyName = LangRu ? "Автоматическое расформирование клана при выходе лидера" : "Automatic disbanding of the clan when the leader leaves the clan")]
public bool AutoDisbandOnLeaderLeave = false;
[JsonProperty(PropertyName = LangRu ? "Настройки чата" : "Chat Settings")]
public ChatSettings ChatSettings = new() {
Enabled = true, TagFormat = "<color=#{color}>[{tag}]</color>", EnabledClanChat = true, ClanChatCommands = new[] {
"c", "cchat"
}
, EnabledAllianceChat = true, AllianceChatCommands = new[] {
"a", "achat"
}
, WorkingWithBetterChat = true, WorkingWithIQChat = true, WorkingWithInGameChat = false
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки разрешений" : "Permission Settings")]
public PermissionSettings PermissionSettings = new() {
UsePermClanCreating = false, ClanCreating = "clans.cancreate", UsePermClanJoining = false, ClanJoining = "clans.canjoin", UsePermClanLeave = false, ClanLeave = "clans.canleave", UsePermClanDisband = false, ClanDisband = "clans.candisband", UsePermClanKick = false, ClanKick = "clans.cankick", UsePermClanSkins = false, ClanSkins = "clans.canskins", ClanInfoAuthLevel = 0
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки альянсов" : "Alliance Settings")]
public AllianceSettings AllianceSettings = new() {
Enabled = true, UseFF = true, DefaultFF = false, GeneralFriendlyFire = false, ModersGeneralFF = false, PlayersGeneralFF = false, AllyAddPlayersTeams = false
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки очистки" : "Purge Settings")]
public PurgeSettings PurgeSettings = new() {
Enabled = true, OlderThanDays = 14, ListPurgedClans = true, WipeClansOnNewSave = false, WipePlayersOnNewSave = false, WipeInvitesOnNewSave = false
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки ограничений" : "Limit Settings")]
public LimitSettings LimitSettings = new() {
MemberLimit = 8, ModeratorLimit = 2, AlliancesLimit = 2
}
;
[JsonProperty(PropertyName = LangRu ? "Ресурсы" : "Resources", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Resources = new() {
"stones", "sulfur.ore", "metal.ore", "hq.metal.ore", "wood"
}
;
[JsonProperty(PropertyName = LangRu ? "Доступные элементы для норм добычи ресурсов" : "Available items for resource standarts", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> AvailableStandartItems = new() {
"gears", "metalblade", "metalpipe", "propanetank", "roadsigns", "rope", "sewingkit", "sheetmetal", "metalspring", "tarp", "techparts", "riflebody", "semibody", "smgbody", "fat.animal", "cctv.camera", "charcoal", "cloth", "crude.oil", "diesel_barrel", "gunpowder", "hq.metal.ore", "leather", "lowgradefuel", "metal.fragments", "metal.ore", "scrap", "stones", "sulfur.ore", "sulfur", "targeting.computer", "wood"
}
;
[JsonProperty(PropertyName = LangRu ? "Страницы" : "Pages", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<PageSettings> Pages = new() {
new PageSettings {
ID = ABOUT_CLAN, Key = "aboutclan", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = MEMBERS_LIST, Key = "memberslist", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = CLANS_TOP, Key = "clanstop", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = PLAYERS_TOP, Key = "playerstop", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = GATHER_RATES, Key = "resources", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = SKINS_PAGE, Key = "skins", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = PLAYERS_LIST, Key = "playerslist", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = ALIANCES_LIST, Key = "alianceslist", Enabled = true, Permission = string.Empty
}
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки интерфейса" : "Interface")]
public InterfaceSettings UI = new() {
Color1 = new IColor("#0E0E10", 100), Color2 = new IColor("#4B68FF", 100), Color3 = new IColor("#161617", 100), Color4 = new IColor("#324192", 100), Color5 = new IColor("#303030", 100), Color6 = new IColor("#FF4B4B", 100), Color7 = new IColor("#4B68FF", 33), Color8 = new IColor("#0E0E10", 99), ValueAbbreviation = true, ShowCloseOnClanCreation = true, TopClansColumns = new List<ColumnSettings> {
new() {
Width = 75, Key = "top", LangKey = TopTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "#{0}"
}
, new() {
Width = 165, Key = "name", LangKey = NameTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 70, Key = "leader", LangKey = LeaderTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 90, Key = "members", LangKey = MembersTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 80, Key = "score", LangKey = ScoreTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
}
, TopPlayersColumns = new List<ColumnSettings> {
new() {
Width = 75, Key = "top", LangKey = TopTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "#{0}"
}
, new() {
Width = 185, Key = "name", LangKey = NameTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 70, Key = "kills", LangKey = KillsTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 70, Key = "resources", LangKey = ResourcesTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 80, Key = "score", LangKey = ScoreTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
}
, ProfileButtons = new List<BtnConf> {
new() {
Enabled = false, CloseMenu = true, AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = "270 -55", OffsetMax = "360 -30", Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf", FontSize = 10, TextColor = new IColor("#FFFFFF", 100), Color = new IColor("#324192", 100), Title = "TP", Command = "tpr {target}"
}
, new() {
Enabled = false, CloseMenu = true, AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = "370 -55", OffsetMax = "460 -30", Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf", FontSize = 10, TextColor = new IColor("#FFFFFF", 100), Color = new IColor("#324192", 100), Title = "TRADE", Command = "trade {target}"
}
}
, ClanMemberProfileFields = new List<ColumnSettings> {
new() {
Width = 140, Key = "gather", LangKey = GatherTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}%"
}
, new() {
Width = 140, Key = "lastlogin", LangKey = LastLoginTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 10, TextFormat = "{0}"
}
}
, TopPlayerProfileFields = new List<ColumnSettings> {
new() {
Width = 300, Key = "clanname", LangKey = ClanNameTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 140, Key = "rating", LangKey = RatingTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 140, Key = "score", LangKey = ScoreTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 140, Key = "kills", LangKey = KillsTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 140, Key = "deaths", LangKey = DeathsTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}"
}
, new() {
Width = 140, Key = "kd", LangKey = KDTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "{0}"
}
}
, ShowBtnChangeAvatar = true, ShowBtnLeave = true, PageAboutClan = new InterfaceSettings.AboutClanInfo {
ShowClanName = true, ShowClanAvatar = true, ShowClanLeader = true, ShowClanGather = true, ShowClanRating = true, ShowClanMembers = true, ShowClanDescription = true
}
, PagePlayersTop = new InterfaceSettings.PlayersTopPage {
PlayersOnPage = 7, Height = 37.5f, Width = 480, Margin = 2.5f, UpIndent = 50
}
, PageClansTop = new InterfaceSettings.ClansTopPage {
ClansOnPage = 7, Height = 37.5f, Width = 480, Margin = 2.5f, UpIndent = 50
}
, PageMembers = new InterfaceSettings.MembersPage {
MembersOnLine = 2, MaxLines = 8, UpIndent = 0, Height = 35, Width = 237.5f, Margin = 5
}
, PagePlayersList = new InterfaceSettings.PlayerListPage {
MembersOnLine = 2, MaxLines = 8, UpIndent = 0, Height = 35, Width = 237.5f, Margin = 5, ShowAllPlayers = false
}
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки скинов" : "Skins Settings")]
public SkinsSettings Skins = new() {
ItemSkins = new Dictionary<string, List<ulong>> {
["metal.facemask"]
= new(), ["hoodie"] = new(), ["metal.plate.torso"] = new(), ["pants"] = new(), ["roadsign.kilt"] = new(), ["shoes.boots"] = new(), ["rifle.ak"] = new(), ["rifle.bolt"] = new()
}
, UseSkinner = false, UseSkinBox = false, UsePlayerSkins = false, UseLSkins = false, CanCustomSkin = true, Permission = string.Empty, DisableSkins = false, DefaultValueDisableSkins = true
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки статистики" : "Statistics Settings")]
public StatisticsSettings Statistics = new() {
Kills = true, Gather = true, Loot = true, Entities = true, Craft = true
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки цветов" : "Colos Settings")]
//TODO: change to Colors
public ColorsSettings Colors = new() {
Member = "#fcf5cb", Moderator = "#74c6ff", Owner = "#a1ff46"
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки PlayerDatabase" : "PlayerDatabase")]
public PlayerDatabaseConf PlayerDatabase = new(false, "Clans");
[JsonProperty(PropertyName = LangRu ? "Настройки ZoneManager" : "ZoneManager Settings")]
public ZoneManagerSettings ZMSettings = new() {
Enabled = false, FFAllowlist = new List<string> {
"92457", "4587478545"
}
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки клан-тегов" : "Clan Tag Settings")]
public TagSettings Tags = new() {
TagMin = 2, TagMax = 6, CaseSensitive = true, BlockedWords = new List<string> {
"admin", "mod", "owner"
}
, CheckingCharacters = true, AllowedCharacters = "!²³", TagColor = new TagSettings.TagColorSettings {
Enabled = true, DefaultColor = "AAFF55", Owners = true, Moderators = false, Players = false
}
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки команд" : "Commands Settings")]
public CommandsSettings Commands = new() {
ClansFF = new[] {
"cff"
}
, AllyFF = new[] {
"aff"
}
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки сохранения" : "Saving Settings")]
public SavingSettings Saving = new() {
SavePlayersOnServerSave = false, SaveClansOnServerSave = true
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки дружественного огня" : "Friendly Fire Settings")]
public FriendlyFireSettings FriendlyFire = new() {
UseFriendlyFire = true, UseTurretsFF = false, GeneralFriendlyFire = false, ModersGeneralFF = false, PlayersGeneralFF = false, FriendlyFire = false, IgnoreOnArenaTournament = false
}
;
[JsonProperty(PropertyName = LangRu ? "Платные функции" : "Paid Functionality Settings")]
public PaidFunctionalitySettings PaidFunctionality = new() {
Economy = new PaidFunctionalitySettings.EconomySettings {
Type = PaidFunctionalitySettings.EconomySettings.EconomyType.Plugin, AddHook = "Deposit", BalanceHook = "Balance", RemoveHook = "Withdraw", Plug = "Economics", ShortName = "scrap", DisplayName = string.Empty, Skin = 0
}
, ChargeFeeToCreateClan = false, CostCreatingClan = 100, ChargeFeeToJoinClan = false, CostJoiningClan = 100, ChargeFeeToKickClanMember = false, CostKickingClanMember = 100, ChargeFeeToLeaveClan = false, CostLeavingClan = 100, ChargeFeeToDisbandClan = false, CostDisbandingClan = 100, ChargeFeeToSetClanSkin = false, CostSettingClanSkin = 100, ChargeFeeToSetClanAvatar = false, CostSettingClanAvatar = 100, ChargeFeeForSendInviteToClan = false, CostForSendInviteToClan = 100
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки страниц" : "Pages Settings")]
public PagesSettings PagesConfig = new() {
Default = new PagesSettings.DefaultPages {
Enabled = true, ClanPageNotFound = ABOUT_CLAN, ClanPageWhenExists = PLAYERS_TOP
}
, StayOnPageWithSelectedSkin = true
}
;
[JsonProperty(PropertyName = LangRu ? "Настройки добычи" : "Loot Settings")]
public LootSettings Loot = new() {
Enabled = true, Loots = new List<LootSettings.LootEntry> {
LootSettings.LootEntry.Create("kills", LootSettings.LootType.Kill), LootSettings.LootEntry.Create("deaths", LootSettings.LootType.Kill, -1f), LootSettings.LootEntry.Create("stone-ore", LootSettings.LootType.Gather, 0.1f), LootSettings.LootEntry.Create("supply_drop", LootSettings.LootType.LootCrate, 3), LootSettings.LootEntry.Create("crate_normal", LootSettings.LootType.LootCrate, 0.3f), LootSettings.LootEntry.Create("crate_elite", LootSettings.LootType.LootCrate, 0.5f), LootSettings.LootEntry.Create("bradley_crate", LootSettings.LootType.LootCrate, 5f), LootSettings.LootEntry.Create("heli_crate", LootSettings.LootType.LootCrate, 5f), LootSettings.LootEntry.Create("bradley", LootSettings.LootType.Kill, 10f), LootSettings.LootEntry.Create("helicopter", LootSettings.LootType.Kill, 15f), LootSettings.LootEntry.Create("barrel", LootSettings.LootType.Kill, 0.1f), LootSettings.LootEntry.Create("scientistnpc", LootSettings.LootType.Kill, 0.5f), LootSettings.LootEntry.Create("heavyscientist", LootSettings.LootType.Kill, 2f), LootSettings.LootEntry.Create("sulfur.ore", LootSettings.LootType.Gather, 0.5f), LootSettings.LootEntry.Create("metal.ore", LootSettings.LootType.Gather, 0.5f), LootSettings.LootEntry.Create("hq.metal.ore", LootSettings.LootType.Gather, 0.5f), LootSettings.LootEntry.Create("stones", LootSettings.LootType.Gather, 0.5f), LootSettings.LootEntry.Create("cupboard.tool.deployed", LootSettings.LootType.Kill)
}
}
;
public VersionNumber Version;
#region Classes
public class PagesSettings {
[JsonProperty(PropertyName = LangRu ? "Страницы по умолчанию" : "Default Pages")]
public DefaultPages Default;
[JsonProperty(PropertyName = LangRu ? "Оставаться на странице выбранного скина" : "Stay on page with selected skin")]
public bool StayOnPageWithSelectedSkin;
public class DefaultPages {
[JsonProperty(PropertyName = LangRu ? "Включено" : "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = LangRu ? "Страница по умолчанию, когда клан не найден" : "Default page when a clan not found")]
public int ClanPageNotFound;
[JsonProperty(PropertyName = LangRu ? "Страница по умолчанию, когда клан существует" : "Default page when a clan exists")]
public int ClanPageWhenExists;
}
}
#endregion Classes
}
private class LootSettings {
#region Fields
[JsonProperty(PropertyName = LangRu ? "Включено" : "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = LangRu ? "Добыча" : "Loot", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<LootEntry> Loots = new();
#endregion
#region Cache
[JsonIgnore]
private Dictionary<LootType, Dictionary<string, float>> _cachedLoot = new();
[JsonIgnore]
private Dictionary<string, float> _cachedScore = new();
public void Init() {
_cachedLoot.Clear();
Loots.ForEach(ent => {
if (!ent.Enabled || ent.Type == LootType.None) return;
if (!_cachedLoot.ContainsKey(ent.Type)) _cachedLoot.TryAdd(ent.Type, new Dictionary<string, float>());
if (!_cachedLoot[ent.Type].TryAdd(ent.ShortName, ent.Score)) _instance?.PrintError($"Can't cache loot type {ent.Type}: shortname '{ent.ShortName}' already exists!!!");
if (_cachedScore.ContainsKey(ent.ShortName)) _cachedScore[ent.ShortName] += ent.Score;
else _cachedScore.TryAdd(ent.ShortName, ent.Score);
}
);
}
#region By Loot Type
public bool TryGetLoot(LootType type, string shortName, out float score) {
if (_cachedLoot.TryGetValue(type, out var dict)) if (dict.TryGetValue(shortName, out score)) return true;
score = 0;
return false;
}
public bool HasLootByType(LootType type, string shortName) {
return _cachedLoot.TryGetValue(type, out var dict) && dict.ContainsKey(shortName);
}
public List<string> GetLootByType(LootType type) {
return !_cachedLoot.TryGetValue(type, out var dict) ? new List<string>() : new List<string>(dict.Keys);
}
#endregion
#region By ShortName
public bool TryGetLoot(string shortName, out float score) {
return _cachedScore.TryGetValue(shortName, out score);
}
public bool HasLootByShortName(string shortName) {
return _cachedScore.ContainsKey(shortName);
}
#endregion
#endregion
#region Classes
public class LootEntry {
[JsonProperty(PropertyName = LangRu ? "Включено" : "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = LangRu ? "Краткое имя предмета" : "Short Name")]
public string ShortName;
[JsonProperty(PropertyName = LangRu ? "Тип добычи" : "Loot Type")]
[JsonConverter(typeof(StringEnumConverter))]
public LootType Type;
[JsonProperty(PropertyName = LangRu ? "Очки" : "Score")]
public float Score;
public static LootEntry Create(string shortName, LootType type, float score = 1f) {
return new LootEntry {
Enabled = true, ShortName = shortName, Type = type, Score = score
}
;
}
}
public enum LootType {
None, Gather, LootCrate, Look, Kill, Craft, HackCrate
}
#endregion
}
private class PaidFunctionalitySettings {
[JsonProperty(PropertyName = LangRu ? "Экономика" : "Economy")]
public EconomySettings Economy;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за создание клана?" : "Charge a fee to create a clan?")]
public bool ChargeFeeToCreateClan;
[JsonProperty(PropertyName = LangRu ? "Стоимость создания клана" : "Cost of creating a clan")]
public int CostCreatingClan;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за вступление в клан?" : "Charge a fee to join a clan?")]
public bool ChargeFeeToJoinClan;
[JsonProperty(PropertyName = LangRu ? "Стоимость вступления в клан" : "Cost of joining a clan")]
public int CostJoiningClan;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за исключение члена клана?" : "Charge a fee to kick a clan member?")]
public bool ChargeFeeToKickClanMember;
[JsonProperty(PropertyName = LangRu ? "Стоимость исключения члена клана" : "Cost of kicking a clan member")]
public int CostKickingClanMember;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за выход из клана?" : "Charge a fee to leave a clan?")]
public bool ChargeFeeToLeaveClan;
[JsonProperty(PropertyName = LangRu ? "Стоимость выхода из клана" : "Cost of leaving a clan")]
public int CostLeavingClan;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за распущение клана?" : "Charge a fee to disband a clan?")]
public bool ChargeFeeToDisbandClan;
[JsonProperty(PropertyName = LangRu ? "Стоимость распуска клана" : "Cost of disbanding a clan")]
public int CostDisbandingClan;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за установку скина клана?" : "Charge a fee to set a clan skin?")]
public bool ChargeFeeToSetClanSkin;
[JsonProperty(PropertyName = LangRu ? "Стоимость установки скина клана" : "Cost of setting a clan skin")]
public int CostSettingClanSkin;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за установку аватара клана?" : "Charge a fee to set a clan avatar?")]
public bool ChargeFeeToSetClanAvatar;
[JsonProperty(PropertyName = LangRu ? "Стоимость установки аватара клана" : "Cost of setting a clan avatar")]
public int CostSettingClanAvatar;
[JsonProperty(PropertyName = LangRu ? "Взимать плату за отправку приглашения в клан?" : "Charge a fee for sending an invitation to a clan?")]
public bool ChargeFeeForSendInviteToClan;
[JsonProperty(PropertyName = LangRu ? "Стоимость отправки приглашения в клан" : "Cost of sending an invitation to a clan")]
public int CostForSendInviteToClan;
public class EconomySettings {
#region Fields
[JsonProperty(PropertyName = LangRu ? "Тип (Plugin/Item)" : "Type (Plugin/Item)")]
[JsonConverter(typeof(StringEnumConverter))]
public EconomyType Type;
[JsonProperty(PropertyName = LangRu ? "Название плагина" : "Plugin name")]
public string Plug;
[JsonProperty(PropertyName = LangRu ? "Функция пополнения баланса" : "Balance add hook")]
public string AddHook;
[JsonProperty(PropertyName = LangRu ? "Функция снятия баланса" : "Balance remove hook")]
public string RemoveHook;
[JsonProperty(PropertyName = LangRu ? "Функция показа баланса" : "Balance show hook")]
public string BalanceHook;
[JsonProperty(PropertyName = LangRu ? "Краткое имя предмета" : "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = LangRu ? "Отображаемое имя (пусто - по умолчанию)" : "Display Name (empty - default)")]
public string DisplayName;
[JsonProperty(PropertyName = LangRu ? "Скин" : "Skin")]
public ulong Skin;
#endregion
#region Public Methods
public enum EconomyType {
Plugin, Item
}
public double ShowBalance(BasePlayer player) {
switch (Type) {
case EconomyType.Plugin : {
var plugin = _instance?.plugins?.Find(Plug);
if (plugin == null) return 0;
return Math.Round(Convert.ToDouble(plugin.Call(BalanceHook, player.UserIDString)));
}
case EconomyType.Item : {
return PlayerItemsCount(player, ShortName, Skin);
}
default : return 0;
}
}
public void AddBalance(BasePlayer player, double amount) {
switch (Type) {
case EconomyType.Plugin : {
var plugin = _instance?.plugins?.Find(Plug);
if (plugin == null) return;
switch (Plug) {
case "BankSystem" : case "ServerRewards" : plugin.Call(AddHook, player.UserIDString, (int) amount);
break;
default : plugin.Call(AddHook, player.UserIDString, amount);
break;
}
break;
}
case EconomyType.Item : {
var am = (int) amount;
var item = ToItem(am);
if (item == null) return;
player.GiveItem(item);
break;
}
}
}
public bool RemoveBalance(BasePlayer player, double amount) {
switch (Type) {
case EconomyType.Plugin : {
if (ShowBalance(player) < amount) return false;
var plugin = _instance?.plugins.Find(Plug);
if (plugin == null) return false;
switch (Plug) {
case "BankSystem" : case "ServerRewards" : plugin.Call(RemoveHook, player.UserIDString, (int) amount);
break;
default : plugin.Call(RemoveHook, player.UserIDString, amount);
break;
}
return true;
}
case EconomyType.Item : {
var playerItems = Pool.Get<List<Item>>();
player.inventory.GetAllItems(playerItems);
var am = (int) amount;
if (ItemCount(playerItems, ShortName, Skin) < am) {
Pool.Free(ref playerItems);
return false;
}
Take(playerItems, ShortName, Skin, am);
Pool.Free(ref playerItems);
return true;
}
default : return false;
}
}
private Item ToItem(int amount) {
var item = ItemManager.CreateByName(ShortName, amount, Skin);
if (item == null) {
Debug.LogError($"Error creating item with ShortName: '{ShortName}'");
return null;
}
if (!string.IsNullOrEmpty(DisplayName)) item.name = DisplayName;
return item;
}
#region Utils
private int PlayerItemsCount(BasePlayer player, string shortname, ulong skin) {
var items = Pool.Get<List<Item>>();
player.inventory.GetAllItems(items);
var result = ItemCount(items, shortname, skin);
Pool.Free(ref items);
return result;
}
private int ItemCount(List<Item> items, string shortname, ulong skin) {
return items.FindAll(item => item.info.shortname == shortname && !item.isBroken && (skin == 0 || item.skin == skin)) .Sum(item => item.amount);
}
private void Take(List<Item> itemList, string shortname, ulong skinId, int iAmount) {
var num1 = 0;
if (iAmount == 0) return;
var list = Pool.Get<List<Item>>();
foreach (var item in itemList) {
if (item.info.shortname != shortname || (skinId != 0 && item.skin != skinId) || item.isBroken) continue;
var num2 = iAmount - num1;
if (num2 <= 0) continue;
if (item.amount > num2) {
item.MarkDirty();
item.amount -= num2;
//num1 += num2;
break;
}
if (item.amount <= num2) {
num1 += item.amount;
list.Add(item);
}
if (num1 == iAmount) break;
}
foreach (var obj in list) obj.RemoveFromContainer();
Pool.FreeUnmanaged(ref list);
}
#endregion
#endregion
}
}
private class FriendlyFireSettings {
[JsonProperty(PropertyName = LangRu ? "Использовать дружественный огонь?" : "Use Friendly Fire?")]
public bool UseFriendlyFire;
[JsonProperty(PropertyName = LangRu ? "Использовать дружественный огонь для турелей?" : "Use Friendly Fire for Turrets?")]
public bool UseTurretsFF;
[JsonProperty(PropertyName = LangRu ? "Общий дружественный огонь (только лидер клана может включить/выключить его)" : "General friendly fire (only the leader of the clan can enable/disable it)")]
public bool GeneralFriendlyFire;
[JsonProperty(PropertyName = LangRu ? "Могут модераторы переключить общий дружественный огонь?" : "Can moderators toggle general friendly fire?")]
public bool ModersGeneralFF;
[JsonProperty(PropertyName = LangRu ? "Могут игроки переключить общий дружественный огонь?" : "Can players toggle general friendly fire?")]
public bool PlayersGeneralFF;
[JsonProperty(PropertyName = LangRu ? "Значение по умолчанию для дружественного огня" : "Friendly Fire Default Value")]
public bool FriendlyFire;
[JsonProperty(PropertyName = LangRu ? "Игнорировать при использовании ArenaTournament?" : "Ignore when using ArenaTournament?")]
public bool IgnoreOnArenaTournament;
}
private class SavingSettings {
[JsonProperty(PropertyName = LangRu ? "Включить сохранение данных игроков во время сохранения сервера?" : "Enable saving player data during server saves?")]
public bool SavePlayersOnServerSave;
[JsonProperty(PropertyName = LangRu ? "Включить сохранение данных кланов во время сохранения сервера?" : "Enable saving clan data during server save?")]
public bool SaveClansOnServerSave;
}
private class AvatarSettings {
[JsonProperty(PropertyName = LangRu ? "Аватар по умолчанию" : "Default Avatar")]
public string DefaultAvatar;
[JsonProperty(PropertyName = LangRu ? "Может ли владелец клана изменить аватар?" : "Can the clan owner change the avatar?")]
public bool CanOwner;
[JsonProperty(PropertyName = LangRu ? "Может ли модератор клана изменить аватар?" : "Can the clan moderator change the avatar?")]
public bool CanModerator;
[JsonProperty(PropertyName = LangRu ? "Может ли участник клана изменить аватар?" : "Can the clan member change the avatar?")]
public bool CanMember;
[JsonProperty(PropertyName = LangRu ? "Разрешение на изменение аватара клана" : "Permission to change clan avatar")]
public string PermissionToChange;
[JsonProperty(PropertyName = LangRu ? "Ключ API Steam (получите его здесь: https://steamcommunity.com/dev/apikey)" : "Steam API key (get one here: https://steamcommunity.com/dev/apikey)")]
public string SteamAPIKey;
}
private class CommandsSettings {
[JsonProperty(PropertyName = LangRu ? "Команды для кланового FF" : "Clans FF", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] ClansFF;
[JsonProperty(PropertyName = LangRu ? "Команды для альянсового FF" : "Aliance FF", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] AllyFF;
}
private class TagSettings {
[JsonProperty(PropertyName = LangRu ? "Запрещенные слова" : "Blocked Words", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> BlockedWords;
[JsonProperty(PropertyName = LangRu ? "Минимальное количество символов в теге клана" : "Minimum clan tag characters")]
public int TagMin;
[JsonProperty(PropertyName = LangRu ? "Максимальное количество символов в теге клана" : "Maximum clan tag characters")]
public int TagMax;
[JsonProperty(PropertyName = LangRu ? "Включить учет регистра для тегов клана" : "Enable case sensitivity for clan tags")]
public bool CaseSensitive;
[JsonProperty(PropertyName = LangRu ? "Включить проверку символов в тегах?" : "Enable character checking in tags?")]
public bool CheckingCharacters;
[JsonProperty(PropertyName = LangRu ? "Разрешенные специальные символы в тегах" : "Special characters allowed in tags")]
public string AllowedCharacters;
[JsonProperty(PropertyName = LangRu ? "Настройки цвета тега" : "Tag Color Settings")]
public TagColorSettings TagColor;
public class TagColorSettings {
[JsonProperty(PropertyName = LangRu ? "Включено" : "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = LangRu ? "Цвет по умолчанию" : "Default Color")]
public string DefaultColor;
[JsonProperty(PropertyName = LangRu ? "Могут ли владельцы изменять цвет?" : "Can the owner change the color?")]
public bool Owners;
[JsonProperty(PropertyName = LangRu ? "Могут ли модераторы изменять цвет?" : "Can the moderators change the color?")]
public bool Moderators;
[JsonProperty(PropertyName = LangRu ? "Могут ли игроки изменять цвет?" : "Can the players change the color?")]
public bool Players;
}
}
private class ZoneManagerSettings {
[JsonProperty(PropertyName = LangRu ? "Включено" : "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = LangRu ? "Зоны с разрешенным дружественным огнем" : "Zones with allowed Friendly Fire", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> FFAllowlist = new();
}
private class ColorsSettings {
[JsonProperty(PropertyName = LangRu ? "Цвет владельца клана (hex)" : "Clan owner color (hex)")]
public string Owner;
[JsonProperty(PropertyName = LangRu ? "Цвет модератора клана (hex)" : "Clan moderator color (hex)")]
public string Moderator;
[JsonProperty(PropertyName = LangRu ? "Цвет участника клана (hex)" : "Clan member color (hex)")]
public string Member;
}
private class PlayerDatabaseConf {
[JsonProperty(PropertyName = LangRu ? "Включено" : "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = LangRu ? "Таблица" : "Table")]
public string Field;
public PlayerDatabaseConf(bool enabled, string field) {
Enabled = enabled;
Field = field;
}
}
private class StatisticsSettings {
[JsonProperty(PropertyName = LangRu ? "Убийства" : "Kills")]
public bool Kills;
[JsonProperty(PropertyName = LangRu ? "Сбор ресурсов" : "Gather")]
public bool Gather;
[JsonProperty(PropertyName = LangRu ? "Лутание" : "Loot")]
public bool Loot;
[JsonProperty(PropertyName = LangRu ? "Объекты" : "Entities")]
public bool Entities;
[JsonProperty(PropertyName = LangRu ? "Крафт" : "Craft")]
public bool Craft;
}
private class SkinsSettings {
#region Fields
[JsonProperty(PropertyName = LangRu ? "Скины предметов" : "Item Skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<ulong>> ItemSkins = new();
[JsonProperty(PropertyName = LangRu ? "Использовать скины из Skinner?" : "Use skins from Skinner?")]
public bool UseSkinner;
[JsonProperty(PropertyName = LangRu ? "Использовать скины из SkinBox?" : "Use skins from SkinBox?")]
public bool UseSkinBox;
[JsonProperty(PropertyName = LangRu ? "Использовать скины из PlayerSkins?" : "Use skins from PlayerSkins?")]
public bool UsePlayerSkins;
[JsonProperty(PropertyName = LangRu ? "Использовать скины из LSkins?" : "Use skins from LSkins?")]
public bool UseLSkins;
[JsonProperty(PropertyName = LangRu ? "Могут ли игроки устанавливать пользовательские скины?" : "Can players install custom skins?")]
public bool CanCustomSkin;
[JsonProperty(PropertyName = LangRu ? "Разрешение на установку пользовательского скина" : "Permission to install custom skin")]
public string Permission;
[JsonProperty(PropertyName = LangRu ? "Отключить скины для клана?" : "Option to disable clan skins?")]
public bool DisableSkins;
[JsonProperty(PropertyName = LangRu ? "Значение по умолчанию для отключения скинов" : "Default value to disable skins")]
public bool DefaultValueDisableSkins;
#endregion Fields
}
private class InterfaceSettings {
#region Fields
[JsonPr
// ... [Code preview truncated due to length. Full source in attached file] ...