C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Facepunch;
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 UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins {
[Info("Clans", "Mevent", "1.0.14")]
public class Clans : RustPlugin {
//TODO: Work with PlayerDatabase
//TODO: Displaying the top clans on the screen
#region Fields
[PluginReference]
private Plugin ImageLibrary, Profile;
//private const string Layer = "UI.Clans";
private const string Layer = "UI.Clans";
//private const string ModalLayer = "SubContent_UI";
private const string ModalLayer = "UI.Clans.Modal";
private static Clans _instance;
private readonly List<ItemDefinition> StandartItems = new List<ItemDefinition>();
private Coroutine ActionAvatars;
private readonly Dictionary<uint, ulong> Looters = new Dictionary<uint, ulong>();
#region Colors
private string Color1;
private string Color2;
private string Color3;
private string Color4;
private string Color5;
private string Color6;
#endregion
#endregion
#region Config
private static Configuration _config;
private class Configuration {
[JsonProperty(PropertyName = "Default Avatar")]
public string DefaultAvatar = "https://i.imgur.com/nn7Lcm2.png";
[JsonProperty(PropertyName = "Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Commands = new List<string> {
"clan", "clans"
}
;
[JsonProperty(PropertyName = "Minimum clan tag characters")]
public int TagMin = 2;
[JsonProperty(PropertyName = "Maximum clan tag characters")]
public int TagMax = 6;
[JsonProperty(PropertyName = "Maximum clan description characters")]
public int DescriptionMax = 256;
[JsonProperty(PropertyName = "Clan tag in player name")]
public bool TagInName = true;
[JsonProperty(PropertyName = "Automatic team creation")]
public bool AutoTeamCreation = true;
[JsonProperty(PropertyName = "Allow players to leave their clan by using Rust's leave team button")]
public bool ClanTeamLeave = true;
[JsonProperty(PropertyName = "Allow players to kick members from their clan using Rust's kick member button")]
public bool ClanTeamKick = true;
[JsonProperty(PropertyName = "Allow players to invite other players to their clan via Rust's team invite system")]
public bool ClanTeamInvite = true;
[JsonProperty(PropertyName = "Allow players to promote other clan members via Rust's team promote button")]
public bool ClanTeamPromote = true;
[JsonProperty(PropertyName = "Friendly Fire Default Value")]
public bool FriendlyFire;
[JsonProperty(PropertyName = "Top refresh rate")]
public float TopRefreshRate = 15f;
[JsonProperty(PropertyName = "Default value for the resource standarts")]
public int DefaultValStandarts = 100000;
[JsonProperty(PropertyName = "Steampowered API key")]
public string SteamWebApiKey = "!!! You can get it HERE > https://steamcommunity.com/dev/apikey < and you need to insert HERE !!!";
[JsonProperty(PropertyName = "Chat Settings")]
public ChatSettings ChatSettings = new ChatSettings {
Enabled = true, TagFormat = "<color=#4B68FF>[{tag}]</color>"
}
;
[JsonProperty(PropertyName = "Permission Settings")]
public PermissionSettings PermissionSettings = new PermissionSettings {
UseClanCreating = false, ClanCreating = "clans.cancreate", UseClanJoining = false, ClanJoining = "clans.canjoin", UseClanLeave = false, ClanLeave = "clans.canleave", UseClanDisband = false, ClanDisband = "clans.candisband", UseClanKick = false, ClanKick = "clans.cankick"
}
;
[JsonProperty(PropertyName = "Alliance Settings")]
public AllianceSettings AllianceSettings = new AllianceSettings {
Enabled = true, UseFF = true, DefaultFF = false
}
;
[JsonProperty(PropertyName = "Purge Settings")]
public PurgeSettings PurgeSettings = new PurgeSettings {
Enabled = true, OlderThanDays = 14, ListPurgedClans = true, WipeOnNewSave = false
}
;
[JsonProperty(PropertyName = "Limit Settings")]
public LimitSettings LimitSettings = new LimitSettings {
MemberLimit = 8, ModeratorLimit = 2, AlliancesLimit = 2
}
;
[JsonProperty(PropertyName = "Resources", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Resources = new List<string> {
"stones", "sulfur.ore", "metal.ore", "hq.metal.ore", "wood"
}
;
[JsonProperty(PropertyName = "Score Table (shortname - score)", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> ScoreTable = new Dictionary<string, float> {
["kills"]
= 1, ["deaths"] = -1, ["stone-ore"] = 0.1f, ["supply_drop"] = 3f, ["crate_normal"] = 0.3f, ["crate_elite"] = 0.5f, ["bradley_crate"] = 5f, ["heli_crate"] = 5f, ["bradley"] = 10f, ["helicopter"] = 15f, ["barrel"] = 0.1f, ["scientistnpc"] = 0.5f, ["heavyscientist"] = 2f, ["sulfur.ore"] = 0.5f, ["metal.ore"] = 0.5f, ["hq.metal.ore"] = 0.5f, ["stones"] = 0.5f, ["cupboard.tool.deployed"] = 1f
}
;
[JsonProperty(PropertyName = "Available items for resource standarts", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> AvailableStandartItems = new List<string> {
"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 = "Blocked Words", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> BlockedWords = new List<string> {
"admin", "mod", "owner"
}
;
[JsonProperty(PropertyName = "Pages", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<PageSettings> Pages = new List<PageSettings> {
new PageSettings {
ID = 0, Key = "aboutclan", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 1, Key = "memberslist", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 2, Key = "clanstop", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 3, Key = "playerstop", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 4, Key = "resources", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 6, Key = "skins", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 5, Key = "playerslist", Enabled = true, Permission = string.Empty
}
, new PageSettings {
ID = 7, Key = "alianceslist", Enabled = true, Permission = string.Empty
}
}
;
[JsonProperty(PropertyName = "Interface")]
public InterfaceSettings UI = new InterfaceSettings {
Color1 = "#0E0E10", Color2 = "#ff4a4a", Color3 = "#161617", Color4 = "#913131", Color5 = "#303030", Color6 = "#FF4B4B", ValueAbbreviation = true, TopClansColumns = new List<ColumnSettings> {
new ColumnSettings {
Width = 75, Key = "top", LangKey = TopTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "#{0}"
}
, new ColumnSettings {
Width = 165, Key = "name", LangKey = NameTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new ColumnSettings {
Width = 70, Key = "leader", LangKey = LeaderTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new ColumnSettings {
Width = 90, Key = "members", LangKey = MembersTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new ColumnSettings {
Width = 80, Key = "score", LangKey = ScoreTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
}
, TopPlayersColumns = new List<ColumnSettings> {
new ColumnSettings {
Width = 75, Key = "top", LangKey = TopTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 10, FontSize = 12, TextFormat = "#{0}"
}
, new ColumnSettings {
Width = 185, Key = "name", LangKey = NameTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new ColumnSettings {
Width = 70, Key = "kills", LangKey = KillsTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new ColumnSettings {
Width = 70, Key = "resources", LangKey = ResourcesTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
, new ColumnSettings {
Width = 80, Key = "score", LangKey = ScoreTitle, TextAlign = TextAnchor.MiddleCenter, TitleFontSize = 12, FontSize = 12, TextFormat = "{0}"
}
}
}
;
[JsonProperty(PropertyName = "Skins Settings")]
public SkinsSettings Skins = new SkinsSettings {
ItemSkins = new Dictionary<string, List<ulong>> {
["metal.facemask"]
= new List<ulong>(), ["hoodie"] = new List<ulong>(), ["metal.plate.torso"] = new List<ulong>(), ["pants"] = new List<ulong>(), ["roadsign.kilt"] = new List<ulong>(), ["shoes.boots"] = new List<ulong>(), ["rifle.ak"] = new List<ulong>(), ["rifle.bolt"] = new List<ulong>()
}
, CanCustomSkin = true, Permission = string.Empty
}
;
}
private class SkinsSettings {
[JsonProperty(PropertyName = "Item Skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<ulong>> ItemSkins;
[JsonProperty(PropertyName = "Can players install custom skins?")]
public bool CanCustomSkin;
[JsonProperty(PropertyName = "Permission to install custom skin")]
public string Permission;
}
private class InterfaceSettings {
[JsonProperty(PropertyName = "Color 1")]
public string Color1;
[JsonProperty(PropertyName = "Color 2")]
public string Color2;
[JsonProperty(PropertyName = "Color 3")]
public string Color3;
[JsonProperty(PropertyName = "Color 4")]
public string Color4;
[JsonProperty(PropertyName = "Color 5")]
public string Color5;
[JsonProperty(PropertyName = "Color 6")]
public string Color6;
[JsonProperty(PropertyName = "Use value abbreviation?")]
public bool ValueAbbreviation;
[JsonProperty(PropertyName = "Top Clans Columns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ColumnSettings> TopClansColumns;
[JsonProperty(PropertyName = "Top Players Columns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ColumnSettings> TopPlayersColumns;
}
private class ColumnSettings {
[JsonProperty(PropertyName = "Width")]
public float Width;
[JsonProperty(PropertyName = "Lang Key")]
public string LangKey;
[JsonProperty(PropertyName = "Key")]
public string Key;
[JsonProperty(PropertyName = "Text Format")]
public string TextFormat;
[JsonProperty(PropertyName = "Text Align")]
[JsonConverter(typeof(StringEnumConverter))]
public TextAnchor TextAlign;
[JsonProperty(PropertyName = "Title Font Size")]
public int TitleFontSize;
[JsonProperty(PropertyName = "Font Size")]
public int FontSize;
public string GetKey(int top, string values) {
switch (Key) {
case "top" : return string.Format(TextFormat, top);
default : return string.Format(TextFormat, values);
}
}
}
private class PageSettings {
[JsonProperty(PropertyName = "ID (DON'T CHANGE)")]
public int ID;
[JsonProperty(PropertyName = "Key (DON'T CHANGE)")]
public string Key;
[JsonProperty(PropertyName = "Enabled?")]
public bool Enabled;
[JsonProperty(PropertyName = "Permission")]
public string Permission;
}
private class LimitSettings {
[JsonProperty(PropertyName = "Member Limit")]
public int MemberLimit;
[JsonProperty(PropertyName = "Moderator Limit")]
public int ModeratorLimit;
[JsonProperty(PropertyName = "Alliances Limit")]
public int AlliancesLimit;
}
private class PurgeSettings {
[JsonProperty(PropertyName = "Enable clan purging")]
public bool Enabled;
[JsonProperty(PropertyName = "Purge clans that havent been online for x amount of day")]
public int OlderThanDays;
[JsonProperty(PropertyName = "List purged clans in console when purging")]
public bool ListPurgedClans;
[JsonProperty(PropertyName = "Wipe clans on new map save")]
public bool WipeOnNewSave;
}
private class ChatSettings {
[JsonProperty(PropertyName = "Enable clan tags in chat?")]
public bool Enabled;
[JsonProperty(PropertyName = "Tag format")]
public string TagFormat;
}
private class PermissionSettings {
[JsonProperty(PropertyName = "Use permission to create a clan")]
public bool UseClanCreating;
[JsonProperty(PropertyName = "Permission to create a clan")]
public string ClanCreating;
[JsonProperty(PropertyName = "Use permission to join a clan")]
public bool UseClanJoining;
[JsonProperty(PropertyName = "Permission to join a clan")]
public string ClanJoining;
[JsonProperty(PropertyName = "Use permission to kick a clan member")]
public bool UseClanKick;
[JsonProperty(PropertyName = "Clan kick permission")]
public string ClanKick;
[JsonProperty(PropertyName = "Use permission to leave a clan")]
public bool UseClanLeave;
[JsonProperty(PropertyName = "Clan leave permission")]
public string ClanLeave;
[JsonProperty(PropertyName = "Use permission to disband a clan")]
public bool UseClanDisband;
[JsonProperty(PropertyName = "Clan disband permission")]
public string ClanDisband;
}
private class AllianceSettings {
[JsonProperty(PropertyName = "Enable clan alliances")]
public bool Enabled;
[JsonProperty(PropertyName = "Enable friendly fire (allied clans)")]
public bool UseFF;
[JsonProperty(PropertyName = "Default friendly firy value")]
public bool DefaultFF;
}
protected override void LoadConfig() {
base.LoadConfig();
try {
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch {
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig() {
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig() {
_config = new Configuration();
}
#endregion
#region Data
private List<ClanData> ClansList = new List<ClanData>();
private Dictionary<ulong, PlayerData> PlayersList = new Dictionary<ulong, PlayerData>();
private void SaveData() {
SaveClans();
SavePlayers();
}
private void SaveClans() {
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/ClansList", ClansList);
}
private void SavePlayers() {
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/PlayersList", PlayersList);
}
private void LoadData() {
try {
ClansList = Interface.Oxide.DataFileSystem.ReadObject<List<ClanData>>($"{Name}/ClansList");
PlayersList = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, PlayerData>>($"{Name}/PlayersList");
}
catch (Exception e) {
PrintError(e.ToString());
}
if (ClansList == null) ClansList = new List<ClanData>();
if (PlayersList == null) PlayersList = new Dictionary<ulong, PlayerData>();
}
private class PlayerData {
[JsonProperty(PropertyName = "Display Name")]
public string DisplayName;
[JsonProperty(PropertyName = "Last Login")]
public DateTime LastLogin;
[JsonProperty(PropertyName = "Friendly Fire")]
public bool FriendlyFire;
[JsonProperty(PropertyName = "Ally Friendly Fire")]
public bool AllyFriendlyFire;
[JsonProperty(PropertyName = "Stats", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> Stats = new Dictionary<string, float>();
[JsonProperty(PropertyName = "Invites", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, InviteData> Invites = new Dictionary<string, InviteData>();
#region Stats
[JsonIgnore]
public float Kills {
get {
float kills;
Stats.TryGetValue("kills", out kills);
return float.IsNaN(kills) || float.IsInfinity(kills) ? 0 : kills;
}
}
[JsonIgnore]
public float Deaths {
get {
float deaths;
Stats.TryGetValue("deaths", out deaths);
return float.IsNaN(deaths) || float.IsInfinity(deaths) ? 0 : deaths;
}
}
[JsonIgnore]
public float KD {
get {
var kd = Kills / Deaths;
return float.IsNaN(kd) || float.IsInfinity(kd) ? 0 : kd;
}
}
[JsonIgnore]
public float Resources {
get {
var resources = Stats.Where(x => _config.Resources.Contains(x.Key)).Sum(x => x.Value);
return float.IsNaN(resources) || float.IsInfinity(resources) ? 0 : resources;
}
}
[JsonIgnore]
public float Score {
get {
return (float) Math.Round(Stats.Where(x => _config.ScoreTable.ContainsKey(x.Key)).Sum(x => x.Value * _config.ScoreTable[x.Key]));
}
}
public float GetValue(string key) {
float val;
Stats.TryGetValue(key, out val);
return float.IsNaN(val) || float.IsInfinity(val) ? 0 : Mathf.Round(val);
}
public float GetTotalFarm(ClanData clan) {
return (float) Math.Round(clan.ResourceStandarts.Values.Sum(check => {
var result = GetValue(check.ShortName) / check.Amount;
return result > 1 ? 1 : result;
}
) / clan.ResourceStandarts.Count, 3);
}
#endregion
}
private class InviteData {
[JsonProperty(PropertyName = "Inviter Name")]
public string InviterName;
[JsonProperty(PropertyName = "Inviter Id")]
public ulong InviterId;
}
private class ClanData {
[JsonProperty(PropertyName = "Clan Tag")]
public string ClanTag;
[JsonProperty(PropertyName = "Avatar")]
public string Avatar;
[JsonProperty(PropertyName = "Leader ID")]
public ulong LeaderID;
[JsonProperty(PropertyName = "Leader Name")]
public string LeaderName;
[JsonProperty(PropertyName = "Description")]
public string Description;
[JsonProperty(PropertyName = "Creation Time")]
public DateTime CreationTime;
[JsonProperty(PropertyName = "Last Online Time")]
public DateTime LastOnlineTime;
[JsonProperty(PropertyName = "Moderators", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ulong> Moderators = new List<ulong>();
[JsonProperty(PropertyName = "Members", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ulong> Members = new List<ulong>();
[JsonProperty(PropertyName = "Invited Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, ulong> InvitedPlayers = new Dictionary<ulong, ulong>();
[JsonProperty(PropertyName = "Resource Standarts", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<int, ResourceStandart> ResourceStandarts = new Dictionary<int, ResourceStandart>();
[JsonProperty(PropertyName = "Skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, ulong> Skins = new Dictionary<string, ulong>();
[JsonProperty(PropertyName = "Alliances", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Alliances = new List<string>();
[JsonProperty(PropertyName = "Alliance Invites", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, ulong> AllianceInvites = new Dictionary<string, ulong>();
[JsonProperty(PropertyName = "Incoming Alliances", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> IncomingAlliances = new List<string>();
[JsonProperty(PropertyName = "Team ID")]
public ulong TeamID;
[JsonIgnore]
public int Top;
[JsonIgnore]
private RelationshipManager.PlayerTeam Team => RelationshipManager.ServerInstance.FindTeam(TeamID) ?? CreateTeam();
#region Info
public bool IsOwner(string userId) {
return IsOwner(ulong.Parse(userId));
}
public bool IsOwner(ulong userId) {
return LeaderID == userId;
}
public bool IsModerator(string userId) {
return IsModerator(ulong.Parse(userId));
}
public bool IsModerator(ulong userId) {
return Moderators.Contains(userId) || IsOwner(userId);
}
public bool IsMember(string userId) {
return IsMember(ulong.Parse(userId));
}
public bool IsMember(ulong userId) {
return Members.Contains(userId);
}
#endregion
public static ClanData CreateNewClan(string clanTag, BasePlayer leader) {
var clan = new ClanData {
ClanTag = clanTag, LeaderID = leader.userID, LeaderName = leader.displayName, Avatar = _config.DefaultAvatar, Members = new List<ulong> {
leader.userID
}
, CreationTime = DateTime.Now, LastOnlineTime = DateTime.Now, Top = _instance.TopClans.Count + 1
}
;
#region Invites
_instance.GetPlayerData(leader)?.Invites.Clear();
_instance.ClansList.ForEach(x => x.InvitedPlayers.Remove(leader.userID));
#endregion
_instance.ClansList.Add(clan);
if (_config.TagInName) leader.displayName = $"[{clanTag}] {leader.displayName}";
if (_config.AutoTeamCreation) clan.CreateTeam();
ClanCreate(clanTag);
return clan;
}
#region Main
public void Disband() {
var memberUserIDs = Members.Select(x => x.ToString()).ToList();
ClanDisbanded(memberUserIDs);
ClanDisbanded(ClanTag, memberUserIDs);
Members.ToList().ForEach(member => Kick(member, true));
ClanDestroy(ClanTag);
_instance?.ClansList.ForEach(clan => {
clan.Alliances.Remove(ClanTag);
clan.AllianceInvites.Remove(ClanTag);
clan.IncomingAlliances.Remove(ClanTag);
}
);
if (_config.AutoTeamCreation) Team?.members.ToList().ForEach(member => {
Team.RemovePlayer(member);
var player = RelationshipManager.FindByID(member);
if (player != null) player.ClearTeam();
}
);
_instance?.ClansList.Remove(this);
}
public void Join(BasePlayer player) {
Members.Add(player.userID);
if (_config.TagInName) player.displayName = $"[{ClanTag}] {player.displayName}";
if (_config.AutoTeamCreation) {
player.Team?.RemovePlayer(player.userID);
Team?.AddPlayer(player);
}
if (Members.Count >= _config.LimitSettings.MemberLimit) {
InvitedPlayers.Clear();
foreach (var member in _instance.PlayersList.Values) member.Invites.Remove(ClanTag);
}
_instance.ClansList.ForEach(x => x.InvitedPlayers.Remove(player.userID));
_instance.GetPlayerData(player.userID)?.Invites.Clear();
ClanMemberJoined(player.UserIDString, ClanTag);
ClanUpdate(ClanTag);
}
public void Kick(ulong target, bool disband = false) {
Members.Remove(target);
Moderators.Remove(target);
if (_config.TagInName) {
var data = _instance.GetPlayerData(target);
if (data == null) return;
var player = BasePlayer.FindByID(target);
if (player != null) player.displayName = data.DisplayName;
}
if (!disband) {
if (_config.AutoTeamCreation && Team != null) Team.RemovePlayer(target);
if (Members.Count == 0) {
Disband();
}
else {
if (LeaderID == target) SetLeader((Moderators.Count > 0 ? Moderators : Members).GetRandom());
}
}
ClanMemberGone(target.ToString(), Members.Select(x => x.ToString()).ToList());
ClanMemberGone(target.ToString(), ClanTag);
ClanUpdate(ClanTag);
}
public void SetModer(ulong target) {
if (!Moderators.Contains(target)) Moderators.Add(target);
ClanUpdate(ClanTag);
}
public void UndoModer(ulong target) {
Moderators.Remove(target);
ClanUpdate(ClanTag);
}
public void SetLeader(ulong target) {
var data = _instance.GetPlayerData(target);
if (data != null) LeaderName = data.DisplayName;
LeaderID = target;
if (_config.AutoTeamCreation) Team.SetTeamLeader(target);
ClanUpdate(ClanTag);
}
#endregion
#region Additionall
public RelationshipManager.PlayerTeam CreateTeam() {
var team = RelationshipManager.ServerInstance.CreateTeam();
team.teamLeader = LeaderID;
AddPlayer(LeaderID, team);
TeamID = team.teamID;
return team;
}
public void AddPlayer(ulong member, RelationshipManager.PlayerTeam team = null) {
if (team == null) team = Team;
if (!team.members.Contains(member)) team.members.Add(member);
if (member == LeaderID) team.teamLeader = LeaderID;
RelationshipManager.ServerInstance.playerToTeam[member] = team;
var player = RelationshipManager.FindByID(member);
if (player != null) {
if (player.Team != null && player.Team.teamID != team.teamID) {
player.Team.RemovePlayer(player.userID);
player.ClearTeam();
}
player.currentTeam = team.teamID;
team.MarkDirty();
player.SendNetworkUpdate();
}
}
public float Score() {
return Members.Sum(member => _instance.GetPlayerData(member).Score);
}
public string Scores() {
return GetValue(Score());
}
public float GetTotalFarm() {
return (float) Math.Round(Members.Sum(member => _instance.GetPlayerData(member).GetTotalFarm(this)) / Members.Count, 3);
}
public JObject ToJObject() {
return new JObject {
["tag"]
= ClanTag, ["description"] = Description, ["owner"] = LeaderID, ["moderators"] = new JArray(Moderators), ["members"] = new JArray(Members), ["invitedallies"] = new JArray(InvitedPlayers.Keys.Select(x => x.ToString()))
}
;
}
public void SetSkin(string shortName, ulong skin) {
Skins[shortName] = skin;
foreach (var player in Players) foreach (var item in player.inventory.AllItems()) if (item.info.shortname == shortName) ApplySkinToItem(item, skin);
}
public string GetParams(string value) {
switch (value) {
case "name" : return ClanTag;
case "leader" : return LeaderName;
case "members" : return Members.Count.ToString();
case "score" : return Scores();
default : return Math.Round(Members.Sum(member => _instance.GetPlayerData(member).GetValue(value))).ToString(CultureInfo.InvariantCulture);
}
}
#endregion
#region Utils
[JsonIgnore]
public IEnumerable<BasePlayer> Players {
get {
return Members.Select(BasePlayer.FindByID).Where(player => player != null);
}
}
#endregion
}
private class ResourceStandart {
public string ShortName;
public int Amount;
}
private PlayerData GetPlayerData(BasePlayer player) {
return GetPlayerData(player.userID);
}
private PlayerData GetPlayerData(ulong userId) {
if (!PlayersList.ContainsKey(userId)) {
PlayersList.Add(userId, new PlayerData());
PlayersList[userId].FriendlyFire = _config.FriendlyFire;
}
return PlayersList[userId];
}
#region Stats
private void AddToStats(ulong member, string shortName, int amount = 1) {
if (!member.IsSteamId() || !PlayerHasClan(member)) return;
var data = GetPlayerData(member);
if (data == null) return;
if (data.Stats.ContainsKey(shortName)) data.Stats[shortName] += amount;
else data.Stats.Add(shortName, amount);
}
private float GetStatsValue(ulong member, string shortname) {
var data = GetPlayerData(member);
if (data == null) return 0;
switch (shortname) {
case "total" : {
return data.Score;
}
case "kd" : {
return data.KD;
}
case "resources" : {
return data.Resources;
}
default : {
float result;
return data.Stats.TryGetValue(shortname, out result) ? result : 0;
}
}
}
private int GetTop(ulong member, int mode = 0) {
var i = 1;
foreach (var player in PlayersList.OrderByDescending(x => {
switch (mode) {
case 2 : return x.Value.KD;
case 1 : return x.Value.Resources;
default : return x.Value.Score;
}
}
)) {
if (player.Key == member) return i;
i++;
}
return i;
}
#endregion
#endregion
#region Hooks
private void Init() {
_instance = this;
LoadData();
if (!_config.ClanTeamLeave) Unsubscribe(nameof(OnTeamLeave));
if (!_config.ClanTeamKick) Unsubscribe(nameof(OnTeamKick));
if (!_config.ClanTeamInvite) Unsubscribe(nameof(OnTeamInvite));
if (!_config.ClanTeamPromote) Unsubscribe(nameof(OnTeamPromote));
PurgeClans();
}
private void OnServerInitialized() {
LoadImages();
foreach (var player in BasePlayer.activePlayerList) OnPlayerConnected(player);
AddCovalenceCommand(_config.Commands.ToArray(), nameof(CmdClans));
FillingStandartItems();
HandleTop();
LoadSkins();
LoadColors();
if (_config.ChatSettings.Enabled) Interface.CallHook("API_RegisterThirdPartyTitle", this, new Func<IPlayer, string>(BetterChat_FormattedClanTag));
FillingTeams();
RegisterPermissions();
Puts($"Loaded {ClansList.Count} clans!");
timer.Every(_config.TopRefreshRate, HandleTop);
}
private void OnServerSave() {
timer.In(Random.Range(2f, 10f), SaveClans);
timer.In(Random.Range(2f, 10f), SavePlayers);
}
private void Unload() {
if (ActionAvatars != null) ServerMgr.Instance.StopCoroutine(ActionAvatars);
foreach (var player in BasePlayer.activePlayerList) {
CuiHelper.DestroyUi(player, Layer);
CuiHelper.DestroyUi(player, ModalLayer);
if (_config.TagInName) {
var data = GetPlayerData(player);
if (data != null) player.displayName = data.DisplayName;
}
}
SaveData();
_instance = null;
_config = null;
}
private void OnNewSave(string filename) {
if (!_config.PurgeSettings.WipeOnNewSave) return;
ClansList.Clear();
PlayersList.Clear();
SaveData();
}
private void OnPlayerConnected(BasePlayer player) {
if (player == null || !player.userID.IsSteamId()) return;
GetAvatar(player.UserIDString, avatar => ImageLibrary?.Call("AddImage", avatar, $"avatar_{player.UserIDString}"));
var data = GetPlayerData(player);
if (data == null) return;
data.DisplayName = player.displayName;
data.LastLogin = DateTime.Now;
var clan = FindClanByID(player.userID);
if (clan == null) return;
clan.LastOnlineTime = DateTime.Now;
if (_config.TagInName) player.displayName = $"[{clan.ClanTag}] {player.displayName}";
if (_config.AutoTeamCreation) clan.AddPlayer(player.userID);
}
#region Stats
#region Kills
private void OnPlayerDeath(BasePlayer player, HitInfo info) {
if (player == null || info == null || player.ShortPrefabName == "player" && !player.userID.IsSteamId()) return;
var attacker = info.InitiatorPlayer;
if (attacker == null || !attacker.userID.IsSteamId() || IsTeammates(player.userID, attacker.userID)) return;
if (player.userID.IsSteamId()) {
AddToStats(attacker.userID, "kills");
AddToStats(player.userID, "deaths");
}
else {
AddToStats(attacker.userID, player.ShortPrefabName);
}
}
#endregion
#region Gather
private void OnCollectiblePickup(Item item, BasePlayer player) {
OnGather(player, item.info.shortname, item.amount);
}
private void OnCropGather(GrowableEntity plant, Item item, BasePlayer player) {
OnGather(player, item.info.shortname, item.amount);
}
private void OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item) {
OnGather(player, item.info.shortname, item.amount);
}
private void OnDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item) {
OnGather(player, item.info.shortname, item.amount);
}
private void OnGather(BasePlayer player, string shortname, int amount) {
if (player == null || string.IsNullOrEmpty(shortname) || amount <= 0) return;
AddToStats(player.userID, shortname, amount);
}
#endregion
#region Loot
private void OnItemRemovedFromContainer(ItemContainer container, Item item) {
ulong id = 0U;
if (container.entityOwner != null) id = container.entityOwner.OwnerID;
else if (container.playerOwner != null) id = container.playerOwner.userID;
if (!Looters.ContainsKey(item.uid)) Looters.Add(item.uid, id);
}
private void CanMoveItem(Item item, PlayerInventory playerLoot, uint targetContainer, int targetSlot, int amount) {
if (item == null || playerLoot == null) return;
var player = playerLoot.GetComponent<BasePlayer>();
if (player == null) return;
if (!(item.GetRootContainer()?.entityOwner is LootContainer)) return;
if (targetContainer == 0 && targetSlot == -1) AddToStats(player.userID, item.info.shortname, item.amount);
}
private void OnItemPickup(Item item, BasePlayer player) {
if (item == null || player == null) return;
if (Looters.ContainsKey(item.uid)) {
if (Looters[item.uid] != player.userID) {
AddToStats(player.userID, item.info.shortname, item.amount);
Looters.Remove(item.uid);
}
}
else {
Looters.Add(item.uid, player.userID);
}
}
#endregion
#region Entity Death
private readonly Dictionary<uint, BasePlayer> _lastHeli = new Dictionary<uint, BasePlayer>();
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
var helicopter = entity as BaseHelicopter;
if (helicopter != null && helicopter.net != null && info.InitiatorPlayer != null) _lastHeli[helicopter.net.ID] = info.InitiatorPlayer;
var player = entity as BasePlayer;
if (player == null) return;
var initiatorPlayer = info.InitiatorPlayer;
if (initiatorPlayer == null || player == initiatorPlayer) return;
var data = GetPlayerData(initiatorPlayer.userID);
if (data == null) return;
var clan = FindClanByID(initiatorPlayer.userID);
if (clan == null) return;
if (!data.FriendlyFire && clan.IsMember(player.userID)) {
info.damageTypes.ScaleAll(0);
Reply(player, CannotDamage);
}
if (!data.AllyFriendlyFire && clan.Alliances.Select(FindClanByTag).Any(x => x.IsMember(player.userID))) {
info.damageTypes.ScaleAll(0);
Reply(player, AllyCannotDamage);
}
}
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
if (entity == null || info == null) return;
if (entity is BaseHelicopter) {
if (_lastHeli.ContainsKey(entity.net.ID)) {
var basePlayer = _lastHeli[entity.net.ID];
if (basePlayer != null) AddToStats(basePlayer.userID, "helicopter");
}
return;
}
var player = info.InitiatorPlayer;
if (player == null) return;
if (entity is BradleyAPC) AddToStats(player.userID, "bradley");
else if (entity.name.Contains("barrel")) AddToStats(player.userID, "barrel");
else if (_config.ScoreTable.ContainsKey(entity.ShortPrefabName)) AddToStats(player.userID, entity.ShortPrefabName);
}
#endregion
#endregion
#region Skins
private void OnItemAddedToContainer(ItemContainer container, Item item) {
if (container == null || item == null) return;
var player = container.GetOwnerPlayer();
if (player == null) return;
var clan = FindClanByID(player.userID);
if (clan == null) return;
if (_config.Skins.ItemSkins.ContainsKey(item.info.shortname) && clan.Skins.ContainsKey(item.info.shortname)) {
var skin = clan.Skins[item.info.shortname];
if (item.info.category == ItemCategory.Attire) {
if (container == player.inventory.containerWear) ApplySkinToItem(item, skin);
}
else {
ApplySkinToItem(item, skin);
}
}
if (Looters.ContainsKey(item.uid)) {
if (container.playerOwner != null) if (Looters[item.uid] != container.playerOwner.userID) {
AddToStats(player.userID, item.info.shortname, item.amount);
Looters.Remove(item.uid);
}
}
else if (container.playerOwner != null) {
Looters.Add(item.uid, container.playerOwner.userID);
}
}
#endregion
#region Team
private void OnTeamLeave(RelationshipManager.PlayerTeam team, BasePlayer player) {
if (team == null || player == null) return;
FindClanByID(player.userID)?.Kick(player.userID);
}
private void OnTeamKick(RelationshipManager.PlayerTeam team, BasePlayer player, ulong target) {
if (team == null || player == null) return;
FindClanByID(player.userID)?.Kick(target);
}
private void OnTeamInvite(BasePlayer inviter, BasePlayer target) {
if (inviter == null || target == null) return;
SendInvite(inviter, target.userID);
}
private void OnTeamPromote(RelationshipManager.PlayerTeam team, BasePlayer newLeader) {
if (team == null || newLeader == null) return;
FindClanByID(team.teamLeader)?.SetLeader(newLeader.userID);
}
#endregion
#endregion
#region Commands
private void CmdClans(IPlayer cov, string command, string[] args) {
var player = cov?.Object as BasePlayer;
if (player == null) return;
if (args.Length == 0) {
MainUi(player, First : true);
return;
}
switch (args[0]) {
case "create" : {
if (args.Length < 2) {
SendReply(player, $"Error syntax! Use: /{command} {args[0]} <clan tag>");
return;
}
if (_config.PermissionSettings.UseClanCreating && !string.IsNullOrEmpty(_config.PermissionSettings.ClanCreating) && !permission.UserHasPermission(player.UserIDString, _config.PermissionSettings.ClanCreating)) {
Reply(player, NoPermCreateClan);
return;
}
if (PlayerHasClan(player.userID)) {
Reply(player, AlreadyClanMember);
return;
}
var tag = string.Join(" ", args.Skip(1));
if (string.IsNullOrEmpty(tag) || tag.Length < _config.TagMin || tag.Length > _config.TagMax) {
Reply(player, ClanTagLimit, _config.TagMin, _config.TagMax);
return;
}
tag = tag.Replace(" ", "");
if (_config.BlockedWords.Exists(word => tag.Contains(word, CompareOptions.OrdinalIgnoreCase))) {
Reply(player, ContainsForbiddenWords);
return;
}
var clan = Find
// ... [Code preview truncated due to length. Full source in attached file] ...