C#:
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using System.Linq;
namespace Oxide.Plugins
{
[Info("ClanLoadouts", "k1lly0u", "0.1.0", ResourceId = 0)]
class ClanLoadouts : RustPlugin
{
#region Fields
private StoredData storedData;
private DynamicConfigFile data;
[PluginReference] Plugin Clans;
private static ClanLoadouts ins;
private Dictionary<string, string> shortnameToDisplayname = new Dictionary<string, string>();
private Dictionary<string, string> displaynameToShortname = new Dictionary<string, string>();
#endregion
#region Oxide Hooks
private void Loaded()
{
data = Interface.Oxide.DataFileSystem.GetFile("clanloadout_data");
lang.RegisterMessages(Messages, this);
}
private void OnServerInitialized()
{
ins = this;
LoadData();
foreach (string shortname in configData.Items)
{
ItemDefinition itemDefinition = ItemManager.FindItemDefinition(shortname);
if (itemDefinition == null)
{
PrintError($"The item shortname '{shortname}' is invalid.Please check your config");
continue;
}
shortnameToDisplayname.Add(shortname, itemDefinition.displayName.english);
displaynameToShortname.Add(itemDefinition.displayName.english, shortname);
}
}
private void OnPlayerRespawned(BasePlayer player)
{
string tag = GetClanTag(player.userID);
if (string.IsNullOrEmpty(tag))
return;
if (storedData.ClanHasData(tag))
timer.In(1f, () => storedData.OnPlayerSpawned(player, tag));
}
private void OnServerSave() => SaveData();
private void Unload()
{
ins = null;
}
#endregion
#region Functions
private string GetClanTag(ulong playerId) => (string)Clans?.Call("GetClanOf", playerId) ?? string.Empty;
private JObject GetClanData(string tag) => (JObject)Clans?.Call("GetClan", tag) ?? null;
private bool IsValidTag(string tag) => Clans?.Call("GetClan", tag) != null;
private bool IsClanOwner(string tag, ulong playerId)
{
JObject clan = GetClanData(tag);
if (clan == null)
return false;
return clan["owner"].ToString() == playerId.ToString();
}
private void UpdateItem(BasePlayer player, string shortname, ulong skinId)
{
Item item = player.inventory.containerWear.FindItemsByItemName(shortname);
if (item != null)
{
item.skin = skinId;
item.MarkDirty();
BaseEntity heldEntity = item.GetHeldEntity();
if (heldEntity != null)
{
heldEntity.skinID = skinId;
heldEntity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
}
int slot = item.position;
item.SetParent(null);
item.MarkDirty();
timer.Once(0.15f, () =>
{
if (item == null)
return;
item.SetParent(player.inventory.containerWear);
item.position = slot;
item.MarkDirty();
});
}
}
#endregion
#region Commands
[ChatCommand("cskin")]
private void cmdLoadout(BasePlayer player, string command, string[] args)
{
string tag = GetClanTag(player.userID);
if (string.IsNullOrEmpty(tag))
{
SendReply(player, msg("Error.NotClanOwner", player.userID));
return;
}
if (!IsClanOwner(tag, player.userID))
{
SendReply(player, msg("Error.NotClanOwner", player.userID));
return;
}
if (configData.RequirePermission && !storedData.ClanHasData(tag))
{
SendReply(player, msg("Error.NoPermission", player.userID));
return;
}
if (args.Length == 0)
{
SendReply(player, msg("Help.Command1", player.userID));
string str = msg("Text.AvailableItems", player.userID);
foreach (var item in shortnameToDisplayname)
str += $"\n <color=#55aaff>{item.Value}</color> <color=#A5A5A5>({item.Key}) - </color><color=#55aaff>{storedData.GetSkin(tag, item.Key)}</color>";
SendReply(player, str);
return;
}
switch (args[0].ToLower())
{
case "set":
if (args.Length == 3)
{
string shortname = string.Empty;
if (shortnameToDisplayname.ContainsKey(args[1]))
shortname = args[1];
else if (displaynameToShortname.ContainsKey(args[1]))
shortname = displaynameToShortname[args[1]];
else
{
SendReply(player, string.Format(msg("Error.InvalidType", player.userID), args[1]));
return;
}
ulong skinId;
if (!ulong.TryParse(args[2], out skinId))
{
SendReply(player, string.Format(msg("Error.InvalidSkin", player.userID), args[2]));
return;
}
storedData.SetSkin(tag, shortname, skinId);
SendReply(player, string.Format(msg("Success.SkinSet", player.userID), shortnameToDisplayname[shortname], skinId));
}
else
{
SendReply(player, msg("Error.InvalidSyntax", player.userID));
return;
}
return;
case "setnow":
List<Item> items = player.inventory.containerWear.itemList;
List<string> results = new List<string>();
foreach (var itemStr in shortnameToDisplayname)
{
Item item = items.Find(x => x.info.shortname == itemStr.Key);
if (item != null)
{
storedData.SetSkin(tag, itemStr.Key, item.skin);
results.Add(itemStr.Value);
}
}
if (results.Count == 0)
SendReply(player, msg("Error.InvalidItems", player.userID));
else SendReply(player, string.Format(msg("Success.SkinSetNow", player.userID), results.ToSentence()));
return;
case "clear":
storedData.WipeClan(tag);
SendReply(player, msg("Success.Clear", player.userID));
return;
default:
SendReply(player, msg("Error.InvalidSyntax", player.userID));
break;
}
}
[ConsoleCommand("cskin")]
private void ccmdLoadout(ConsoleSystem.Arg arg)
{
if (arg.Connection != null)
return;
if (!configData.RequirePermission)
{
SendReply(arg, "You currently have the config set to ignore permission.All clans can use cskins");
return;
}
if (arg.Args == null || arg.Args.Length == 0)
{
SendReply(arg, "cskin add <tag> - Add a clan to the custom cskin list");
SendReply(arg, "cskin remove <tag> - Remove a clan from the custom cskin list");
SendReply(arg, "cskin wipe <tag> - Wipe the target clans selected skins");
SendReply(arg, "cskin list - List all clans registered for custom cskins");
return;
}
if (arg.GetString(0).ToLower() == "list")
{
string str = "Registered Clans;";
foreach (string tag in storedData.clanData.Keys)
str += $"\n- {tag}";
SendReply(arg, str);
return;
}
else
{
if (arg.Args.Length == 2)
{
string tag = arg.GetString(1);
if (!IsValidTag(tag))
{
SendReply(arg, $"The tag {tag} is not a valid clan tag");
return;
}
switch (arg.GetString(0).ToLower())
{
case "add":
SendReply(arg, storedData.AddClan(tag));
return;
case "remove":
SendReply(arg, storedData.RemoveClan(tag));
return;
case "wipe":
SendReply(arg, storedData.WipeClan(tag));
return;
default:
SendReply(arg, "Invalid Syntax! Type 'cskin' to see available commands");
return;
}
}
}
}
#endregion
#region Config
private ConfigData configData;
private class ConfigData
{
[JsonProperty(PropertyName = "Default items (shortnames)")]
public string[] Items { get; set; }
[JsonProperty(PropertyName = "Manually approve clans to use")]
public bool RequirePermission { get; set; }
public Oxide.Core.VersionNumber Version { get; set; }
}
protected override void LoadConfig()
{
base.LoadConfig();
configData = Config.ReadObject<ConfigData>();
if (configData.Version < Version)
UpdateConfigValues();
Config.WriteObject(configData, true);
}
protected override void LoadDefaultConfig() => configData = GetBaseConfig();
private ConfigData GetBaseConfig()
{
return new ConfigData
{
Items = new string[] { "shoes.boots", "pants", "hoodie" },
RequirePermission = false,
Version = Version
};
}
protected override void SaveConfig() => Config.WriteObject(configData, true);
private void UpdateConfigValues()
{
PrintWarning("Config update detected! Updating config values...");
configData.Version = Version;
PrintWarning("Config update completed!");
}
#endregion
#region Data Management
private void SaveData() => data.WriteObject(storedData);
private void LoadData()
{
try
{
storedData = data.ReadObject<StoredData>();
}
catch
{
storedData = new StoredData();
}
}
private class StoredData
{
public Hash<string, ClanData> clanData = new Hash<string, ClanData>();
public List<string> approvedClans = new List<string>();
public string AddClan(string tag)
{
tag = tag.ToUpper();
if (clanData.ContainsKey(tag))
return $"The clan {tag} is already registered";
if (!approvedClans.Contains(tag))
approvedClans.Add(tag);
clanData[tag] = new ClanData();
return $"The clan {tag} can now customise their spawn skins";
}
public string RemoveClan(string tag)
{
tag = tag.ToUpper();
if (!clanData.ContainsKey(tag))
return $"The clan {tag} is not registered";
if (approvedClans.Contains(tag))
approvedClans.Remove(tag);
clanData.Remove(tag);
return $"The clan {tag} can no longer customise their spawn skins";
}
public string WipeClan(string tag)
{
tag = tag.ToUpper();
ClanData data;
if (!clanData.TryGetValue(tag.ToUpper(), out data))
return $"The clan {tag} is not registered";
data.PopulateList();
return $"The clan {tag} can no longer customise their spawn skins";
}
public bool ClanHasData(string tag) => clanData.ContainsKey(tag.ToUpper());
public void OnPlayerSpawned(BasePlayer player, string tag)
{
if (player == null)
return;
ClanData data;
if (clanData.TryGetValue(tag.ToUpper(), out data))
data.GiveDefaultAttire(player);
}
public void SetSkin(string tag, string shortname, ulong skinId)
{
ClanData data;
if (clanData.TryGetValue(tag.ToUpper(), out data))
data.SetSkin(shortname, skinId);
else
{
clanData[tag] = new ClanData();
clanData[tag].SetSkin(shortname, skinId);
}
}
public string GetSkin(string tag, string shortname)
{
ClanData data;
if (clanData.TryGetValue(tag.ToUpper(), out data))
return data.itemSkins[shortname].ToString();
return string.Empty;
}
public class ClanData
{
public Hash<string, ulong> itemSkins = new Hash<string, ulong>();
public ClanData()
{
PopulateList();
}
public void SetSkin(string shortname, ulong skinId)
{
itemSkins[shortname] = skinId;
}
public void PopulateList()
{
foreach (string shortname in ins.configData.Items)
itemSkins[shortname] = 0UL;
}
public void GiveDefaultAttire(BasePlayer player)
{
for (int i = 0; i < itemSkins.Count; i++)
{
KeyValuePair<string, ulong> data = itemSkins.ElementAt(i);
if (data.Value == 0UL || !ins.configData.Items.Contains(data.Key))
continue;
Item item = ItemManager.CreateByName(data.Key, 1, data.Value);
item.MoveToContainer(player.inventory.containerWear);
}
}
}
}
#endregion
#region Localization
private string msg(string key, ulong playerId = 0UL) => lang.GetMessage(key, this, playerId == 0UL ? null : playerId.ToString());
private Dictionary<string, string> Messages = new Dictionary<string, string>
{
["Error.NotClanOwner"] = "You must be a clan owner to access this command",
["Error.NoPermission"] = "You do not have permission to use this command",
["Error.InvalidSyntax"] = "Invalid Syntax! Type '/cskin' to see available commands",
["Error.InvalidType"] = "'{0}' is a invalid shortname or displayname.Either type the target item shortname or display name as seen in the available items list",
["Error.InvalidSkin"] = "'{0}' is an invalid skin ID",
["Error.InvalidItems"] = "You are not wearing any valid items",
["Help.Command1"] = "Clan /cskin set \"shortname or display name\" <skin ID> - Set the skin for the specified item",
["Text.AvailableItems"] = "Available Items :",
["Success.SkinSet"] = "You have set your {0} skin to {1}",
["Success.SkinSetNow"] = "You have set skins for: {0}",
["Success.Clear"] = "You have set all your skins back to default"
};
#endregion
}
}