C#:
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Clans", "Shady", "1.9.4", ResourceId = 0 /*/842/*/
)] public class Clans : RustPlugin {
//originally by dcode.huge edits/additions/changes by me (Shady) seem worthy of changing authorship - includes (forced) team system integration
[PluginReference]
private readonly Plugin Compilation;
[PluginReference]
private readonly Plugin BanSystem;
[PluginReference]
private readonly Plugin Vanish;
[PluginReference]
private readonly Plugin Deathmatch;
private readonly Dictionary<string, float> _lastAttemptedInvite = new Dictionary<string, float>();
#region Rust:IO Bindings
public class Clan {
public string tag;
public string description;
public string owner;
public List<string> moderators = new List<string>();
public List<string> members = new List<string>();
public List<string> invited = new List<string>();
public static Clan Create(string tag, string description, string ownerId) {
var clan = new Clan() {
tag = tag, description = description, owner = ownerId
}
;
clan.members.Add(ownerId);
return clan;
}
public bool IsOwner(string userId) {
return userId == owner;
}
public bool IsModerator(string userId) {
return moderators.Contains(userId);
}
public bool IsMember(string userId) {
return members.Contains(userId);
}
public bool IsInvited(string userId) {
return invited.Contains(userId);
}
public void Broadcast(string message) {
if (string.IsNullOrEmpty(message)) throw new ArgumentNullException(nameof(message));
for (int i = 0; i < members.Count; i++) {
var memberId = members[i];
var player = BasePlayer.FindByID(Convert.ToUInt64(memberId));
if (player == null) continue;
player.SendConsoleCommand("chat.add", string.Empty, 0, "<color=#8ae6ff><size=10>[<size=12>Clan</size>]</size></color> " + message);
}
}
internal JObject ToJObject() {
var obj = new JObject();
obj["tag"] = tag;
obj["description"] = description;
obj["owner"] = owner;
var jmoderators = new JArray();
for (int i = 0; i < moderators.Count; i++) jmoderators.Add(moderators[i]);
obj["moderators"] = jmoderators;
var jmembers = new JArray();
for (int i = 0; i < members.Count; i++) jmembers.Add(members[i]);
obj["members"] = jmembers;
var jinvited = new JArray();
for (int i = 0; i < invited.Count; i++) jinvited.Add(invited[i]);
obj["invited"] = jinvited;
return obj;
}
internal void OnCreate() => Interface.CallHook("OnClanCreate", tag);
internal void OnUpdate() => Interface.CallHook("OnClanUpdate", tag);
internal void OnDestroy() => Interface.CallHook("OnClanDestroy", tag);
}
private Library lib;
private MethodInfo isInstalled;
private MethodInfo hasFriend;
private MethodInfo addFriend;
private MethodInfo deleteFriend;
internal static Clans Instance = null;
// FieldInfo displayName = typeof(BasePlayer).GetField("_displayName", (BindingFlags.Instance | BindingFlags.NonPublic));
private void ioInitialize() {
lib = Interface.Oxide.GetLibrary<Library>("RustIO");
if (lib == null || (isInstalled = lib.GetFunction("IsInstalled")) == null || (hasFriend = lib.GetFunction("HasFriend")) == null || (addFriend = lib.GetFunction("AddFriend")) == null || (deleteFriend = lib.GetFunction("DeleteFriend")) == null) {
lib = null;
Puts("{0}: {1}", Title, "Rust:IO is not present.You need to install Rust:IO first in order to use this plugin!");
}
}
private bool ioIsInstalled() {
if (lib == null) return false;
return (bool)isInstalled.Invoke(lib, new object[] {
}
);
}
private bool ioHasFriend(string playerId, string friendId) {
if (lib == null) return false;
return (bool)hasFriend.Invoke(lib, new object[] {
playerId, friendId
}
);
}
private bool ioAddFriend(string playerId, string friendId) {
if (lib == null) return false;
return (bool)addFriend.Invoke(lib, new object[] {
playerId, friendId
}
);
}
private bool ioDeleteFriend(string playerId, string friendId) {
if (lib == null) return false;
return (bool)deleteFriend.Invoke(lib, new object[] {
playerId, friendId
}
);
}
#endregion
private readonly Dictionary<string, Clan> clans = new Dictionary<string, Clan>();
private readonly Dictionary<string, string> originalNames = new Dictionary<string, string>();
private readonly Regex tagRe = new Regex("^[a-zA-Z0-9]{2,7}$");
private readonly Dictionary<string, string> messages = new Dictionary<string, string>();
private readonly Dictionary<string, Clan> lookup = new Dictionary<string, Clan>();
private bool addClanMatesAsFriends = true;
private int limitMembers = -1;
private int limitModerators = -1;
// Loads the data file
private void loadData() {
clans.Clear();
var data = Interface.Oxide.DataFileSystem.GetDatafile("rustio_clans");
if (data["clans"] != null) {
var clansData = (Dictionary<string, object>)Convert.ChangeType(data["clans"], typeof(Dictionary<string, object>));
var sb = new StringBuilder();
foreach (var iclan in clansData) {
string tag = iclan.Key;
var clanData = iclan.Value as Dictionary<string, object>;
string description = (string)clanData["description"];
string owner = (string)clanData["owner"];
List<string> moderators = new List<string>();
List<string> members = new List<string>();
List<string> invited = new List<string>();
var clanDataMods = clanData["moderators"] as List<object>;
var clanDataMembers = clanData["members"] as List<object>;
var clanDataInvited = clanData["invited"] as List<object>;
for (int i = 0; i < clanDataMods.Count; i++) {
moderators.Add((string)clanDataMods[i]);
}
for(int i = 0; i < clanDataMembers.Count; i++) {
members.Add((string)clanDataMembers[i]);
}
for(int i = 0; i < clanDataInvited.Count; i++) {
invited.Add((string)clanDataInvited[i]);
}
if (members?.Count < 1) {
sb.AppendLine("Found clan with < 1 member!! tag: " + tag + " - will try to add leader if exists");
if (!string.IsNullOrEmpty(owner)) {
// var added = false;
members.Add(owner);
sb.AppendLine("Successfully added leader to clan " + tag + " that was lacking any members");
}
else {
sb.AppendLine("Couldn't add anyone to clan withoue members: " + tag + " !!!");
continue;
}
}
Clan clan;
clans.Add(tag, clan = new Clan() {
tag = tag, description = description, owner = owner, moderators = moderators, members = members, invited = invited
}
);
lookup[owner] = clan;
for (int i = 0; i < members.Count; i++) lookup[members[i]] = clan;
}
if (sb.Length > 0) PrintWarning(sb.ToString().TrimEnd());
}
}
// Saves the data file
private void saveData() {
var data = Interface.Oxide.DataFileSystem.GetDatafile("rustio_clans");
var clansData = new Dictionary<string, object>();
foreach (var clan in clans) {
var clanData = new Dictionary<string, object>();
clanData.Add("tag", clan.Value.tag);
clanData.Add("description", clan.Value.description);
clanData.Add("owner", clan.Value.owner);
var moderators = new List<object>();
var members = new List<object>();
var invited = new List<object>();
for (int i = 0; i < clan.Value.moderators.Count; i++) {
var imoderator = clan.Value.moderators[i];
moderators.Add(imoderator);
}
for(int i = 0; i < clan.Value.members.Count; i++) {
members.Add(clan.Value.members[i]);
}
for(int i = 0; i < clan.Value.invited.Count; i++) {
invited.Add(clan.Value.invited[i]);
}
clanData.Add("moderators", moderators);
clanData.Add("members", members);
clanData.Add("invited", invited);
clansData.Add(clan.Value.tag, clanData);
}
data["clans"] = clansData;
Interface.Oxide.DataFileSystem.SaveDatafile("rustio_clans");
}
[HookMethod("Unload")]
private void Unload() {
saveData();
try {
if (ServerMgr.Instance != null && UpdateAllRoutine != null) ServerMgr.Instance.StopCoroutine(UpdateAllRoutine);
var disbanded = 0;
foreach (var kvp in clanToTeam) {
var team = kvp.Value;
if (team != null) {
DisbandTeam(team);
disbanded++;
}
}
PrintWarning("Disbanded " + disbanded.ToString("N0") + "/" + clanToTeam.Count.ToString("N0") + " teams on unload");
// Reset player names to originals
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
var player = BasePlayer.activePlayerList[i];
if (player == null) continue;
player.displayName = stripTag(player.displayName);
}
for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) {
var player = BasePlayer.sleepingPlayerList[i];
if (player == null || (player?.IsConnected ?? false)) continue;
player.displayName = stripTag(player.displayName);
}
/*/
foreach (var pair in originalNames)
{
var playerId = Convert.ToUInt64(pair.Key);
var player = BasePlayer.FindByID(playerId) ?? BasePlayer.FindSleeping(playerId);
var displayNamee = player?.displayName ?? string.Empty;
var IDString = player?.UserIDString ?? string.Empty;
if (displayNamee == "Shady" && IDString == "76561198028248023") continue;
if (player != null)
{
player.displayName = pair.Value;
if (player.IsConnected) player.SendNetworkUpdate();
}
}/*/
}
catch (Exception ex) {
error("Unload failed", ex);
}
}
// A list of all translateable texts
private readonly List<string> texts = new List<string>() {
"%NAME% has come online!", "%NAME% has gone offline.", "You are currently not a member of a clan.", "You are the owner of:", "You are a moderator of:", "You are a member of:", "Members online:", "Pending invites:", "To learn more about clans, type: <color=#ffd479>/clan help</color>", "Usage: <color=#ffd479>/clan create \"TAG\" \"Description\"</color>", "You are already a member of a clan.", "Clan tags must be 2 to 6 characters long and may contain standard letters and numbers only", "Please provide a short description of your clan.", "There is already a clan with this tag.", "You are now the owner of your new clan:", "To invite new members, type: <color=#ffd479>/clan invite \"Player name\"</color>", "Usage: <color=#ffd479>/clan invite \"Player name\"</color>", "You need to be a moderator of your clan to use this command.", "No such player or player name not unique:", "This player is already a member of your clan:", "This player is not a member of your clan:", "This player has already been invited to your clan:", "This player is already a moderator of your clan:", "This player is not a moderator of your clan:", "%MEMBER% invited %PLAYER% to the clan.", "Usage: <color=#ffd479>/clan join \"TAG\"</color>", "You have not been invited to join this clan.", "%NAME% has joined the clan!", "You have been invited to join the clan:", "To join, type: <color=#ffd479>/clan join \"%TAG%\"</color>", "This clan has already reached the maximum number of members.", "This clan has already reached the maximum number of moderators.", "Usage: <color=#ffd479>/clan promote \"Player name\"</color>", "You need to be the owner of your clan to use this command.", "%OWNER% promoted %MEMBER% to moderator.", "Usage: <color=#ffd479>/clan demote \"Player name\"</color>", "Usage: <color=#ffd479>/clan leave</color>", "You have left your current clan.", "%NAME% has left the clan.", "Usage: <color=#ffd479>/clan kick \"Player name\"</color>", "This player is an owner or moderator and cannot be kicked:", "%NAME% kicked %MEMBER% from the clan.", "Usage: <color=#ffd479>/clan disband forever</color>", "Your current clan has been disbanded forever.", "Usage: <color=#ffd479>/clan delete \"TAG\"</color>", "You need to be a server owner to delete clans.", "There is no clan with that tag:", "Your clan has been deleted by the server owner.", "You have deleted the clan:", "Available commands:", "<color=#ffd479>/clan</color> - Displays relevant information about your current clan", "<color=#ffd479>/c Message...</color> - Sends a message to all online clan members", "<color=#ffd479>/clan create \"TAG\" \"Description\"</color> - Creates a new clan you own", "<color=#ffd479>/clan join \"TAG\"</color> - Joins a clan you have been invited to", "<color=#ffd479>/clan leave</color> - Leaves your current clan", "<color=#74c6ff>Moderator</color> commands:", "<color=#ffd479>/clan invite \"Player name\"</color> - Invites a player to your clan", "<color=#ffd479>/clan kick \"Player name\"</color> - Kicks a member from your clan", "<color=#a1ff46>Owner</color> commands:", "<color=#ffd479>/clan promote \"Name\"</color> - Promotes a member to moderator", "<color=#ffd479>/clan demote \"Name\"</color> - Demotes a moderator to member", "<color=#ffd479>/clan disband forever</color> - Disbands your clan (no undo)", "<color=#cd422b>Server owner</color> commands:", "<color=#ffd479>/clan delete \"TAG\"</color> - Deletes a clan (no undo)", "<color=#ffd479>/clan</color> - Displays your current clan status", "<color=#ffd479>/clan help</color> - Learn how to create or join a clan"
}
;
// Loads the default configuration
protected override void LoadDefaultConfig() {
var messages = new Dictionary<string, object>();
for(int i = 0; i < texts.Count; i++) {
var text = texts[i];
if (messages.ContainsKey(text)) Puts("{0}: {1}", Title, "Duplicate translation string: " + text);
else messages.Add(text, text);
}
Config["messages"] = messages;
Config.Set("addClanMatesAsFriends", true);
Config.Set("limit", "members", -1);
Config.Set("limit", "moderators", -1);
}
// Translates a string
private string _(string text, Dictionary<string, string> replacements = null) {
if (messages.ContainsKey(text) && messages[text] != null) text = messages[text];
if (replacements != null) foreach (var replacement in replacements) text = text.Replace("%" + replacement.Key + "%", replacement.Value);
return text;
}
// Finds a clan by tag
private Clan findClan(string tag) {
if (string.IsNullOrEmpty(tag)) return null;
Clan clan;
if (clans.TryGetValue(tag, out clan) && clan != null) return clan;
//try to find by exact key name (case sensitive) first
foreach(var kvp in clans) {
if (kvp.Value.tag.Equals(tag, StringComparison.OrdinalIgnoreCase)) {
clan = kvp.Value;
break;
}
}
return clan;
// return clans?.Where(p => p.Value.tag.Equals(tag, StringComparison.OrdinalIgnoreCase))?.FirstOrDefault().Value ?? null;
/*/
Clan clan;
if (clans.TryGetValue(tag, out clan))
return clan;/*/
// return null;
}
// Finds a user's clan
private Clan findClanByUser(string userId) {
if (string.IsNullOrEmpty(userId)) return null;
Clan clan;
return lookup.TryGetValue(userId, out clan) ? clan : null;
}
private List<Clan> GetAllClansList() {
if (clans == null || clans.Count < 1) return null;
var clansList = new List<Clan>();
foreach (var kvp in clans) clansList.Add(kvp.Value);
return clansList;
}
private IPlayer FindClanPlayer(string nameOrIdOrIp, Clan clan) {
if (string.IsNullOrEmpty(nameOrIdOrIp)) throw new ArgumentNullException(nameof(nameOrIdOrIp));
if (clan == null) throw new ArgumentNullException(nameof(clan));
var members = clan?.members ?? null;
if ((members?.Count ?? 0) < 1) return null;
var foundMembers = Facepunch.Pool.GetList<IPlayer>();
try {
for (int i = 0; i < members.Count; i++) {
var member = members[i];
var player = covalence.Players?.FindPlayerById(member) ?? null;
if (player == null) continue;
var pName = player?.Name ?? string.Empty;
if ((player?.IsConnected ?? false) && player.Address == nameOrIdOrIp) {
// PrintWarning("connected && adddress == nameidip: " + nameOrIdOrIp);
foundMembers.Add(player);
}
else if (player.Id == nameOrIdOrIp) {
//PrintWarning("player.id == nameidip " + nameOrIdOrIp);
foundMembers.Add(player);
}
else if (pName.Equals(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase)) {
// PrintWarning("pname == nameidip: " + nameOrIdOrIp);
foundMembers.Add(player);
}
else if (pName.IndexOf(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase) >= 0) {
//PrintWarning("pname indexof nameidip: " + nameOrIdOrIp);
foundMembers.Add(player);
}
//if ((player?.IsConnected ?? false && player.Address == nameOrIdOrIp) || player.Id == nameOrIdOrIp || pName.Equals(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase) || pName.IndexOf(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase) >= 0) foundMembers.Add(player);
}
return foundMembers.Count == 1 ? foundMembers[0] : null;
}
finally {
Facepunch.Pool.FreeList(ref foundMembers);
}
}
private IPlayer FindClanPlayerByTag(string nameOrIdOrIp, string clan) {
if (string.IsNullOrEmpty(nameOrIdOrIp)) throw new ArgumentNullException(nameof(nameOrIdOrIp));
if (string.IsNullOrEmpty(clan)) throw new ArgumentNullException(nameof(clan));
return FindClanPlayer(nameOrIdOrIp, findClan(clan));
}
private IPlayer FindConnectedPlayer(string nameOrIdOrIp, bool tryFindOfflineIfNoOnline = false) {
if (string.IsNullOrEmpty(nameOrIdOrIp)) throw new ArgumentNullException(nameof(nameOrIdOrIp));
var p = covalence.Players.FindPlayerById(nameOrIdOrIp);
if (p != null) if ((!p.IsConnected && tryFindOfflineIfNoOnline) || p.IsConnected) return p;
var players = Facepunch.Pool.GetList<IPlayer>();
try {
var connected = covalence.Players.Connected;
foreach (var player in connected) {
if (players.Count > 1) break;
if (player.Name.Equals(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase)) players.Add(player);
else if (player.Address == nameOrIdOrIp) players.Add(player);
else if (player.Name.IndexOf(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase) >= 0) players.Add(player);
}
if (players.Count < 1 && tryFindOfflineIfNoOnline) {
foreach (var player in covalence.Players.All) {
if (player.IsConnected) continue;
if (players.Count > 1) break;
if (player.Name.Equals(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase)) players.Add(player);
else if (player.Name.IndexOf(nameOrIdOrIp, StringComparison.OrdinalIgnoreCase) >= 0) players.Add(player);
}
}
return players.Count == 1 ? players[0] : null;
}
finally {
Facepunch.Pool.FreeList(ref players);
}
}
// Strips the tag from a player's name
private string stripTag(string name, Clan clan = null) {
if (clan == null) {
Clan foundClan;
foreach(var kvp in clans) {
var val = kvp.Value;
if (name.Contains(val.tag)) {
foundClan = val;
break;
}
}
}
if (clan == null) return name;
var sb = Facepunch.Pool.Get<StringBuilder>();
try {
var re = new Regex(sb.Clear().Append(@"^\[").Append(clan.tag).Append(@"\]\s").ToString());
while (re.IsMatch(sb.ToString())) name = name.Substring(clan.tag.Length + 3);
return name;
}
finally {
Facepunch.Pool.Free(ref sb);
}
}
/*/
// Sets up a player to use the correct clan tag
private void setupPlayer(BasePlayer player)
{
// var prevName = player.displayName;
var playerId = player.UserIDString;
var clan = findClanByUser(playerId);
// if (player.displayName == "Shady" && playerId == "76561198028248023") return;
// player.displayName = stripTag(player.displayName, clan);
// displayName.SetValue(player, stripTag(player.displayName, clan));
// var originalName = string.Empty;
// if (!originalNames.ContainsKey(playerId)) originalNames.Add(playerId, originalName = player.displayName);
// else originalName = originalNames[playerId];
if (clan == null) player.displayName = originalName;
else
{
var tag = "[" + clan.tag + "]" + " ";
if (!player.displayName.StartsWith(tag)) player.displayName = tag + originalName;
}
// if (player.displayName != prevName) player.SendNetworkUpdate();
}
// Sets up all players contained in playerIds
private void setupPlayers(List<string> playerIds)
{
for(int i = 0; i < playerIds.Count; i++)
{
var playerId = playerIds[i];
var uid = Convert.ToUInt64(playerId);
var player = BasePlayer.FindByID(uid);
if (player != null)
setupPlayer(player);
else
{
player = BasePlayer.FindSleeping(uid);
if (player != null)
setupPlayer(player);
}
}
}/*/
[HookMethod("Init")]
private void Init() {
Instance = this;
AddCovalenceCommand(new string[] {
"clan", "clans", "klan", "klans"
}
, nameof(cmdChatClan));
var clansInfo = plugins.Find("ClansInfo");
if (clansInfo == null || !clansInfo.IsLoaded) {
covalence.Server.Command("o.load ClansInfo");
}
}
private readonly Dictionary<string, RelationshipManager.PlayerTeam> clanToTeam = new Dictionary<string, RelationshipManager.PlayerTeam>();
private System.Collections.IEnumerator UpdateAllClanTeams() {
var watch = Facepunch.Pool.Get<Stopwatch>();
try {
watch.Restart();
var sb = Facepunch.Pool.Get<StringBuilder>();
try {
PrintWarning(sb.Clear().Append("UpdateAllTeams() being called for: ").Append(clans.Count.ToString("N0")).Append(" clans").ToString());
foreach (var kvp in clans) {
UpdateClanTeam(kvp.Value);
if (Performance.report.frameRate < 60 && Performance.report.frameRateAverage >= 60) yield return CoroutineEx.waitForSeconds(0.025f);
else yield return CoroutineEx.waitForEndOfFrame;
}
watch.Stop();
PrintWarning(sb.Clear().Append("UpdateAllClanTeams() finished in ").Append(watch.Elapsed.TotalMilliseconds).Append("ms").ToString());
}
finally {
Facepunch.Pool.Free(ref sb);
}
}
finally {
Facepunch.Pool.Free(ref watch);
}
}
private void UpdateClanTeam(Clan clan) {
if (clan == null) throw new ArgumentNullException(nameof(clan));
if ((clan?.members?.Count ?? 0) < 1) {
PrintWarning("UpdateClanTeam called with no members!!! Clan tag: " + clan?.tag);
return;
}
var watch = Facepunch.Pool.Get<Stopwatch>();
try {
watch.Restart();
var ownerId = Convert.ToUInt64(clan.owner);
var ownerPly = RelationshipManager.FindByID(ownerId) ?? BasePlayer.FindByID(ownerId) ?? BasePlayer.FindSleeping(ownerId);
var lastIndex = RelationshipManager.ServerInstance.lastTeamIndex;
//(ulong)lastTeamIndex.GetValue(RelationshipManager.ServerInstance);
RelationshipManager.PlayerTeam newTeam = null;
RelationshipManager.PlayerTeam foundTeam = null;
for (int i = 0; i < clan.members.Count; i++) {
var c = clan.members[i];
var cID = Convert.ToUInt64(c);
var clanPly = BasePlayer.FindByID(cID) ?? BasePlayer.FindSleeping(cID);
if (clanPly == null) {
foreach(var team in RelationshipManager.ServerInstance.teams) {
var val = team.Value;
if (val == null) continue;
if ((val?.members?.Contains(cID) ?? false)) {
foundTeam = val;
//PrintWarning("found existing team from clan leader or a member, so we'll use it & just update (clanPly was null, but manual lookup succeeded)");
break;
}
}
}
else if (clanPly?.currentTeam != 0) {
var findTeam = RelationshipManager.ServerInstance.FindTeam(clanPly.currentTeam);
if (findTeam != null) {
foundTeam = findTeam;
//PrintWarning("found existing team from clan leader or a member, so we'll use it & just update");
break;
}
}
}
if (foundTeam != null) {
newTeam = foundTeam;
ClearTeamMembers(foundTeam, true);
}
var bumpIndex = lastIndex + 1;
if (newTeam == null) {
var findTeamWithIndex = RelationshipManager.ServerInstance.FindTeam(lastIndex);
if (findTeamWithIndex == null) findTeamWithIndex = RelationshipManager.ServerInstance.FindTeam(bumpIndex);
if (findTeamWithIndex != null) {
newTeam = findTeamWithIndex;
var oldCount = newTeam.members.Count;
ClearTeamMembers(newTeam);
var newCount = newTeam.members.Count;
PrintWarning("(" + ownerPly + ") FOUND existing team with lastIndex + 1, val: " + (lastIndex + 1) + ", before clear: " + oldCount + ", now: " + newCount);
}
else {
var createTeam = RelationshipManager.ServerInstance.CreateTeam();
if (createTeam.members.Count > 0) {
PrintWarning("createTeam for teamId: " + createTeam.teamID + " and owner: " + ownerId + " (" + ownerPly + ") had members upon creation, members: " + string.Join(" ", createTeam.members.Select(p => GetDisplayNameFromID(p.ToString()) + " (" + p + "), ")) + ", clearing!");
var loopMax = 5000;
var loopCount = 0;
while ((createTeam = RelationshipManager.ServerInstance.CreateTeam()).members.Count > 0) {
loopCount++;
if (loopCount >= loopMax) {
PrintWarning("yo dude we just called CreateTeam 5000 times and every time we had members in it already lol");
break;
}
}
if (createTeam.members.Count > 0) {
PrintWarning("members count is STILL > 0 after " + loopCount.ToString("N0") + " CreateTeam calls, now with Id: " + createTeam.teamID);
ClearTeamMembers(createTeam);
}
else PrintWarning("members.count was not > 0 after " + loopCount.ToString("N0") + " CreateTeam calls! :^)");
}
// else PrintWarning("it is truly a miracle.we did NOT have any members already in this team when we first created it.Thanks be to God");
newTeam = createTeam;
}
}
if (newTeam == null) {
PrintError("somehow newTeam is still null after all that, so something has gone really bad");
return;
}
newTeam.teamLeader = ownerId;
if (ownerPly != null) {
// PrintWarning("ownerPly was not null, so calling AddPlayer for: " + ownerPly + " for teamId: " + newTeam.teamID);
if (!newTeam.members.Contains(ownerId) && !newTeam.AddPlayer(ownerPly)) {
PrintWarning("COULD NOT ADD OWNER PLAYER, DID NOT EXIST IN TEAM MEMBERS BUT ALSO COULD NOT ADD.RETURNED FALSE ON BOOL!!! PLAYER: " + ownerPly + Environment.NewLine + " teamId: " + newTeam.teamID + ", member count: " + newTeam.members.Count + ", player.currentTeam: " + ownerPly.currentTeam + ", members.contains: " + newTeam.members.Contains(ownerPly.userID));
}
}
else {
AddPlayerToTeam(newTeam, ownerId);
}
if (clan.members.Count > 1) {
// PrintWarning("clan " + clan.tag + " has members count > 1, which means it isn't just the leader.going to add each team member, count: " + clan.members.Count + " for teamId: " + newTeam.teamID);
for (int i = 0; i < clan.members.Count; i++) {
var memberStr = clan.members[i];
var member = Convert.ToUInt64(memberStr);
if (member == ownerId) {
// PrintWarning("member == ownerId for clan: " + clan.tag + " and user: " + GetDisplayNameFromID(ownerId.ToString()) + " (" + ownerId + "), continuing");
continue;
}
var ply = RelationshipManager.FindByID(member) ?? BasePlayer.FindByID(member) ?? BasePlayer.FindSleeping(member);
if (ply != null && ply.currentTeam != 0 && ply.currentTeam != newTeam.teamID) {
var plyTeam = RelationshipManager.ServerInstance.FindTeam(ply.currentTeam);
if (plyTeam != null) RemovePlayerFromTeam(plyTeam, ply.userID);
// plyTeam.RemovePlayer(ply.userID);
ply.ClearTeam();
}
// PrintWarning("ADD CLAN MEM: " + GetDisplayNameFromID(memberStr) + " (" + memberStr + "), CLAN " + clan.tag + " TEAM: " + newTeam.teamID);
RelationshipManager.PlayerTeam tempTeam;
if (RelationshipManager.ServerInstance.playerToTeam.TryGetValue(member, out tempTeam) && tempTeam.teamID != newTeam.teamID) {
PrintWarning("playerToTeam on loop found member: " + member + " in another team.forcing to leave or disband");
if (tempTeam.members.Count < 2) DisbandTeam(tempTeam);
else RemovePlayerFromTeam(tempTeam, member);
//tempTeam.RemovePlayer(member);
}
if (!newTeam.members.Contains(member)) {
//PrintWarning("newTeam.members did not contain member: " + member + ", adding new member");
if (ply != null) newTeam.AddPlayer(ply);
else AddPlayerToTeam(newTeam, member);
//newTeam.members.Add(member);
}
}
}
newTeam.MarkDirty();
clanToTeam[clan.tag] = newTeam;
watch.Stop();
if (watch.Elapsed.TotalMilliseconds > 10) PrintWarning("UpdateClanTeam took: " + watch.Elapsed.TotalMilliseconds + "ms");
}
finally {
Facepunch.Pool.Free(ref watch);
}
}
private void OnClanUpdate(string tag) {
if (string.IsNullOrEmpty(tag)) throw new ArgumentNullException(nameof(tag));
var clan = findClan(tag);
if (clan?.members == null || clan.members.Count < 1) {
PrintWarning("OnClanUpdate has null members or < 1: " + tag);
return;
}
UpdateClanTeam(clan);
}
private void OnClanCreate(string tag) {
if (string.IsNullOrEmpty(tag)) throw new ArgumentNullException(nameof(tag));
var clan = findClan(tag);
if (clan?.members == null || clan.members.Count < 1) {
PrintWarning("OnClanCreate has null members or < 1: " + tag);
return;
}
UpdateClanTeam(clan);
}
private void OnClanDestroy(string tag) {
if (string.IsNullOrEmpty(tag)) throw new ArgumentNullException(nameof(tag));
RelationshipManager.PlayerTeam clanTeam;
if (clanToTeam.TryGetValue(tag, out clanTeam)) {
clanToTeam.Remove(tag);
if (clanTeam != null) DisbandTeam(clanTeam);
}
else PrintWarning("no clanToTeam on OnClanDestroy for: " + tag);
}
private void OnTeamLeave(RelationshipManager.PlayerTeam team, BasePlayer player) {
if (team == null || player == null) return;
var clanName = string.Empty;
foreach (var kvp in clanToTeam) {
if (kvp.Value == team) {
clanName = kvp.Key;
break;
}
}
if (string.IsNullOrEmpty(clanName)) return;
var clan = findClan(clanName);
if (clan == null) return;
var userId = player?.userID ?? 0;
var userIDStr = player?.UserIDString ?? string.Empty;
ServerMgr.Instance.Invoke(() => {
if (team?.members == null || !team.members.Contains(userId)) {
if (clan != null && clan.IsMember(userIDStr)) {
if (player != null && player.IsConnected) player.SendConsoleCommand("clan leave");
else {
clan.members.Remove(userIDStr);
lookup.Remove(userIDStr);
clan.OnUpdate();
}
}
}
}
, 0.25f);
}
private object OnTeamInvite(BasePlayer player, BasePlayer target) {
if (player == null || target == null) return null;
var clan = findClanByUser(player.UserIDString) ?? findClan(GetClanOf(player));
if (clan == null) {
PrintError("team invite attempted with a null clan!!!!! " + player + " " + target);
return null;
}
RelationshipManager.PlayerTeam team;
if (!clanToTeam.TryGetValue(clan.tag, out team)) {
PrintError("clanToTeam null for " + clan.tag + "!!!!");
return null;
}
var isVanish = Vanish?.Call<bool>("IsInvisible", player) ?? false;
if (isVanish) return null;
if (clan.IsMember(target.UserIDString)) return null;
var sb = Facepunch.Pool.Get<StringBuilder>();
try {
if (team.members.Count >= Mathf.Min(limitMembers, RelationshipManager.maxTeamSize)) {
SendReply(player, "Your team is already full!");
return true;
}
if (!team.invites.Contains(target.userID)) {
//avoid message spam?
team.invites.Add(target.userID);
SendReply(target, sb.Clear().Append(player.displayName).Append(" invited you to join their team.To join the team, join the ").Append(clan.tag).Append(" clan.You have been invited.").Append(Environment.NewLine).Append("<color=orange>/clan join \"").Append(clan.tag).Append("\"</color>").ToString());
SendReply(player, sb.Clear().Append("Sent clan invite to: ").Append(target.displayName).ToString());
player.SendConsoleCommand(sb.Clear().Append("clan invite \"").Append(target.displayName).Append("\"").ToString());
}
return true;
}
finally {
Facepunch.Pool.Free(ref sb);
}
}
private object OnServerCommand(ConsoleSystem.Arg arg) {
if (arg?.Connection == null) return null;
var command = arg?.cmd?.FullName ?? string.Empty;
if (command.IndexOf("trycreateteam", StringComparison.OrdinalIgnoreCase) >= 0) {
var player = arg?.Player() ?? null;
if (player != null && player.IsConnected) {
SendLocalEffect(player, "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab");
SendReply(player, "--<size=20><color=#4aff92>TEAMS</color></size>--\n<color=#df5eff>To create a team, you must make a <color=#ecff3d>clan</color></color>, <color=#ff3030>there are no longer teams without clans.<color=#97ff85>Upon creating a clan, you'll automatically be put into a team!</color> <color=#ff5ec4>:)</color></color>\n<color=#ff3da8>Type <color=#ecff3d>/clan</color> for more info</color>.");
}
return true;
}
return null;
}
private void OnTeamKick(RelationshipManager.PlayerTeam team, BasePlayer kicker, ulong targetId) {
if (team == null || kicker == null || targetId == 0) return;
var clanName = string.Empty;
foreach (var kvp in clanToTeam) {
if (kvp.Value == team) {
clanName = kvp.Key;
break;
}
}
if (string.IsNullOrEmpty(clanName)) return;
var clan = findClan(clanName);
if (clan == null) return;
var player = BasePlayer.FindByID(targetId) ?? BasePlayer.FindSleeping(targetId);
ServerMgr.Instance.Invoke(() => {
if (team?.members == null || !team.members.Contains(targetId)) {
var userIDStr = targetId.ToString();
if (clan != null && clan.IsMember(userIDStr)) {
if (player != null && player.IsConnected) player.SendConsoleCommand("clan leave");
else {
clan.members.Remove(userIDStr);
lookup.Remove(userIDStr);
clan.OnUpdate();
}
}
}
}
, 0.25f);
}
private void OnTeamPromote(RelationshipManager.PlayerTeam team, BasePlayer target) {
if (team == null || target == null) return;
var clanName = string.Empty;
foreach (var kvp in clanToTeam) {
if (kvp.Value == team) {
clanName = kvp.Key;
break;
}
}
if (string.IsNullOrEmpty(clanName)) return;
var clan = findClan(clanName);
if (clan == null) return;
var oldOwner = clan.owner;
if (target.UserIDString == oldOwner) {
PrintWarning("Somehow target userid is same as oldOwner on OnTeamPromote!");
return;
}
ServerMgr.Instance.Invoke(() => {
if (team == null || clan?.members == null || clan.members.Count < 1) return;
clan.owner = target.UserIDString;
if (!clan.moderators.Contains(oldOwner)) clan.moderators.Add(oldOwner);
clan.Broadcast(GetDisplayNameFromID(oldOwner) + " promoted " + target?.displayName + " to clan & team leader.");
}
, 0.1f);
}
private string GetDisplayNameFromID(string userID) {
if (string.IsNullOrEmpty(userID)) return string.Empty;
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
var p = BasePlayer.activePlayerList[i];
if (p?.UserIDString == userID) return p?.displayName;
}
for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) {
var p = BasePlayer.sleepingPlayerList[i];
if (p?.UserIDString == userID) return p?.displayName;
}
return covalence.Players.FindPlayerById(userID)?.Name ?? string.Empty;
//BasePlayer.activePlayerList?.Where(p => p != null && p.UserIDString == userID)?.FirstOrDefault()?.displayName ?? BasePlayer.sleepingPlayerList?.Where(p => p != null && p.UserIDString == userID)?.FirstOrDefault()?.displayName ?? string.Empty;
}
private Coroutine UpdateAllRoutine = null;
[HookMethod("OnServerInitialized")]
private void OnServerInitialized() {
try {
ioInitialize();
LoadConfig();
try {
var customMessages = Config.Get<Dictionary<string, object>>("messages");
if (customMessages != null) foreach (var pair in customMessages) messages[pair.Key] = (string)pair.Value;
}
catch (Exception ex2) {
PrintError(ex2.ToString());
warn("oxide/config/Clans.json seems to contain an invalid 'messages' structure.Please delete the config file once and reload the plugin.");
}
try {
loadData();
UpdateAllRoutine = ServerMgr.Instance.StartCoroutine(UpdateAllClanTeams());
//UpdateAllClanTeams();
}
catch(Exception ex) {
PrintError(ex.ToString());
}
// for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) setupPlayer(BasePlayer.activePlayerList[i]);
// for (int i = 0; i < BasePlayer.sleepingPlayerList.Count; i++) setupPlayer(BasePlayer.sleepingPlayerList[i]);
try {
addClanMatesAsFriends = Config.Get<bool>("addClanMatesAsFriends");
limitMembers = Config.Get<int>("limit", "members");
limitModerators = Config.Get<int>("limit", "moderators");
}
catch(Exception ex) {
PrintError(ex.ToString());
}
}
catch (Exception ex) {
error("OnServerInitialized failed", ex);
}
}
[HookMethod("OnUserApprove")]
private void OnUserApprove(Network.Connection connection) {
// Override whatever there is
originalNames[connection.userid.ToString()] = connection.u
// ... [Code preview truncated due to length. Full source in attached file] ...