Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6be6d61022 |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,953 +0,0 @@
|
||||
using Oxide.Plugins.BetterChatExtensions;
|
||||
using Oxide.Core.Libraries.Covalence;
|
||||
using Oxide.Core.Plugins;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
#if RUST
|
||||
using Network;
|
||||
using ConVar;
|
||||
using Facepunch;
|
||||
using Facepunch.Math;
|
||||
using CompanionServer;
|
||||
#endif
|
||||
|
||||
// TODO: Improve string usage by using stringbuilders
|
||||
// TODO: Add "name" or "identifier" format for third-party plugins to obtain a formatted identifier
|
||||
|
||||
namespace Oxide.Plugins
|
||||
{
|
||||
[Info("Better Chat", "LaserHydra", "5.2.5")]
|
||||
[Description("Allows to manage chat groups, customize colors and add titles.")]
|
||||
internal class BetterChat : CovalencePlugin
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private static BetterChat _instance;
|
||||
|
||||
private Configuration _config;
|
||||
private List<ChatGroup> _chatGroups;
|
||||
private Dictionary<Plugin, Func<IPlayer, string>> _thirdPartyTitles = new Dictionary<Plugin, Func<IPlayer, string>>();
|
||||
|
||||
private static readonly string[] _stringReplacements = new string[]
|
||||
{
|
||||
#if RUST || HURTWORLD || UNTURNED
|
||||
"<b>", "</b>",
|
||||
"<i>", "</i>",
|
||||
"</size>",
|
||||
"</color>"
|
||||
#endif
|
||||
};
|
||||
|
||||
private static readonly Regex[] _regexReplacements = new Regex[]
|
||||
{
|
||||
new Regex(@"<voffset=(?:.|\s)*?>", RegexOptions.Compiled),
|
||||
#if RUST || HURTWORLD || UNTURNED
|
||||
new Regex(@"<color=.+?>", RegexOptions.Compiled),
|
||||
new Regex(@"<size=.+?>", RegexOptions.Compiled),
|
||||
#elif REIGNOFKINGS || SEVENDAYSTODIE
|
||||
new Regex(@"\[[\w\d]{6}\]", RegexOptions.Compiled),
|
||||
#elif RUSTLEGACY
|
||||
new Regex(@"\[color #[\w\d]{6}\]", RegexOptions.Compiled),
|
||||
#elif TERRARIA
|
||||
new Regex(@"\[c\/[\w\d]{6}:", RegexOptions.Compiled),
|
||||
#endif
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hooks
|
||||
|
||||
private void Loaded()
|
||||
{
|
||||
_instance = this;
|
||||
|
||||
LoadData(ref _chatGroups);
|
||||
|
||||
if (_chatGroups.Count == 0)
|
||||
_chatGroups.Add(new ChatGroup("default"));
|
||||
|
||||
foreach (ChatGroup group in _chatGroups)
|
||||
{
|
||||
if (!permission.GroupExists(group.GroupName))
|
||||
permission.CreateGroup(group.GroupName, string.Empty, 0);
|
||||
}
|
||||
|
||||
SaveData(_chatGroups);
|
||||
}
|
||||
|
||||
private void OnPluginUnloaded(Plugin plugin)
|
||||
{
|
||||
if (_thirdPartyTitles.ContainsKey(plugin))
|
||||
_thirdPartyTitles.Remove(plugin);
|
||||
}
|
||||
|
||||
#if RUST
|
||||
private object OnPlayerChat(BasePlayer bplayer, string message, Chat.ChatChannel chatchannel)
|
||||
{
|
||||
IPlayer player = bplayer.IPlayer;
|
||||
#else
|
||||
private object OnUserChat(IPlayer player, string message)
|
||||
{
|
||||
#endif
|
||||
if (message.Length > _instance._config.MaxMessageLength)
|
||||
message = message.Substring(0, _instance._config.MaxMessageLength);
|
||||
|
||||
BetterChatMessage chatMessage = ChatGroup.FormatMessage(player, message);
|
||||
|
||||
if (chatMessage == null)
|
||||
return null;
|
||||
|
||||
Dictionary<string, object> chatMessageDict = chatMessage.ToDictionary();
|
||||
#if RUST
|
||||
chatMessageDict.Add("ChatChannel", chatchannel);
|
||||
#endif
|
||||
foreach (Plugin plugin in plugins.GetAll())
|
||||
{
|
||||
object hookResult = plugin.CallHook("OnBetterChat", chatMessageDict);
|
||||
|
||||
if (hookResult is Dictionary<string, object>)
|
||||
{
|
||||
try
|
||||
{
|
||||
chatMessageDict = hookResult as Dictionary<string, object>;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
PrintError($"Failed to load modified OnBetterChat hook data from plugin '{plugin.Title} ({plugin.Version})':{Environment.NewLine}{e}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (hookResult != null)
|
||||
return null;
|
||||
}
|
||||
|
||||
chatMessage = BetterChatMessage.FromDictionary(chatMessageDict);
|
||||
|
||||
switch (chatMessage.CancelOption)
|
||||
{
|
||||
case BetterChatMessage.CancelOptions.BetterChatOnly:
|
||||
return null;
|
||||
|
||||
case BetterChatMessage.CancelOptions.BetterChatAndDefault:
|
||||
return true;
|
||||
}
|
||||
|
||||
var output = chatMessage.GetOutput();
|
||||
|
||||
#if RUST
|
||||
switch (chatchannel)
|
||||
{
|
||||
case Chat.ChatChannel.Team:
|
||||
RelationshipManager.PlayerTeam team = bplayer.Team;
|
||||
if (team == null || team.members.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
team.BroadcastTeamChat(bplayer.userID, player.Name, chatMessage.Message, chatMessage.UsernameSettings.Color);
|
||||
|
||||
List<Network.Connection> onlineMemberConnections = team.GetOnlineMemberConnections();
|
||||
if (onlineMemberConnections != null)
|
||||
{
|
||||
ConsoleNetwork.SendClientCommand(onlineMemberConnections, "chat.add", new object[] { (int) chatchannel, player.Id, output.Chat });
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
foreach (BasePlayer p in BasePlayer.activePlayerList.Where(p => !chatMessage.BlockedReceivers.Contains(p.UserIDString)))
|
||||
p.SendConsoleCommand("chat.add", new object[] { (int) chatchannel, player.Id, output.Chat });
|
||||
break;
|
||||
}
|
||||
#else
|
||||
foreach (IPlayer p in players.Connected.Where(p => !chatMessage.BlockedReceivers.Contains(p.Id)))
|
||||
p.Message(output.Chat);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if RUST
|
||||
Puts($"[{chatchannel}] {output.Console}");
|
||||
|
||||
RCon.Broadcast(RCon.LogType.Chat, new Chat.ChatEntry
|
||||
{
|
||||
Channel = chatchannel,
|
||||
Message = output.Console,
|
||||
UserId = player.Id,
|
||||
Username = player.Name,
|
||||
Color = chatMessage.UsernameSettings.Color,
|
||||
Time = Epoch.Current
|
||||
});
|
||||
#else
|
||||
Puts(output.Console);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region API
|
||||
|
||||
private bool API_AddGroup(string group)
|
||||
{
|
||||
if (ChatGroup.Find(group) != null)
|
||||
return false;
|
||||
|
||||
_chatGroups.Add(new ChatGroup(group));
|
||||
SaveData(_chatGroups);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<JObject> API_GetAllGroups() => _chatGroups.ConvertAll(JObject.FromObject);
|
||||
|
||||
private List<JObject> API_GetUserGroups(IPlayer player) => ChatGroup.GetUserGroups(player).ConvertAll(JObject.FromObject);
|
||||
|
||||
private bool API_GroupExists(string group) => ChatGroup.Find(group) != null;
|
||||
|
||||
private ChatGroup.Field.SetValueResult? API_SetGroupField(string group, string field, string value) => ChatGroup.Find(group)?.SetField(field, value);
|
||||
|
||||
private Dictionary<string, object> API_GetGroupFields(string group) => ChatGroup.Find(group)?.GetFields() ?? new Dictionary<string, object>();
|
||||
|
||||
private Dictionary<string, object> API_GetMessageData(IPlayer player, string message) => ChatGroup.FormatMessage(player, message)?.ToDictionary();
|
||||
|
||||
private string API_GetFormattedUsername(IPlayer player)
|
||||
{
|
||||
var primary = ChatGroup.GetUserPrimaryGroup(player);
|
||||
|
||||
// Player has no groups - this should never happen
|
||||
if (primary == null)
|
||||
return player.Name;
|
||||
|
||||
return $"[#{primary.Username.GetUniversalColor()}][+{primary.Username.Size}]{player.Name}[/+][/#]";
|
||||
}
|
||||
|
||||
private string API_GetFormattedMessage(IPlayer player, string message, bool console = false) => console ? ChatGroup.FormatMessage(player, message).GetOutput().Console : ChatGroup.FormatMessage(player, message).GetOutput().Chat;
|
||||
|
||||
private void API_RegisterThirdPartyTitle(Plugin plugin, Func<IPlayer, string> titleGetter) => _thirdPartyTitles[plugin] = titleGetter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
[Command("chat"), Permission("betterchat.admin")]
|
||||
private void CmdChat(IPlayer player, string cmd, string[] args)
|
||||
{
|
||||
cmd = player.LastCommand == CommandType.Console ? cmd : $"/{cmd}";
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
player.Reply($"{cmd} group <add|remove|set|list>");
|
||||
player.Reply($"{cmd} user <add|remove>");
|
||||
return;
|
||||
}
|
||||
|
||||
string argsStr = string.Join(" ", args);
|
||||
|
||||
var commands = new Dictionary<string, Action<string[]>>
|
||||
{
|
||||
["group add"] = a => {
|
||||
if (a.Length != 1)
|
||||
{
|
||||
player.Reply($"Syntax: {cmd} group add <group>");
|
||||
return;
|
||||
}
|
||||
|
||||
string groupName = a[0].ToLower();
|
||||
|
||||
if (ChatGroup.Find(groupName) != null)
|
||||
{
|
||||
player.ReplyLang("Group Already Exists", new KeyValuePair<string, string>("group", groupName));
|
||||
return;
|
||||
}
|
||||
|
||||
ChatGroup group = new ChatGroup(groupName);
|
||||
|
||||
_chatGroups.Add(group);
|
||||
|
||||
if (!permission.GroupExists(group.GroupName))
|
||||
permission.CreateGroup(group.GroupName, string.Empty, 0);
|
||||
|
||||
SaveData(_chatGroups);
|
||||
|
||||
player.ReplyLang("Group Added", new KeyValuePair<string, string>("group", groupName));
|
||||
},
|
||||
["group remove"] = a => {
|
||||
if (a.Length != 1)
|
||||
{
|
||||
player.Reply($"Syntax: {cmd} group remove <group>");
|
||||
return;
|
||||
}
|
||||
|
||||
string groupName = a[0].ToLower();
|
||||
ChatGroup group = ChatGroup.Find(groupName);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
|
||||
return;
|
||||
}
|
||||
|
||||
_chatGroups.Remove(group);
|
||||
SaveData(_chatGroups);
|
||||
|
||||
player.ReplyLang("Group Removed", new KeyValuePair<string, string>("group", groupName));
|
||||
},
|
||||
["group set"] = a => {
|
||||
if (a.Length != 3)
|
||||
{
|
||||
player.Reply($"Syntax: {cmd} group set <group> <field> <value>");
|
||||
player.Reply($"Fields:{Environment.NewLine}{string.Join(", ", ChatGroup.Fields.Select(kvp => $"({kvp.Value.UserFriendyType}) {kvp.Key}").ToArray())}");
|
||||
return;
|
||||
}
|
||||
|
||||
string groupName = a[0].ToLower();
|
||||
ChatGroup group = ChatGroup.Find(groupName);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
|
||||
return;
|
||||
}
|
||||
|
||||
string field = a[1];
|
||||
string strValue = a[2];
|
||||
|
||||
switch (group.SetField(field, strValue))
|
||||
{
|
||||
case ChatGroup.Field.SetValueResult.Success:
|
||||
SaveData(_chatGroups);
|
||||
player.ReplyLang("Group Field Changed", new Dictionary<string, string> { ["group"] = group.GroupName, ["field"] = field, ["value"] = strValue });
|
||||
break;
|
||||
|
||||
case ChatGroup.Field.SetValueResult.InvalidField:
|
||||
player.ReplyLang("Invalid Field", new KeyValuePair<string, string>("field", field));
|
||||
break;
|
||||
|
||||
case ChatGroup.Field.SetValueResult.InvalidValue:
|
||||
player.ReplyLang("Invalid Value", new Dictionary<string, string> { ["field"] = field, ["value"] = strValue, ["type"] = ChatGroup.Fields[field].UserFriendyType });
|
||||
break;
|
||||
}
|
||||
},
|
||||
["group list"] = a =>
|
||||
{
|
||||
player.Reply(string.Join(", ", _chatGroups.Select(g => g.GroupName).ToArray()));
|
||||
},
|
||||
["group"] = a => player.Reply($"Syntax: {cmd} group <add|remove|set|list>"),
|
||||
["user add"] = a => {
|
||||
if (a.Length != 2)
|
||||
{
|
||||
player.Reply($"Syntax: {cmd} user add <username|id> <group>");
|
||||
return;
|
||||
}
|
||||
|
||||
string response;
|
||||
IPlayer targetPlayer = FindPlayer(a[0], out response);
|
||||
|
||||
if (targetPlayer == null)
|
||||
{
|
||||
player.Reply(response);
|
||||
return;
|
||||
}
|
||||
|
||||
string groupName = a[1].ToLower();
|
||||
ChatGroup group = ChatGroup.Find(groupName);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission.UserHasGroup(targetPlayer.Id, groupName))
|
||||
{
|
||||
player.ReplyLang("Player Already In Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
|
||||
return;
|
||||
}
|
||||
|
||||
group.AddUser(targetPlayer);
|
||||
player.ReplyLang("Added To Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
|
||||
},
|
||||
["user remove"] = a => {
|
||||
if (a.Length != 2)
|
||||
{
|
||||
player.Reply($"Syntax: {cmd} user remove <username|id> <group>");
|
||||
return;
|
||||
}
|
||||
|
||||
string response;
|
||||
IPlayer targetPlayer = FindPlayer(a[0], out response);
|
||||
|
||||
if (targetPlayer == null)
|
||||
{
|
||||
player.Reply(response);
|
||||
return;
|
||||
}
|
||||
|
||||
string groupName = a[1].ToLower();
|
||||
ChatGroup group = ChatGroup.Find(groupName);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
player.ReplyLang("Group Does Not Exist", new KeyValuePair<string, string>("group", groupName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!permission.UserHasGroup(targetPlayer.Id, groupName))
|
||||
{
|
||||
player.ReplyLang("Player Not In Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
|
||||
return;
|
||||
}
|
||||
|
||||
group.RemoveUser(targetPlayer);
|
||||
player.ReplyLang("Removed From Group", new Dictionary<string, string> { ["player"] = targetPlayer.Name, ["group"] = groupName });
|
||||
},
|
||||
["user"] = a => player.Reply($"Syntax: {cmd} user <add|remove>"),
|
||||
[string.Empty] = a =>
|
||||
{
|
||||
player.Reply($"{cmd} group <add|remove|set|list>");
|
||||
player.Reply($"{cmd} user <add|remove>");
|
||||
}
|
||||
};
|
||||
|
||||
var command = commands.First(c => argsStr.ToLower().StartsWith(c.Key));
|
||||
|
||||
string remainingArgs = argsStr.Remove(0, command.Key.Length);
|
||||
|
||||
command.Value(remainingArgs.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper and Wrapper Methods
|
||||
|
||||
#region Player Lookup
|
||||
|
||||
private IPlayer FindPlayer(string nameOrID, out string response)
|
||||
{
|
||||
response = null;
|
||||
|
||||
if (IsConvertableTo<string, ulong>(nameOrID) && nameOrID.StartsWith("7656119") && nameOrID.Length == 17)
|
||||
{
|
||||
IPlayer result = players.All.ToList().Find((p) => p.Id == nameOrID);
|
||||
|
||||
if (result == null)
|
||||
response = $"Could not find player with ID '{nameOrID}'";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
List<IPlayer> foundPlayers = new List<IPlayer>();
|
||||
|
||||
foreach (IPlayer current in players.Connected)
|
||||
{
|
||||
if (current.Name.ToLower() == nameOrID.ToLower())
|
||||
return current;
|
||||
|
||||
if (current.Name.ToLower().Contains(nameOrID.ToLower()))
|
||||
foundPlayers.Add(current);
|
||||
}
|
||||
|
||||
switch (foundPlayers.Count)
|
||||
{
|
||||
case 0:
|
||||
response = $"Could not find player with name '{nameOrID}'";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
return foundPlayers[0];
|
||||
|
||||
default:
|
||||
string[] names = (from current in foundPlayers select current.Name).ToArray();
|
||||
response = "Multiple matching players found: \n" + string.Join(", ", names);
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Type Conversion
|
||||
|
||||
private bool IsConvertableTo<TSource, TResult>(TSource s)
|
||||
{
|
||||
TResult result;
|
||||
return TryConvert(s, out result);
|
||||
}
|
||||
|
||||
private bool TryConvert<TSource, TResult>(TSource s, out TResult c)
|
||||
{
|
||||
try
|
||||
{
|
||||
c = (TResult)Convert.ChangeType(s, typeof(TResult));
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
c = default(TResult);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
private void LoadData<T>(ref T data, string filename = null) => data = Core.Interface.Oxide.DataFileSystem.ReadObject<T>(filename ?? Name);
|
||||
|
||||
private void SaveData<T>(T data, string filename = null) => Core.Interface.Oxide.DataFileSystem.WriteObject(filename ?? Name, data);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Formatting
|
||||
|
||||
private static string StripRichText(string text)
|
||||
{
|
||||
|
||||
|
||||
foreach (var replacement in _stringReplacements)
|
||||
text = text.Replace(replacement, string.Empty);
|
||||
|
||||
foreach (var replacement in _regexReplacements)
|
||||
text = replacement.Replace(text, string.Empty);
|
||||
|
||||
return Formatter.ToPlaintext(text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Message Wrapper
|
||||
|
||||
public static string GetMessage(string key, string id) => _instance.lang.GetMessage(key, _instance, id);
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Localization
|
||||
|
||||
protected override void LoadDefaultMessages()
|
||||
{
|
||||
lang.RegisterMessages(new Dictionary<string, string>
|
||||
{
|
||||
["Group Already Exists"] = "Group '{group}' already exists.",
|
||||
["Group Does Not Exist"] = "Group '{group}' doesn't exist.",
|
||||
["Group Field Changed"] = "Changed {field} to {value} for group '{group}'.",
|
||||
["Group Added"] = "Successfully added group '{group}'.",
|
||||
["Group Removed"] = "Successfully removed group '{group}'.",
|
||||
["Invalid Field"] = "{field} is not a valid field. Type 'chat group set' to list all existing fields.",
|
||||
["Invalid Value"] = "'{value}' is not a correct value for field '{field}'! Should be a '{type}'.",
|
||||
["Player Already In Group"] = "{player} already is in group '{group}'.",
|
||||
["Added To Group"] = "{player} was added to group '{group}'.",
|
||||
["Player Not In Group"] = "{player} is not in group '{group}'.",
|
||||
["Removed From Group"] = "{player} was removed from group '{group}'."
|
||||
}, this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Configuration
|
||||
|
||||
protected override void LoadConfig()
|
||||
{
|
||||
base.LoadConfig();
|
||||
_config = Config.ReadObject<Configuration>();
|
||||
SaveConfig();
|
||||
}
|
||||
|
||||
protected override void LoadDefaultConfig() => _config = new Configuration();
|
||||
|
||||
protected override void SaveConfig() => Config.WriteObject(_config);
|
||||
|
||||
private class Configuration
|
||||
{
|
||||
[JsonProperty("Maximal Titles")]
|
||||
public int MaxTitles { get; set; } = 3;
|
||||
|
||||
[JsonProperty("Maximal Characters Per Message")]
|
||||
public int MaxMessageLength { get; set; } = 128;
|
||||
|
||||
[JsonProperty("Reverse Title Order")]
|
||||
public bool ReverseTitleOrder { get; set; } = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Group Structures
|
||||
|
||||
public class BetterChatMessage
|
||||
{
|
||||
public IPlayer Player;
|
||||
public string Username;
|
||||
public string Message;
|
||||
public List<string> Titles;
|
||||
public string PrimaryGroup;
|
||||
public ChatGroup.UsernameSettings UsernameSettings;
|
||||
public ChatGroup.MessageSettings MessageSettings;
|
||||
public ChatGroup.FormatSettings FormatSettings;
|
||||
public List<string> BlockedReceivers = new List<string>();
|
||||
public CancelOptions CancelOption;
|
||||
|
||||
public ChatGroup.FormatSettings GetOutput()
|
||||
{
|
||||
ChatGroup.FormatSettings output = new ChatGroup.FormatSettings();
|
||||
|
||||
Dictionary<string, string> replacements = new Dictionary<string, string>
|
||||
{
|
||||
["Title"] = string.Join(" ", Titles.ToArray()),
|
||||
["Username"] = $"[#{UsernameSettings.GetUniversalColor()}][+{UsernameSettings.Size}]{Username}[/+][/#]",
|
||||
["Group"] = PrimaryGroup,
|
||||
["Message"] = $"[#{MessageSettings.GetUniversalColor()}][+{MessageSettings.Size}]{Message}[/+][/#]",
|
||||
["ID"] = Player.Id,
|
||||
["Time"] = DateTime.Now.TimeOfDay.ToString(),
|
||||
["Date"] = DateTime.Now.ToString()
|
||||
};
|
||||
|
||||
output.Chat = FormatSettings.Chat;
|
||||
output.Console = FormatSettings.Console;
|
||||
|
||||
foreach (var replacement in replacements)
|
||||
{
|
||||
output.Console = StripRichText(output.Console.Replace($"{{{replacement.Key}}}", replacement.Value));
|
||||
output.Chat = _instance.covalence.FormatText(output.Chat.Replace($"{{{replacement.Key}}}", replacement.Value));
|
||||
}
|
||||
|
||||
if (output.Chat.StartsWith(" "))
|
||||
output.Chat = output.Chat.Remove(0, 1);
|
||||
|
||||
if (output.Console.StartsWith(" "))
|
||||
output.Console = output.Console.Remove(0, 1);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static BetterChatMessage FromDictionary(Dictionary<string, object> dictionary)
|
||||
{
|
||||
var usernameSettings = dictionary[nameof(UsernameSettings)] as Dictionary<string, object>;
|
||||
var messageSettings = dictionary[nameof(MessageSettings)] as Dictionary<string, object>;
|
||||
var formatSettings = dictionary[nameof(FormatSettings)] as Dictionary<string, object>;
|
||||
|
||||
return new BetterChatMessage
|
||||
{
|
||||
Player = dictionary[nameof(Player)] as IPlayer,
|
||||
Message = dictionary[nameof(Message)] as string,
|
||||
Username = dictionary[nameof(Username)] as string,
|
||||
Titles = dictionary[nameof(Titles)] as List<string>,
|
||||
PrimaryGroup = dictionary[nameof(PrimaryGroup)] as string,
|
||||
BlockedReceivers = dictionary[nameof(BlockedReceivers)] as List<string>,
|
||||
UsernameSettings = new ChatGroup.UsernameSettings
|
||||
{
|
||||
Color = usernameSettings[nameof(ChatGroup.UsernameSettings.Color)] as string,
|
||||
Size = (int)usernameSettings[nameof(ChatGroup.UsernameSettings.Size)]
|
||||
},
|
||||
MessageSettings = new ChatGroup.MessageSettings
|
||||
{
|
||||
Color = messageSettings[nameof(ChatGroup.MessageSettings.Color)] as string,
|
||||
Size = (int)messageSettings[nameof(ChatGroup.MessageSettings.Size)]
|
||||
},
|
||||
FormatSettings = new ChatGroup.FormatSettings
|
||||
{
|
||||
Chat = formatSettings[nameof(ChatGroup.FormatSettings.Chat)] as string,
|
||||
Console = formatSettings[nameof(ChatGroup.FormatSettings.Console)] as string
|
||||
},
|
||||
CancelOption = (CancelOptions) dictionary[nameof(CancelOption)]
|
||||
};
|
||||
}
|
||||
|
||||
public Dictionary<string, object> ToDictionary() => new Dictionary<string, object>
|
||||
{
|
||||
[nameof(Player)] = Player,
|
||||
[nameof(Message)] = Message,
|
||||
[nameof(Username)] = Username,
|
||||
[nameof(Titles)] = Titles,
|
||||
[nameof(PrimaryGroup)] = PrimaryGroup,
|
||||
[nameof(BlockedReceivers)] = BlockedReceivers,
|
||||
[nameof(UsernameSettings)] = new Dictionary<string, object>
|
||||
{
|
||||
[nameof(ChatGroup.UsernameSettings.Color)] = UsernameSettings.Color,
|
||||
[nameof(ChatGroup.UsernameSettings.Size)] = UsernameSettings.Size
|
||||
},
|
||||
[nameof(MessageSettings)] = new Dictionary<string, object>
|
||||
{
|
||||
[nameof(ChatGroup.MessageSettings.Color)] = MessageSettings.Color,
|
||||
[nameof(ChatGroup.MessageSettings.Size)] = MessageSettings.Size
|
||||
},
|
||||
[nameof(FormatSettings)] = new Dictionary<string, object>
|
||||
{
|
||||
[nameof(ChatGroup.FormatSettings.Chat)] = FormatSettings.Chat,
|
||||
[nameof(ChatGroup.FormatSettings.Console)] = FormatSettings.Console
|
||||
},
|
||||
[nameof(CancelOption)] = CancelOption
|
||||
};
|
||||
|
||||
public enum CancelOptions
|
||||
{
|
||||
None = 0,
|
||||
BetterChatOnly = 1,
|
||||
BetterChatAndDefault = 2
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatGroup
|
||||
{
|
||||
private static readonly ChatGroup _fallbackGroup = new ChatGroup("default");
|
||||
|
||||
#if RUST
|
||||
private static readonly ChatGroup _rustDeveloperGroup = new ChatGroup("rust_developer")
|
||||
{
|
||||
Priority = 100,
|
||||
Title =
|
||||
{
|
||||
Text = "[Rust Developer]",
|
||||
Color = "#ffaa55"
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
public string GroupName;
|
||||
public int Priority = 0;
|
||||
|
||||
public TitleSettings Title = new TitleSettings();
|
||||
public UsernameSettings Username = new UsernameSettings();
|
||||
public MessageSettings Message = new MessageSettings();
|
||||
public FormatSettings Format = new FormatSettings();
|
||||
|
||||
public ChatGroup(string name)
|
||||
{
|
||||
GroupName = name;
|
||||
Title = new TitleSettings(name);
|
||||
}
|
||||
|
||||
public static readonly Dictionary<string, Field> Fields = new Dictionary<string, Field>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
["Priority"] = new Field(g => g.Priority, (g, v) => g.Priority = int.Parse(v), "number"),
|
||||
|
||||
["Title"] = new Field(g => g.Title.Text, (g, v) => g.Title.Text = v, "text"),
|
||||
["TitleColor"] = new Field(g => g.Title.Color, (g, v) => g.Title.Color = v, "color"),
|
||||
["TitleSize"] = new Field(g => g.Title.Size, (g, v) => g.Title.Size = int.Parse(v), "number"),
|
||||
["TitleHidden"] = new Field(g => g.Title.Hidden, (g, v) => g.Title.Hidden = bool.Parse(v), "true/false"),
|
||||
["TitleHiddenIfNotPrimary"] = new Field(g => g.Title.HiddenIfNotPrimary, (g, v) => g.Title.HiddenIfNotPrimary = bool.Parse(v), "true/false"),
|
||||
|
||||
["UsernameColor"] = new Field(g => g.Username.Color, (g, v) => g.Username.Color = v, "color"),
|
||||
["UsernameSize"] = new Field(g => g.Username.Size, (g, v) => g.Username.Size = int.Parse(v), "number"),
|
||||
|
||||
["MessageColor"] = new Field(g => g.Message.Color, (g, v) => g.Message.Color = v, "color"),
|
||||
["MessageSize"] = new Field(g => g.Message.Size, (g, v) => g.Message.Size = int.Parse(v), "number"),
|
||||
|
||||
["ChatFormat"] = new Field(g => g.Format.Chat, (g, v) => g.Format.Chat = v, "text"),
|
||||
["ConsoleFormat"] = new Field(g => g.Format.Console, (g, v) => g.Format.Console = v, "text")
|
||||
};
|
||||
|
||||
public static ChatGroup Find(string name) => _instance._chatGroups.Find(g => g.GroupName == name);
|
||||
|
||||
public static List<ChatGroup> GetUserGroups(IPlayer player)
|
||||
{
|
||||
string[] oxideGroups = _instance.permission.GetUserGroups(player.Id);
|
||||
var groups = _instance._chatGroups.Where(g => oxideGroups.Any(name => g.GroupName.ToLower() == name)).ToList();
|
||||
|
||||
#if RUST
|
||||
BasePlayer bPlayer = BasePlayer.Find(player.Id);
|
||||
|
||||
if (bPlayer?.IsDeveloper ?? false)
|
||||
groups.Add(_rustDeveloperGroup);
|
||||
#endif
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
public static ChatGroup GetUserPrimaryGroup(IPlayer player)
|
||||
{
|
||||
List<ChatGroup> groups = GetUserGroups(player);
|
||||
ChatGroup primary = null;
|
||||
|
||||
foreach (ChatGroup group in groups)
|
||||
if (primary == null || group.Priority < primary.Priority)
|
||||
primary = group;
|
||||
|
||||
return primary;
|
||||
}
|
||||
|
||||
public static BetterChatMessage FormatMessage(IPlayer player, string message)
|
||||
{
|
||||
ChatGroup primary = GetUserPrimaryGroup(player);
|
||||
List<ChatGroup> groups = GetUserGroups(player);
|
||||
|
||||
if (primary == null)
|
||||
{
|
||||
_instance.PrintWarning($"{player.Name} ({player.Id}) does not seem to be in any BetterChat group - falling back to plugin's default group! This should never happen! Please make sure you have a group called 'default'.");
|
||||
primary = _fallbackGroup;
|
||||
groups.Add(primary);
|
||||
}
|
||||
|
||||
groups.Sort((a, b) => b.Priority.CompareTo(a.Priority));
|
||||
|
||||
var titles = (from g in groups
|
||||
where !g.Title.Hidden && !(g.Title.HiddenIfNotPrimary && primary != g)
|
||||
select $"[#{g.Title.GetUniversalColor()}][+{g.Title.Size}]{g.Title.Text}[/+][/#]")
|
||||
.ToList();
|
||||
|
||||
titles = titles.GetRange(0, Math.Min(_instance._config.MaxTitles, titles.Count));
|
||||
|
||||
if (_instance._config.ReverseTitleOrder)
|
||||
{
|
||||
titles.Reverse();
|
||||
}
|
||||
|
||||
foreach (var thirdPartyTitle in _instance._thirdPartyTitles)
|
||||
{
|
||||
try
|
||||
{
|
||||
string title = thirdPartyTitle.Value(player);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
titles.Add(title);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_instance.PrintError($"Error when trying to get third-party title from plugin '{thirdPartyTitle.Key}'{Environment.NewLine}{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
return new BetterChatMessage
|
||||
{
|
||||
Player = player,
|
||||
Username = StripRichText(player.Name),
|
||||
Message = StripRichText(message),
|
||||
Titles = titles,
|
||||
PrimaryGroup = primary.GroupName,
|
||||
UsernameSettings = primary.Username,
|
||||
MessageSettings = primary.Message,
|
||||
FormatSettings = primary.Format
|
||||
};
|
||||
}
|
||||
|
||||
public void AddUser(IPlayer player) => _instance.permission.AddUserGroup(player.Id, GroupName);
|
||||
|
||||
public void RemoveUser(IPlayer player) => _instance.permission.RemoveUserGroup(player.Id, GroupName);
|
||||
|
||||
public Field.SetValueResult SetField(string field, string value)
|
||||
{
|
||||
if (!Fields.ContainsKey(field))
|
||||
return Field.SetValueResult.InvalidField;
|
||||
|
||||
try
|
||||
{
|
||||
Fields[field].Setter(this, value);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return Field.SetValueResult.InvalidValue;
|
||||
}
|
||||
|
||||
return Field.SetValueResult.Success;
|
||||
}
|
||||
|
||||
public Dictionary<string, object> GetFields() => Fields.ToDictionary(field => field.Key, field => field.Value.Getter(this));
|
||||
|
||||
public override int GetHashCode() => GroupName.GetHashCode();
|
||||
|
||||
public class TitleSettings
|
||||
{
|
||||
public string Text = "[Player]";
|
||||
public string Color = "#55aaff";
|
||||
public int Size = 15;
|
||||
public bool Hidden = false;
|
||||
public bool HiddenIfNotPrimary = false;
|
||||
|
||||
public string GetUniversalColor() => Color.StartsWith("#") ? Color.Substring(1) : Color;
|
||||
|
||||
public TitleSettings(string groupName)
|
||||
{
|
||||
if (groupName != "default" && groupName != null)
|
||||
Text = $"[{groupName}]";
|
||||
}
|
||||
|
||||
public TitleSettings()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class UsernameSettings
|
||||
{
|
||||
public string Color = "#55aaff";
|
||||
public int Size = 15;
|
||||
|
||||
public string GetUniversalColor() => Color.StartsWith("#") ? Color.Substring(1) : Color;
|
||||
}
|
||||
|
||||
public class MessageSettings
|
||||
{
|
||||
public string Color = "white";
|
||||
public int Size = 15;
|
||||
|
||||
public string GetUniversalColor() => Color.StartsWith("#") ? Color.Substring(1) : Color;
|
||||
}
|
||||
|
||||
public class FormatSettings
|
||||
{
|
||||
public string Chat = "{Title} {Username}: {Message}";
|
||||
public string Console = "{Title} {Username}: {Message}";
|
||||
}
|
||||
|
||||
public class Field
|
||||
{
|
||||
public Func<ChatGroup, object> Getter { get; }
|
||||
public Action<ChatGroup, string> Setter { get; }
|
||||
public string UserFriendyType { get; }
|
||||
|
||||
public enum SetValueResult
|
||||
{
|
||||
Success,
|
||||
InvalidField,
|
||||
InvalidValue
|
||||
}
|
||||
|
||||
public Field(Func<ChatGroup, object> getter, Action<ChatGroup, string> setter, string userFriendyType)
|
||||
{
|
||||
Getter = getter;
|
||||
Setter = setter;
|
||||
UserFriendyType = userFriendyType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#region Extension Methods
|
||||
|
||||
namespace Oxide.Plugins.BetterChatExtensions
|
||||
{
|
||||
internal static class IPlayerExtensions
|
||||
{
|
||||
public static void ReplyLang(this IPlayer player, string key, Dictionary<string, string> replacements = null)
|
||||
{
|
||||
string message = BetterChat.GetMessage(key, player.Id);
|
||||
|
||||
if (replacements != null)
|
||||
foreach (var replacement in replacements)
|
||||
message = message.Replace($"{{{replacement.Key}}}", replacement.Value);
|
||||
|
||||
replacements = null;
|
||||
|
||||
player.Reply(message);
|
||||
}
|
||||
|
||||
public static void ReplyLang(this IPlayer player, string key, KeyValuePair<string, string> replacement)
|
||||
{
|
||||
string message = BetterChat.GetMessage(key, player.Id);
|
||||
message = message.Replace($"{{{replacement.Key}}}", replacement.Value);
|
||||
|
||||
player.Reply(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1,705 +0,0 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Oxide.Core;
|
||||
using Oxide.Core.Plugins;
|
||||
using Oxide.Game.Rust;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oxide.Plugins
|
||||
{
|
||||
[Info("Blueprint Share", "c_creep", "1.2.4")]
|
||||
[Description("Allows players to share researched blueprints with their friends, clan or team")]
|
||||
|
||||
class BlueprintShare : RustPlugin
|
||||
{
|
||||
#region Fields
|
||||
|
||||
[PluginReference] private Plugin Clans, ClansReborn, Friends;
|
||||
|
||||
private StoredData storedData;
|
||||
|
||||
private bool clansEnabled = true, friendsEnabled = true, teamsEnabled = true, recycleEnabled = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Localization
|
||||
|
||||
protected override void LoadDefaultMessages()
|
||||
{
|
||||
lang.RegisterMessages(new Dictionary<string, string>
|
||||
{
|
||||
["Prefix"] = "<color=#D85540>[Blueprint Share] </color>",
|
||||
["ArgumentsError"] = "Error, incorrect arguments. Try /bs help.",
|
||||
["Help"] = "<color=#D85540>Blueprint Share Help:</color>\n\n<color=#D85540>/bs toggle</color> - Toggles the sharing of blueprints.\n<color=#D85540>/bs share <player></color> - Shares your blueprints with other player.",
|
||||
["ToggleOn"] = "You have enabled sharing blueprints.",
|
||||
["ToggleOff"] = "You have disabled sharing blueprints.",
|
||||
["NoPermission"] = "You don't have permission to use this command!",
|
||||
["CannotShare"] = "You cannot share blueprints with this player because they aren't a friend or in the same clan or team!",
|
||||
["NoTarget"] = "You didn't specifiy a player to share with!",
|
||||
["TargetEqualsPlayer"] = "You cannot share blueprints with your self!",
|
||||
["PlayerNotFound"] = "Couldn't find a player with that name!",
|
||||
["MultiplePlayersFound"] = "Found multiple players with a similar name: {0}",
|
||||
["ShareSuccess"] = "You shared {0} blueprints with {1}.",
|
||||
["ShareFailure"] = "You don't have any new blueprints to share with {0}",
|
||||
["ShareReceieve"] = "{0} has shared {1} blueprints with you.",
|
||||
["Recycle"] = "You have kept the blueprint because no one learnt the blueprint.",
|
||||
["ShareError"] = "An error occured while attempting to share items with another player"
|
||||
}, this);
|
||||
}
|
||||
|
||||
private string GetLangValue(string key, string id = null, params object[] args)
|
||||
{
|
||||
var msg = lang.GetMessage(key, this, id);
|
||||
|
||||
return args.Length > 0 ? string.Format(msg, args) : msg;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Oxide Hooks
|
||||
|
||||
private void Init()
|
||||
{
|
||||
LoadData();
|
||||
LoadDefaultConfig();
|
||||
|
||||
permission.RegisterPermission("blueprintshare.toggle", this);
|
||||
permission.RegisterPermission("blueprintshare.share", this);
|
||||
}
|
||||
|
||||
private void OnPlayerConnected(BasePlayer player)
|
||||
{
|
||||
var playerUID = player.UserIDString;
|
||||
|
||||
if (!PlayerDataExists(playerUID))
|
||||
{
|
||||
CreateNewPlayerData(playerUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemAction(Item item, string action, BasePlayer player)
|
||||
{
|
||||
if (player != null)
|
||||
{
|
||||
if (action == "study")
|
||||
{
|
||||
var itemShortName = item.blueprintTargetDef.shortname;
|
||||
|
||||
if (CanShareBlueprint(itemShortName, player))
|
||||
{
|
||||
item.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTechTreeNodeUnlocked(Workbench workbench, TechTreeData.NodeInstance node, BasePlayer player)
|
||||
{
|
||||
if (workbench != null)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
if (player != null)
|
||||
{
|
||||
var itemShortName = node.itemDef.shortname;
|
||||
|
||||
CanShareBlueprint(itemShortName, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region General Methods
|
||||
|
||||
private bool CanShareBlueprint(string itemShortName, BasePlayer player)
|
||||
{
|
||||
if (player == null) return false;
|
||||
if (string.IsNullOrEmpty(itemShortName)) return false;
|
||||
|
||||
var playerUID = player.UserIDString;
|
||||
|
||||
if (SharingEnabled(playerUID))
|
||||
{
|
||||
if (InTeam(player.userID) || InClan(player.userID) || HasFriends(player.userID))
|
||||
{
|
||||
if (SomeoneWillLearnBlueprint(player, itemShortName))
|
||||
{
|
||||
TryInsertBlueprint(player, itemShortName);
|
||||
ShareWithPlayers(player, itemShortName);
|
||||
HandleAdditionalBlueprints(player, itemShortName);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (recycleEnabled)
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Recycle", playerUID));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TryInsertBlueprint(player, itemShortName);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAdditionalBlueprints(BasePlayer player, string itemShortName)
|
||||
{
|
||||
var additionalBlueprints = GetItemDefinition(itemShortName).Blueprint.additionalUnlocks;
|
||||
|
||||
if (additionalBlueprints.Count > 0)
|
||||
{
|
||||
foreach (var blueprint in additionalBlueprints)
|
||||
{
|
||||
var additionalItemShortName = blueprint.shortname;
|
||||
|
||||
if (!string.IsNullOrEmpty(additionalItemShortName))
|
||||
{
|
||||
if (SomeoneWillLearnBlueprint(player, additionalItemShortName))
|
||||
{
|
||||
ShareWithPlayers(player, additionalItemShortName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShareWithPlayers(BasePlayer sharer, string itemShortName)
|
||||
{
|
||||
if (sharer == null || string.IsNullOrEmpty(itemShortName)) return;
|
||||
|
||||
var recipients = SelectSharePlayers(sharer);
|
||||
|
||||
foreach (var recipient in recipients)
|
||||
{
|
||||
if (recipient != null)
|
||||
{
|
||||
if (UnlockBlueprint(recipient, itemShortName))
|
||||
{
|
||||
TryInsertBlueprint(recipient, itemShortName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShareWithPlayer(BasePlayer sharer, BasePlayer recipient)
|
||||
{
|
||||
var sharerUID = sharer.UserIDString;
|
||||
var recipientUID = recipient.UserIDString;
|
||||
|
||||
if (SameTeam(sharer, recipient) || SameClan(sharerUID, recipientUID) || AreFriends(sharerUID, recipientUID))
|
||||
{
|
||||
var itemShortNames = LoadBlueprints(sharerUID);
|
||||
|
||||
if (itemShortNames != null)
|
||||
{
|
||||
if (itemShortNames.Count > 0)
|
||||
{
|
||||
var learnedBlueprints = 0;
|
||||
|
||||
foreach (var itemShortName in itemShortNames)
|
||||
{
|
||||
if (recipient == null || string.IsNullOrEmpty(itemShortName)) return;
|
||||
|
||||
if (UnlockBlueprint(recipient, itemShortName))
|
||||
{
|
||||
TryInsertBlueprint(recipient, itemShortName);
|
||||
|
||||
learnedBlueprints++;
|
||||
}
|
||||
}
|
||||
|
||||
if (learnedBlueprints > 0)
|
||||
{
|
||||
sharer.ChatMessage(GetLangValue("Prefix", sharerUID) + GetLangValue("ShareSuccess", sharerUID, learnedBlueprints, recipient.displayName));
|
||||
|
||||
recipient.ChatMessage(GetLangValue("Prefix", recipientUID) + GetLangValue("ShareReceieve", recipientUID, sharer.displayName, learnedBlueprints));
|
||||
}
|
||||
else
|
||||
{
|
||||
sharer.ChatMessage(GetLangValue("Prefix", sharerUID) + GetLangValue("ShareFailure", sharerUID, recipient.displayName));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sharer.ChatMessage(GetLangValue("Prefix", sharerUID) + GetLangValue("ShareFailure", sharerUID, recipient.displayName));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sharer.ChatMessage(GetLangValue("ShareError", sharerUID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool UnlockBlueprint(BasePlayer player, string itemShortName)
|
||||
{
|
||||
if (player == null) return false;
|
||||
if (string.IsNullOrEmpty(itemShortName)) return false;
|
||||
|
||||
var blueprintComponent = player.blueprints;
|
||||
|
||||
if (blueprintComponent == null) return false;
|
||||
|
||||
var itemDefinition = GetItemDefinition(itemShortName);
|
||||
|
||||
if (itemDefinition == null) return false;
|
||||
|
||||
if (blueprintComponent.HasUnlocked(itemDefinition)) return false;
|
||||
|
||||
var soundEffect = new Effect("assets/prefabs/deployable/research table/effects/research-success.prefab", player.transform.position, Vector3.zero);
|
||||
|
||||
if (soundEffect == null) return false;
|
||||
|
||||
EffectNetwork.Send(soundEffect, player.net.connection);
|
||||
|
||||
blueprintComponent.Unlock(itemDefinition);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SomeoneWillLearnBlueprint(BasePlayer sharer, string itemShortName)
|
||||
{
|
||||
if (sharer == null || string.IsNullOrEmpty(itemShortName)) return false;
|
||||
|
||||
var players = SelectSharePlayers(sharer);
|
||||
|
||||
if (players.Count > 0)
|
||||
{
|
||||
var blueprintItem = GetItemDefinition(itemShortName);
|
||||
|
||||
if (blueprintItem != null)
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (player != null)
|
||||
{
|
||||
if (!player.blueprints.HasUnlocked(blueprintItem))
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private List<BasePlayer> SelectSharePlayers(BasePlayer player)
|
||||
{
|
||||
var playersToShareWith = new List<BasePlayer>();
|
||||
|
||||
var playerUID = player.userID;
|
||||
|
||||
if (clansEnabled && (Clans != null || ClansReborn != null) && InClan(playerUID))
|
||||
{
|
||||
playersToShareWith.AddRange(GetClanMembers(playerUID));
|
||||
}
|
||||
|
||||
if (friendsEnabled && Friends != null && HasFriends(playerUID))
|
||||
{
|
||||
playersToShareWith.AddRange(GetFriends(playerUID));
|
||||
}
|
||||
|
||||
if (teamsEnabled && InTeam(playerUID))
|
||||
{
|
||||
playersToShareWith.AddRange(GetTeamMembers(playerUID));
|
||||
}
|
||||
|
||||
return playersToShareWith;
|
||||
}
|
||||
|
||||
private List<string> LoadBlueprints(string playerUID)
|
||||
{
|
||||
if (PlayerDataExists(playerUID))
|
||||
{
|
||||
return storedData.players[playerUID].learntBlueprints;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateNewPlayerData(playerUID);
|
||||
|
||||
if (storedData.players[playerUID].learntBlueprints == null)
|
||||
{
|
||||
return storedData.players[playerUID].learntBlueprints = new List<string>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return storedData.players[playerUID].learntBlueprints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryInsertBlueprint(BasePlayer player, string itemShortName)
|
||||
{
|
||||
var playerUID = player.UserIDString;
|
||||
|
||||
if (PlayerDataExists(playerUID))
|
||||
{
|
||||
InsertBlueprint(playerUID, itemShortName);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateNewPlayerData(playerUID);
|
||||
|
||||
InsertBlueprint(playerUID, itemShortName);
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertBlueprint(string playerUID, string itemShortName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerUID) || string.IsNullOrEmpty(itemShortName)) return;
|
||||
|
||||
if (!storedData.players[playerUID].learntBlueprints.Contains(itemShortName))
|
||||
{
|
||||
storedData.players[playerUID].learntBlueprints.Add(itemShortName);
|
||||
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Config
|
||||
|
||||
protected override void LoadDefaultConfig()
|
||||
{
|
||||
Config["ClansEnabled"] = clansEnabled = GetConfigValue("ClansEnabled", true);
|
||||
Config["FriendsEnabled"] = friendsEnabled = GetConfigValue("FriendsEnabled", true);
|
||||
Config["TeamsEnabled"] = teamsEnabled = GetConfigValue("TeamsEnabled", true);
|
||||
Config["RecycleBlueprints"] = recycleEnabled = GetConfigValue("RecycleBlueprints", false);
|
||||
|
||||
SaveConfig();
|
||||
}
|
||||
|
||||
private T GetConfigValue<T>(string name, T defaultValue)
|
||||
{
|
||||
return Config[name] == null ? defaultValue : (T)Convert.ChangeType(Config[name], typeof(T));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Friends Methods
|
||||
|
||||
private bool HasFriends(ulong playerUID)
|
||||
{
|
||||
if (Friends == null) return false;
|
||||
|
||||
var friendsList = Friends.Call<ulong[]>("GetFriends", playerUID);
|
||||
|
||||
return friendsList != null && friendsList.Length != 0;
|
||||
}
|
||||
|
||||
private List<BasePlayer> GetFriends(ulong playerUID)
|
||||
{
|
||||
var friendsList = new List<BasePlayer>();
|
||||
|
||||
var friends = Friends.Call<ulong[]>("GetFriends", playerUID);
|
||||
|
||||
foreach (var friendUID in friends)
|
||||
{
|
||||
var friend = RustCore.FindPlayerById(friendUID);
|
||||
|
||||
friendsList.Add(friend);
|
||||
}
|
||||
|
||||
return friendsList;
|
||||
}
|
||||
|
||||
private bool AreFriends(string sharerUID, string playerUID) => Friends == null ? false : Friends.Call<bool>("AreFriends", sharerUID, playerUID);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Clan Methods
|
||||
|
||||
private bool InClan(ulong playerUID)
|
||||
{
|
||||
if (ClansReborn == null && Clans == null) return false;
|
||||
|
||||
var clanName = Clans?.Call<string>("GetClanOf", playerUID);
|
||||
|
||||
return clanName != null;
|
||||
}
|
||||
|
||||
private List<BasePlayer> GetClanMembers(ulong playerUID)
|
||||
{
|
||||
var membersList = new List<BasePlayer>();
|
||||
|
||||
var clanName = Clans?.Call<string>("GetClanOf", playerUID);
|
||||
|
||||
if (!string.IsNullOrEmpty(clanName))
|
||||
{
|
||||
var clan = Clans?.Call<JObject>("GetClan", clanName);
|
||||
|
||||
if (clan != null && clan is JObject)
|
||||
{
|
||||
var members = clan.GetValue("members");
|
||||
|
||||
if (members != null)
|
||||
{
|
||||
foreach (var member in members)
|
||||
{
|
||||
ulong clanMemberUID;
|
||||
|
||||
if (!ulong.TryParse(member.ToString(), out clanMemberUID)) continue;
|
||||
|
||||
BasePlayer clanMember = RustCore.FindPlayerById(clanMemberUID);
|
||||
|
||||
membersList.Add(clanMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return membersList;
|
||||
}
|
||||
|
||||
private bool SameClan(string sharerUID, string playerUID) => ClansReborn == null && Clans == null ? false : (bool)Clans?.Call<bool>("IsClanMember", sharerUID, playerUID);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Team Methods
|
||||
|
||||
private bool InTeam(ulong playerUID)
|
||||
{
|
||||
var player = RustCore.FindPlayerById(playerUID);
|
||||
|
||||
return player.currentTeam != 0;
|
||||
}
|
||||
|
||||
private List<BasePlayer> GetTeamMembers(ulong playerUID)
|
||||
{
|
||||
var membersList = new List<BasePlayer>();
|
||||
|
||||
var player = RustCore.FindPlayerById(playerUID);
|
||||
|
||||
var teamMembers = player.Team.members;
|
||||
|
||||
foreach (var teamMemberUID in teamMembers)
|
||||
{
|
||||
var teamMember = RustCore.FindPlayerById(teamMemberUID);
|
||||
|
||||
if (teamMember != null)
|
||||
{
|
||||
membersList.Add(teamMember);
|
||||
}
|
||||
}
|
||||
|
||||
return membersList;
|
||||
}
|
||||
|
||||
private bool SameTeam(BasePlayer sharer, BasePlayer player) => sharer.currentTeam == player.currentTeam;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
private BasePlayer FindPlayer(string playerName, BasePlayer player, string playerUID)
|
||||
{
|
||||
var targets = FindPlayers(playerName);
|
||||
|
||||
if (targets.Count <= 0)
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("PlayerNotFound", playerUID));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (targets.Count > 1)
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("MultiplePlayersFound", playerUID));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return targets.First();
|
||||
}
|
||||
|
||||
private List<BasePlayer> FindPlayers(string playerName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerName)) return null;
|
||||
|
||||
return BasePlayer.allPlayerList.Where(p => p && p.UserIDString == playerName || p.displayName.Contains(playerName, CompareOptions.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
|
||||
private ItemDefinition GetItemDefinition(string itemShortName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(itemShortName)) return null;
|
||||
|
||||
var itemDefinition = ItemManager.FindItemDefinition(itemShortName.ToLower());
|
||||
|
||||
return itemDefinition;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
private class StoredData
|
||||
{
|
||||
public Dictionary<string, PlayerData> players = new Dictionary<string, PlayerData>();
|
||||
}
|
||||
|
||||
private class PlayerData
|
||||
{
|
||||
public bool sharingEnabled;
|
||||
|
||||
public List<string> learntBlueprints;
|
||||
}
|
||||
|
||||
private void CreateData()
|
||||
{
|
||||
storedData = new StoredData();
|
||||
|
||||
SaveData();
|
||||
}
|
||||
|
||||
private void LoadData()
|
||||
{
|
||||
if (Interface.Oxide.DataFileSystem.ExistsDatafile(Name))
|
||||
{
|
||||
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateData();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
|
||||
|
||||
private bool PlayerDataExists(string playerUID) => storedData.players.ContainsKey(playerUID);
|
||||
|
||||
private void CreateNewPlayerData(string playerUID)
|
||||
{
|
||||
storedData.players.Add(playerUID, new PlayerData
|
||||
{
|
||||
sharingEnabled = true,
|
||||
learntBlueprints = new List<string>()
|
||||
});
|
||||
|
||||
SaveData();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Chat Commands
|
||||
|
||||
[ChatCommand("bs")]
|
||||
private void ToggleCommand(BasePlayer player, string command, string[] args)
|
||||
{
|
||||
var playerUID = player.UserIDString;
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("Help", playerUID));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0].ToLower())
|
||||
{
|
||||
case "help":
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Help", playerUID));
|
||||
|
||||
break;
|
||||
}
|
||||
case "toggle":
|
||||
{
|
||||
if (permission.UserHasPermission(playerUID, "blueprintshare.toggle"))
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue(SharingEnabled(playerUID) ? "ToggleOff" : "ToggleOn", playerUID));
|
||||
|
||||
if (storedData.players.ContainsKey(playerUID))
|
||||
{
|
||||
storedData.players[playerUID].sharingEnabled = !storedData.players[playerUID].sharingEnabled;
|
||||
|
||||
SaveData();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("NoPermission", playerUID));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "share":
|
||||
{
|
||||
if (permission.UserHasPermission(playerUID, "blueprintshare.share"))
|
||||
{
|
||||
if (args.Length == 2)
|
||||
{
|
||||
var target = FindPlayer(args[1], player, playerUID);
|
||||
|
||||
if (target == null) return;
|
||||
|
||||
if (target == player)
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("TargetEqualsPlayer", playerUID));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ShareWithPlayer(player, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("NoTarget", playerUID));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("NoPermission", playerUID));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
player.ChatMessage(GetLangValue("Prefix", playerUID) + GetLangValue("ArgumentsError", playerUID));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region API
|
||||
|
||||
private bool SharingEnabled(string playerUID) => storedData.players.ContainsKey(playerUID) ? storedData.players[playerUID].sharingEnabled : true;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
-1318
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,422 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oxide.Plugins
|
||||
{
|
||||
[Info("Inventory Viewer", "Mughisi", "3.0.3", ResourceId = 871)]
|
||||
[Description("Allows players with permission assigned to view anyone's inventory")]
|
||||
public class InventoryViewer : RustPlugin
|
||||
{
|
||||
private readonly string RequiredPermission = "inventoryviewer.allowed";
|
||||
|
||||
private readonly Dictionary<BasePlayer, List<BasePlayer>> matches = new Dictionary<BasePlayer, List<BasePlayer>>();
|
||||
|
||||
/// <summary>
|
||||
/// UnityEngine script to be attached to the player viewing someone's inventory.
|
||||
/// </summary>
|
||||
private class Inspector : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The player doing the inspecting.
|
||||
/// </summary>
|
||||
private BasePlayer player;
|
||||
|
||||
/// <summary>
|
||||
/// The player being inspected.
|
||||
/// </summary>
|
||||
private BasePlayer target;
|
||||
|
||||
/// <summary>
|
||||
/// The tick counter used by the Inspector.
|
||||
/// </summary>
|
||||
private int ticks;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates the Inspector script.
|
||||
/// </summary>
|
||||
public void Instantiate(BasePlayer player, BasePlayer target)
|
||||
{
|
||||
this.player = player;
|
||||
this.target = target;
|
||||
|
||||
BeginLooting();
|
||||
|
||||
InvokeRepeating("UpdateLoot", 0f, 0.1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the loot.
|
||||
/// </summary>
|
||||
private void UpdateLoot()
|
||||
{
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.inventory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ticks++;
|
||||
|
||||
if (!player.inventory.loot.IsLooting())
|
||||
{
|
||||
BeginLooting();
|
||||
}
|
||||
|
||||
player.inventory.loot.SendImmediate();
|
||||
|
||||
player.SendNetworkUpdateImmediate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops inspecting.
|
||||
/// </summary>
|
||||
private void StopInspecting(bool forced = false)
|
||||
{
|
||||
if (ticks < 5 && !forced)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CancelInvoke("UpdateLoot");
|
||||
|
||||
EndLooting();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the looting.
|
||||
/// </summary>
|
||||
private void BeginLooting()
|
||||
{
|
||||
player.inventory.loot.Clear();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.inventory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
player.inventory.loot.AddContainer(target.inventory.containerMain);
|
||||
player.inventory.loot.AddContainer(target.inventory.containerWear);
|
||||
player.inventory.loot.AddContainer(target.inventory.containerBelt);
|
||||
player.inventory.loot.PositionChecks = false;
|
||||
player.inventory.loot.entitySource = target;
|
||||
player.inventory.loot.itemSource = null;
|
||||
player.inventory.loot.MarkDirty();
|
||||
player.inventory.loot.SendImmediate();
|
||||
player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", "player_corpse");
|
||||
player.SendNetworkUpdateImmediate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends the looting.
|
||||
/// </summary>
|
||||
private void EndLooting()
|
||||
{
|
||||
player.inventory.loot.MarkDirty();
|
||||
|
||||
if (player.inventory.loot.entitySource)
|
||||
{
|
||||
player.inventory.loot.entitySource.SendMessage("PlayerStoppedLooting", player, SendMessageOptions.DontRequireReceiver);
|
||||
}
|
||||
|
||||
foreach (ItemContainer container in player.inventory.loot.containers)
|
||||
{
|
||||
if (container != null)
|
||||
{
|
||||
container.onDirty -= player.inventory.loot.MarkDirty;
|
||||
}
|
||||
}
|
||||
|
||||
player.inventory.loot.containers.Clear();
|
||||
player.inventory.loot.entitySource = null;
|
||||
player.inventory.loot.itemSource = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the script
|
||||
/// </summary>
|
||||
public void Remove(bool forced = false)
|
||||
{
|
||||
if (ticks < 5 && !forced)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StopInspecting(forced);
|
||||
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oxide hook that is triggered when the plugin is loaded.
|
||||
/// </summary>
|
||||
private void Loaded()
|
||||
{
|
||||
permission.RegisterPermission(RequiredPermission, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oxide hook that is triggered after the plugin is loaded to setup localized messages.
|
||||
/// </summary>
|
||||
private new void LoadDefaultMessages()
|
||||
{
|
||||
lang.RegisterMessages(new Dictionary<string, string>
|
||||
{
|
||||
{ "InvalidArguments", "Invalid argument(s) supplied! Use '/{0} <name>' or '/{0} list <number>'." },
|
||||
{ "InvalidSelection", "Invalid number, use the number in front of the player's name. Use '/{0} list' to check the list of players again." },
|
||||
{ "MultiplePlayersFound", "Multiple players found with that name, please select one of these players by using '/{0} list <number>':" },
|
||||
{ "NoListAvailable", "You do not have a players list available, use '/{0} <name>' instead." },
|
||||
{ "NoPlayersFound", "Couldn't find any players matching that name." },
|
||||
{ "NotAllowed", "You are not allowed to use this command." },
|
||||
{ "TooManyPlayersFound", "Too many players were found, the list of matches is only showing the first 5. Try to be more specific." }
|
||||
}, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oxide hook that is triggered when the plugin is unloaded.
|
||||
/// </summary>
|
||||
private void Unload()
|
||||
{
|
||||
Inspector[] inspectors = UnityEngine.Object.FindObjectsOfType<Inspector>();
|
||||
|
||||
foreach (Inspector inspector in inspectors)
|
||||
inspector.Remove();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oxide hook that is triggered when a console command is executed.
|
||||
/// </summary>
|
||||
private void OnServerCommand(ConsoleSystem.Arg arg)
|
||||
{
|
||||
if (arg.cmd.FullName == "inventory.endloot")
|
||||
{
|
||||
BasePlayer player = arg.Player();
|
||||
player.GetComponent<Inspector>()?.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oxide hook that is triggered when a player attempts to loot another player
|
||||
/// </summary>
|
||||
private object CanLootPlayer(BasePlayer target, BasePlayer looter)
|
||||
{
|
||||
if (looter.GetComponent<Inspector>() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the /inspect command
|
||||
/// </summary>
|
||||
[ChatCommand("inspect")]
|
||||
private void InspectCommand(BasePlayer player, string command, string[] args)
|
||||
{
|
||||
ViewInventoryCommand(player, command, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the /viewinv command
|
||||
/// </summary>
|
||||
[ChatCommand("viewinv")]
|
||||
private void ViewInvCommand(BasePlayer player, string command, string[] args)
|
||||
{
|
||||
ViewInventoryCommand(player, command, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the /viewinventory command
|
||||
/// </summary>
|
||||
[ChatCommand("viewinventory")]
|
||||
private void ViewInventoryCommand(BasePlayer player, string command, string[] args)
|
||||
{
|
||||
if (!CanUseCommand(player))
|
||||
{
|
||||
SendChatMessage(player, "NotAllowed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
SendChatMessage(player, "InvalidArguments", command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0] == "list")
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
if (!matches.ContainsKey(player) || matches[player] == null)
|
||||
{
|
||||
SendChatMessage(player, "NoListAvailable", command);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowMatches(player);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int num;
|
||||
if (int.TryParse(args[1], out num))
|
||||
{
|
||||
if (!matches.ContainsKey(player) || matches[player] == null)
|
||||
{
|
||||
SendChatMessage(player, "NoListAvailable", command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num > matches[player].Count)
|
||||
{
|
||||
SendChatMessage(player, "InvalidSelection", command);
|
||||
ShowMatches(player);
|
||||
return;
|
||||
}
|
||||
|
||||
StartInspecting(player, matches[player][num - 1]);
|
||||
return;
|
||||
}
|
||||
|
||||
SendChatMessage(player, "InvalidArguments", command);
|
||||
}
|
||||
else
|
||||
{
|
||||
string name = string.Join(" ", args);
|
||||
List<BasePlayer> players = FindPlayersByNameOrId(name);
|
||||
|
||||
switch (players.Count)
|
||||
{
|
||||
case 0:
|
||||
SendChatMessage(player, "NoPlayersFound", command);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
StartInspecting(player, players[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
SendChatMessage(player, "MultiplePlayersFound", command);
|
||||
|
||||
if (!matches.ContainsKey(player))
|
||||
{
|
||||
matches.Add(player, players);
|
||||
}
|
||||
else
|
||||
{
|
||||
matches[player] = players;
|
||||
}
|
||||
|
||||
ShowMatches(player);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up all players (active and sleeping) by a given (partial) name or steam id.
|
||||
/// </summary>
|
||||
private List<BasePlayer> FindPlayersByNameOrId(string nameOrId)
|
||||
{
|
||||
List<BasePlayer> matches = new List<BasePlayer>();
|
||||
|
||||
foreach (BasePlayer player in BasePlayer.activePlayerList)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(player.displayName))
|
||||
{
|
||||
if (player.displayName.ToLower().Contains(nameOrId.ToLower()))
|
||||
{
|
||||
matches.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (player.UserIDString == nameOrId)
|
||||
{
|
||||
matches.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (BasePlayer player in BasePlayer.sleepingPlayerList)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(player.displayName))
|
||||
{
|
||||
if (player.displayName.ToLower().Contains(nameOrId.ToLower()))
|
||||
{
|
||||
matches.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (player.UserIDString == nameOrId)
|
||||
{
|
||||
matches.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
return matches.OrderBy(p => p.displayName).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the cached matches for the player.
|
||||
/// </summary>
|
||||
private void ShowMatches(BasePlayer player)
|
||||
{
|
||||
for (int i = 0; i < matches[player].Count; i++)
|
||||
{
|
||||
SendChatMessage(player, $"{i + 1}. {matches[player][i].displayName}");
|
||||
|
||||
if (i == 4 && i < matches[player].Count)
|
||||
{
|
||||
SendChatMessage(player, "TooManyPlayersFound");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the inspector for the given player and target.
|
||||
/// </summary>
|
||||
private void StartInspecting(BasePlayer player, BasePlayer target)
|
||||
{
|
||||
Inspector inspector = player.gameObject.GetComponent<Inspector>();
|
||||
inspector?.Remove();
|
||||
|
||||
inspector = player.gameObject.AddComponent<Inspector>();
|
||||
inspector.Instantiate(player, target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified BasePlayer has the required permission.
|
||||
/// </summary>
|
||||
private bool CanUseCommand(BasePlayer player)
|
||||
{
|
||||
return permission.UserHasPermission(player.UserIDString, RequiredPermission);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a localized chat message using the key to the specified player
|
||||
/// </summary>
|
||||
private void SendChatMessage(BasePlayer player, string key, params string[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
{
|
||||
Player.Reply(player, lang.GetMessage(key, this, player.UserIDString));
|
||||
}
|
||||
else
|
||||
{
|
||||
Player.Reply(player, string.Format(lang.GetMessage(key, this, player.UserIDString), args));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
-1933
File diff suppressed because it is too large
Load Diff
@@ -1,537 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Oxide.Core;
|
||||
|
||||
namespace Oxide.Plugins
|
||||
{
|
||||
[Info("Stack Size Controller", "Canopy Sheep", "2.0.4", ResourceId = 2320)]
|
||||
[Description("Allows you to set the max stack size of every item.")]
|
||||
public class StackSizeController : RustPlugin
|
||||
{
|
||||
#region Data
|
||||
|
||||
private bool pluginLoaded = false;
|
||||
Items items;
|
||||
class Items
|
||||
{
|
||||
public Dictionary<string, int> itemlist = new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
private bool LoadData()
|
||||
{
|
||||
var itemsdatafile = Interface.Oxide.DataFileSystem.GetFile("StackSizeController");
|
||||
try
|
||||
{
|
||||
items = itemsdatafile.ReadObject<Items>();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PrintWarning("Error: Data file is corrupt. Debug info: " + ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateItems()
|
||||
{
|
||||
var gameitemList = ItemManager.itemList;
|
||||
List<string> itemCategories = new List<string>();
|
||||
int stacksize;
|
||||
|
||||
foreach (var item in gameitemList)
|
||||
{
|
||||
if (!itemCategories.Contains(item.category.ToString()))
|
||||
{
|
||||
if (!(configData.Settings.CategoryDefaultStack.ContainsKey(item.category.ToString())))
|
||||
{
|
||||
configData.Settings.CategoryDefaultStack[item.category.ToString()] = configData.Settings.NewCategoryDefaultSetting;
|
||||
Puts("Added item category: '" + item.category.ToString() + "' to the config.");
|
||||
}
|
||||
itemCategories.Add(item.category.ToString());
|
||||
}
|
||||
|
||||
if (!(items.itemlist.ContainsKey(item.displayName.english)))
|
||||
{
|
||||
stacksize = DetermineStack(item);
|
||||
items.itemlist.Add(item.displayName.english, stacksize);
|
||||
}
|
||||
}
|
||||
|
||||
List<string> KeysToRemove = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string ,int> category in configData.Settings.CategoryDefaultStack)
|
||||
{
|
||||
if (!itemCategories.Contains(category.Key)) { KeysToRemove.Add(category.Key); }
|
||||
}
|
||||
|
||||
if (KeysToRemove.Count > 0)
|
||||
{
|
||||
Puts("Cleaning config categories...");
|
||||
foreach (string Key in KeysToRemove)
|
||||
{
|
||||
configData.Settings.CategoryDefaultStack.Remove(Key);
|
||||
}
|
||||
}
|
||||
|
||||
SaveConfig();
|
||||
|
||||
KeysToRemove = new List<string>();
|
||||
bool foundItem = false;
|
||||
|
||||
foreach (KeyValuePair<string, int> item in items.itemlist)
|
||||
{
|
||||
foreach (var itemingamelist in gameitemList)
|
||||
{
|
||||
if (itemingamelist.displayName.english == item.Key)
|
||||
{
|
||||
foundItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(foundItem)) { KeysToRemove.Add(item.Key); }
|
||||
foundItem = false;
|
||||
}
|
||||
|
||||
if (KeysToRemove.Count > 0)
|
||||
{
|
||||
Puts("Cleaning data file...");
|
||||
foreach (string key in KeysToRemove)
|
||||
{
|
||||
items.itemlist.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
SaveData();
|
||||
LoadStackSizes();
|
||||
}
|
||||
|
||||
private int DetermineStack(ItemDefinition item)
|
||||
{
|
||||
if (item.condition.enabled && item.condition.max > 0 && (!configData.Settings.StackHealthItems))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (configData.Settings.DefaultStack != 0 && (!configData.Settings.CategoryDefaultStack.ContainsKey(item.category.ToString())))
|
||||
{
|
||||
return configData.Settings.DefaultStack;
|
||||
}
|
||||
else if (configData.Settings.CategoryDefaultStack.ContainsKey(item.category.ToString()) && configData.Settings.CategoryDefaultStack[item.category.ToString()] != 0)
|
||||
{
|
||||
return configData.Settings.CategoryDefaultStack[item.category.ToString()];
|
||||
}
|
||||
else if (configData.Settings.DefaultStack != 0 && configData.Settings.CategoryDefaultStack[item.category.ToString()] == 0)
|
||||
{
|
||||
return configData.Settings.DefaultStack;
|
||||
}
|
||||
else
|
||||
{
|
||||
return item.stackable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadStackSizes()
|
||||
{
|
||||
var gameitemList = ItemManager.itemList;
|
||||
|
||||
foreach (var item in gameitemList)
|
||||
{
|
||||
item.stackable = items.itemlist[item.displayName.english];
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveData()
|
||||
{
|
||||
Interface.Oxide.DataFileSystem.WriteObject("StackSizeController", items);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Config
|
||||
|
||||
ConfigData configData;
|
||||
class ConfigData
|
||||
{
|
||||
public SettingsData Settings { get; set; }
|
||||
}
|
||||
|
||||
class SettingsData
|
||||
{
|
||||
public int DefaultStack { get; set; }
|
||||
public int NewCategoryDefaultSetting { get; set; }
|
||||
public bool StackHealthItems { get; set; }
|
||||
public Dictionary<string, int> CategoryDefaultStack { get; set; }
|
||||
}
|
||||
|
||||
private void TryConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
configData = Config.ReadObject<ConfigData>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PrintWarning("Corrupt config detected, debug: " + ex.Message);
|
||||
LoadDefaultConfig();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadDefaultConfig()
|
||||
{
|
||||
Puts("Generating a new config file...");
|
||||
|
||||
Config.WriteObject(new ConfigData
|
||||
{
|
||||
Settings = new SettingsData
|
||||
{
|
||||
DefaultStack = 0,
|
||||
NewCategoryDefaultSetting = 0,
|
||||
StackHealthItems = true,
|
||||
CategoryDefaultStack = new Dictionary<string, int>()
|
||||
{
|
||||
{ "Ammunition", 0 },
|
||||
{ "Weapon", 0 },
|
||||
},
|
||||
},
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void SaveConfig()
|
||||
{
|
||||
Config.WriteObject(configData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Hooks
|
||||
private void OnServerInitialized()
|
||||
{
|
||||
TryConfig();
|
||||
pluginLoaded = LoadData();
|
||||
|
||||
if (pluginLoaded)
|
||||
{
|
||||
if (!configData.Settings.StackHealthItems) { Unsubscribe(); }
|
||||
UpdateItems();
|
||||
}
|
||||
else { Puts("Stack Sizes could not be changed due to a corrupt data file."); }
|
||||
|
||||
permission.RegisterPermission("stacksizecontroller.canChangeStackSize", this);
|
||||
}
|
||||
|
||||
private bool hasPermission(BasePlayer player, string perm)
|
||||
{
|
||||
if (player.net.connection.authLevel > 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return permission.UserHasPermission(player.userID.ToString(), perm);
|
||||
}
|
||||
|
||||
private object CanStackItem(Item item, Item targetItem)
|
||||
{
|
||||
if (item.info.shortname != targetItem.info.shortname) { return null; }
|
||||
if (item.contents != targetItem.contents) { return false; }
|
||||
|
||||
FlameThrower flamethrower = item.GetHeldEntity() as FlameThrower;
|
||||
if (flamethrower != null)
|
||||
{
|
||||
if (flamethrower.ammo != (targetItem.GetHeldEntity() as FlameThrower).ammo) { return false; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Unsubscribe()
|
||||
{
|
||||
Unsubscribe(nameof(CanStackItem));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
[ChatCommand("stack")]
|
||||
private void StackCommand(BasePlayer player, string command, string[] args)
|
||||
{
|
||||
if (!hasPermission(player, "stacksizecontroller.canChangeStackSize"))
|
||||
{
|
||||
SendReply(player, "You don't have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pluginLoaded)
|
||||
{
|
||||
SendReply(player, "StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 2)
|
||||
{
|
||||
SendReply(player, "Syntax Error: Requires 2 arguments. Syntax Example: /stack ammo.rocket.hv 64 (Use shortname)");
|
||||
return;
|
||||
}
|
||||
|
||||
int stackAmount = 0;
|
||||
|
||||
List<ItemDefinition> gameitems = ItemManager.itemList.FindAll(x => x.shortname.Equals(args[0]));
|
||||
|
||||
if (gameitems.Count == 0)
|
||||
{
|
||||
SendReply(player, "Syntax Error: That is an incorrect item name. Please use a valid shortname.");
|
||||
return;
|
||||
}
|
||||
|
||||
string replymessage = "";
|
||||
switch (args[1].ToLower())
|
||||
{
|
||||
case "default":
|
||||
{
|
||||
stackAmount = DetermineStack(gameitems[0]);
|
||||
replymessage = "Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + " (Default value based on config).";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (int.TryParse(args[1], out stackAmount) == false)
|
||||
{
|
||||
SendReply(player, "Syntax Error: Stack Amount is not a number. Syntax Example: /stack ammo.rocket.hv 64 (Use shortname)");
|
||||
return;
|
||||
}
|
||||
replymessage = "Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameitems[0].condition.enabled && gameitems[0].condition.max > 0)
|
||||
{
|
||||
if (!(configData.Settings.StackHealthItems))
|
||||
{
|
||||
SendReply(player, "Error: Stacking health items is disabled in the config.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
items.itemlist[gameitems[0].displayName.english] = Convert.ToInt32(stackAmount);
|
||||
|
||||
gameitems[0].stackable = Convert.ToInt32(stackAmount);
|
||||
|
||||
SaveData();
|
||||
|
||||
SendReply(player, replymessage);
|
||||
}
|
||||
|
||||
[ChatCommand("stackall")]
|
||||
private void StackAllCommand(BasePlayer player, string command, string[] args)
|
||||
{
|
||||
if (!hasPermission(player, "stacksizecontroller.canChangeStackSize"))
|
||||
{
|
||||
SendReply(player, "You don't have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pluginLoaded)
|
||||
{
|
||||
SendReply(player, "StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
SendReply(player, "Syntax Error: Requires 1 argument. Syntax Example: /stackall 65000");
|
||||
return;
|
||||
}
|
||||
|
||||
int stackAmount = 0;
|
||||
string replymessage = "";
|
||||
|
||||
var itemList = ItemManager.itemList;
|
||||
|
||||
foreach (var gameitem in itemList)
|
||||
{
|
||||
switch (args[0].ToLower())
|
||||
{
|
||||
case "default":
|
||||
{
|
||||
stackAmount = DetermineStack(gameitem);
|
||||
replymessage = "The Stack Size of all stackable items has been set to their default values (specified in config).";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (int.TryParse(args[0], out stackAmount) == false)
|
||||
{
|
||||
SendReply(player, "Syntax Error: Stack Amount is not a number. Syntax Example: /stackall 65000");
|
||||
return;
|
||||
}
|
||||
replymessage = "The Stack Size of all stackable items has been set to " + stackAmount.ToString() + ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameitem.condition.enabled && gameitem.condition.max > 0 && !(configData.Settings.StackHealthItems)) { continue; }
|
||||
if (gameitem.displayName.english.ToString() == "Salt Water" || gameitem.displayName.english.ToString() == "Water") { continue; }
|
||||
|
||||
items.itemlist[gameitem.displayName.english] = Convert.ToInt32(stackAmount);
|
||||
gameitem.stackable = Convert.ToInt32(stackAmount);
|
||||
}
|
||||
|
||||
SaveData();
|
||||
|
||||
SendReply(player, replymessage);
|
||||
}
|
||||
|
||||
[ConsoleCommand("stack")]
|
||||
private void StackConsoleCommand(ConsoleSystem.Arg arg)
|
||||
{
|
||||
if (arg.IsAdmin != true)
|
||||
{
|
||||
if ((arg.Connection.userid.ToString() != null) && !(permission.UserHasPermission(arg.Connection.userid.ToString(), "stacksizecontroller.canChangeStackSize")))
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] You don't have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pluginLoaded)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg.Args != null)
|
||||
{
|
||||
if (arg.Args.Length < 2)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 2 arguments. Syntax Example: stack ammo.rocket.hv 64 (Use shortname)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 2 arguments. Syntax Example: stack ammo.rocket.hv 64 (Use shortname)");
|
||||
return;
|
||||
}
|
||||
|
||||
int stackAmount = 0;
|
||||
List<ItemDefinition> gameitems = ItemManager.itemList.FindAll(x => x.shortname.Equals(arg.Args[0]));
|
||||
|
||||
if (gameitems.Count == 0)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: That is an incorrect item name. Please use a valid shortname.");
|
||||
return;
|
||||
}
|
||||
|
||||
string replymessage = "";
|
||||
switch (arg.Args[1].ToLower())
|
||||
{
|
||||
case "default":
|
||||
{
|
||||
stackAmount = DetermineStack(gameitems[0]);
|
||||
replymessage = "[StackSizeController] Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + " (Default value based on config).";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (int.TryParse(arg.Args[1], out stackAmount) == false)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: Stack Amount is not a number. Syntax Example: /stack ammo.rocket.hv 64 (Use shortname)");
|
||||
return;
|
||||
}
|
||||
replymessage = "[StackSizeController] Updated Stack Size for " + gameitems[0].displayName.english + " (" + gameitems[0].shortname + ") to " + stackAmount + ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameitems[0].condition.enabled && gameitems[0].condition.max > 0)
|
||||
{
|
||||
if (!(configData.Settings.StackHealthItems))
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Error: Stacking health items is disabled in the config.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
items.itemlist[gameitems[0].displayName.english] = Convert.ToInt32(stackAmount);
|
||||
|
||||
gameitems[0].stackable = Convert.ToInt32(stackAmount);
|
||||
|
||||
SaveData();
|
||||
|
||||
arg.ReplyWith(replymessage);
|
||||
}
|
||||
|
||||
[ConsoleCommand("stackall")]
|
||||
private void StackAllConsoleCommand(ConsoleSystem.Arg arg)
|
||||
{
|
||||
if (arg.IsAdmin != true)
|
||||
{
|
||||
if ((arg.Connection.userid.ToString() != null) && !(permission.UserHasPermission(arg.Connection.userid.ToString(), "stacksizecontroller.canChangeStackSize")))
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] You don't have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pluginLoaded)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] StackSizeController has encountered an error while trying to read the data file. Please contact your server administrator to fix the issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg.Args != null)
|
||||
{
|
||||
if (arg.Args.Length < 1)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 1 argument. Syntax Example: stackall 65000");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: Requires 1 argument. Syntax Example: stackall 65000");
|
||||
return;
|
||||
}
|
||||
|
||||
int stackAmount = 0;
|
||||
string replymessage = "";
|
||||
|
||||
var itemList = ItemManager.itemList;
|
||||
|
||||
foreach (var gameitem in itemList)
|
||||
{
|
||||
if (gameitem.condition.enabled && gameitem.condition.max > 0 && (!(configData.Settings.StackHealthItems))) { continue; }
|
||||
if (gameitem.displayName.english.ToString() == "Salt Water" ||
|
||||
gameitem.displayName.english.ToString() == "Water") { continue; }
|
||||
|
||||
switch (arg.Args[0].ToLower())
|
||||
{
|
||||
case "default":
|
||||
{
|
||||
stackAmount = DetermineStack(gameitem);
|
||||
replymessage = "[StackSizeController] The Stack Size of all stackable items has been set to their default values (specified in config).";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (int.TryParse(arg.Args[0], out stackAmount) == false)
|
||||
{
|
||||
arg.ReplyWith("[StackSizeController] Syntax Error: Stack Amount is not a number. Syntax Example: /stackall 65000");
|
||||
return;
|
||||
}
|
||||
replymessage = "[StackSizeController] The Stack Size of all stackable items has been set to " + stackAmount.ToString() + ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
items.itemlist[gameitem.displayName.english] = Convert.ToInt32(stackAmount);
|
||||
gameitem.stackable = Convert.ToInt32(stackAmount);
|
||||
}
|
||||
|
||||
SaveData();
|
||||
|
||||
arg.ReplyWith(replymessage);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Oxide.Plugins
|
||||
{
|
||||
[Info("Unburnable Meat", "S642667", "1.0.1")]
|
||||
[Description("Prevent cooked meats from burning")]
|
||||
class UnburnableMeat : RustPlugin
|
||||
{
|
||||
public static readonly string[] CookedItems = new string[]
|
||||
{
|
||||
"bearmeat.cooked",
|
||||
"chicken.cooked",
|
||||
"deermeat.cooked",
|
||||
"horsemeat.cooked",
|
||||
"humanmeat.cooked",
|
||||
"meat.pork.cooked",
|
||||
"wolfmeat.cooked",
|
||||
"fish.cooked"
|
||||
};
|
||||
|
||||
private Dictionary<string, int> lowTemps = new Dictionary<string, int>();
|
||||
private Dictionary<string, int> highTemps = new Dictionary<string, int>();
|
||||
|
||||
ItemModCookable GetCookable (string shortname)
|
||||
{
|
||||
var definition = ItemManager.FindItemDefinition(shortname);
|
||||
if (definition == null)
|
||||
{
|
||||
Puts($"Unknown definition for {shortname}");
|
||||
return null;
|
||||
}
|
||||
var cookable = definition.GetComponent<ItemModCookable>();
|
||||
if (cookable == null)
|
||||
{
|
||||
Puts($"Unknown cookable for {shortname}");
|
||||
return null;
|
||||
}
|
||||
return cookable;
|
||||
}
|
||||
|
||||
void OnServerInitialized()
|
||||
{
|
||||
foreach (var shortname in CookedItems)
|
||||
{
|
||||
var cookable = GetCookable(shortname);
|
||||
if (cookable == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
lowTemps.Add(shortname, cookable.lowTemp);
|
||||
highTemps.Add(shortname, cookable.highTemp);
|
||||
cookable.lowTemp = -1;
|
||||
cookable.highTemp = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Unload()
|
||||
{
|
||||
foreach (KeyValuePair<string, int> item in lowTemps)
|
||||
{
|
||||
var cookable = GetCookable(item.Key);
|
||||
if (cookable == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cookable.lowTemp = item.Value;
|
||||
cookable.highTemp = highTemps[item.Key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,428 +0,0 @@
|
||||
using Network;
|
||||
using Newtonsoft.Json;
|
||||
using Oxide.Core;
|
||||
using Oxide.Core.Libraries.Covalence;
|
||||
using Oxide.Game.Rust.Cui;
|
||||
using Rust;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oxide.Plugins
|
||||
{
|
||||
[Info("Vanish", "Whispers88", "1.3.8")]
|
||||
[Description("Allows players with permission to become invisible")]
|
||||
public class Vanish : RustPlugin
|
||||
{
|
||||
#region Configuration
|
||||
private readonly List<BasePlayer> _hiddenPlayers = new List<BasePlayer>();
|
||||
private readonly List<BasePlayer> _hiddenOffline = new List<BasePlayer>();
|
||||
private static List<string> _registeredhooks = new List<string> { "OnNpcTarget", "CanBeTargeted", "CanHelicopterTarget", "CanHelicopterStrafeTarget", "CanBradleyApcTarget", "CanUseLockedEntity", "OnEntityTakeDamage", "OnPlayerDisconnected" };
|
||||
private static readonly DamageTypeList _EmptyDmgList = new DamageTypeList();
|
||||
CuiElementContainer cachedVanishUI = null;
|
||||
|
||||
private Configuration config;
|
||||
|
||||
public class Configuration
|
||||
{
|
||||
[JsonProperty("NoClip on Vanish (runs noclip command)")]
|
||||
public bool NoClipOnVanish = true;
|
||||
|
||||
[JsonProperty("Hide an invisible players body under the terrain after disconnect")]
|
||||
public bool HideOnDisconnect = false;
|
||||
|
||||
[JsonProperty("If a player was vanished on disconnection keep them vanished on reconnect")]
|
||||
public bool HideOnReconnect = true;
|
||||
|
||||
[JsonProperty("Turn off fly hack detection for players in vanish")]
|
||||
public bool AntiFlyHack = true;
|
||||
|
||||
[JsonProperty("Enable vanishing and reappearing sound effects")]
|
||||
public bool EnableSound = true;
|
||||
|
||||
[JsonProperty("Make sound effects public")]
|
||||
public bool PublicSound = false;
|
||||
|
||||
[JsonProperty("Enable chat notifications")]
|
||||
public bool EnableNotifications = true;
|
||||
|
||||
[JsonProperty("Sound effect to use when vanishing")]
|
||||
public string VanishSoundEffect = "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab";
|
||||
|
||||
[JsonProperty("Sound effect to use when reappearing")]
|
||||
public string ReappearSoundEffect = "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab";
|
||||
|
||||
[JsonProperty("Enable GUI")]
|
||||
public bool EnableGUI = true;
|
||||
|
||||
[JsonProperty("Icon URL (.png or .jpg)")]
|
||||
public string ImageUrlIcon = "http://i.imgur.com/Gr5G3YI.png";
|
||||
|
||||
[JsonProperty("Image Color")]
|
||||
public string ImageColor = "1 1 1 0.3";
|
||||
|
||||
[JsonProperty("Image AnchorMin")]
|
||||
public string ImageAnchorMin = "0.175 0.017";
|
||||
|
||||
[JsonProperty("Image AnchorMax")]
|
||||
public string ImageAnchorMax = "0.22 0.08";
|
||||
|
||||
public string ToJson() => JsonConvert.SerializeObject(this);
|
||||
|
||||
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
|
||||
}
|
||||
|
||||
protected override void LoadDefaultConfig() => config = new Configuration();
|
||||
|
||||
protected override void LoadConfig()
|
||||
{
|
||||
base.LoadConfig();
|
||||
try
|
||||
{
|
||||
config = Config.ReadObject<Configuration>();
|
||||
if (config == null)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
|
||||
{
|
||||
PrintToConsole("Configuration appears to be outdated; updating and saving");
|
||||
SaveConfig();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
PrintToConsole($"Configuration file {Name}.json is invalid; using defaults");
|
||||
LoadDefaultConfig();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SaveConfig()
|
||||
{
|
||||
PrintToConsole($"Configuration changes saved to {Name}.json");
|
||||
Config.WriteObject(config, true);
|
||||
}
|
||||
|
||||
#endregion Configuration
|
||||
|
||||
#region Localization
|
||||
|
||||
protected override void LoadDefaultMessages()
|
||||
{
|
||||
lang.RegisterMessages(new Dictionary<string, string>
|
||||
{
|
||||
["VanishCommand"] = "vanish",
|
||||
["CollisionToggle"] = "collider",
|
||||
["Vanished"] = "Vanish: <color=orange> Enabled </color>",
|
||||
["Reappear"] = "Vanish: <color=orange> Disabled </color>",
|
||||
["NoPerms"] = "You do not have permission to do this",
|
||||
["PermanentVanish"] = "You are in a permanent vanish mode",
|
||||
["ColliderEnbabled"] = "Player Collider: <color=orange> Enabled </color>",
|
||||
["ColliderDisabled"] = "Player Collider: <color=orange> Disabled </color>"
|
||||
|
||||
}, this);
|
||||
}
|
||||
|
||||
#endregion Localization
|
||||
|
||||
#region Initialization
|
||||
|
||||
private const string permallow = "vanish.allow";
|
||||
private const string permunlock = "vanish.unlock";
|
||||
private const string permdamage = "vanish.damage";
|
||||
private const string permavanish = "vanish.permanent";
|
||||
private const string permcollision = "vanish.collision";
|
||||
|
||||
private void Init()
|
||||
{
|
||||
cachedVanishUI = CreateVanishUI();
|
||||
|
||||
// Register univeral chat/console commands
|
||||
AddLocalizedCommand(nameof(VanishCommand));
|
||||
AddLocalizedCommand(nameof(CollisionToggle));
|
||||
|
||||
// Register permissions for commands
|
||||
permission.RegisterPermission(permallow, this);
|
||||
permission.RegisterPermission(permunlock, this);
|
||||
permission.RegisterPermission(permdamage, this);
|
||||
permission.RegisterPermission(permavanish, this);
|
||||
permission.RegisterPermission(permcollision, this);
|
||||
//Unsubscribe from hooks
|
||||
UnSubscribeFromHooks();
|
||||
|
||||
BasePlayer.activePlayerList.Where(i => HasPerm(i.UserIDString, permavanish) && !IsInvisible(i)).ToList().ForEach(j => Disappear(j));
|
||||
}
|
||||
|
||||
private void Unload()
|
||||
{
|
||||
_hiddenPlayers.Where(i => i != null).ToList().ForEach(j => Reappear(j));
|
||||
}
|
||||
|
||||
#endregion Initialization
|
||||
|
||||
#region Commands
|
||||
|
||||
private void VanishCommand(IPlayer iplayer, string command, string[] args)
|
||||
{
|
||||
var player = (BasePlayer)iplayer.Object;
|
||||
if (!HasPerm(player.UserIDString, permallow))
|
||||
{
|
||||
if (config.EnableNotifications) Message(player.IPlayer, "NoPerms");
|
||||
return;
|
||||
}
|
||||
if (HasPerm(player.UserIDString, permavanish))
|
||||
{
|
||||
if (config.EnableNotifications) Message(player.IPlayer, "PermanentVanish");
|
||||
return;
|
||||
}
|
||||
if (IsInvisible(player)) Reappear(player);
|
||||
else Disappear(player);
|
||||
|
||||
}
|
||||
|
||||
private void CollisionToggle(IPlayer iplayer, string command, string[] args)
|
||||
{
|
||||
var player = (BasePlayer)iplayer.Object;
|
||||
if (!IsInvisible(player)) return;
|
||||
if (!HasPerm(player.UserIDString, permcollision))
|
||||
{
|
||||
if (config.EnableNotifications) Message(player.IPlayer, "NoPerms");
|
||||
return;
|
||||
}
|
||||
var col = player.gameObject.GetComponent<Collider>();
|
||||
if (!col.enabled)
|
||||
{
|
||||
player.EnablePlayerCollider();
|
||||
Message(player.IPlayer, "ColliderEnbabled");
|
||||
return;
|
||||
}
|
||||
player.DisablePlayerCollider();
|
||||
Message(player.IPlayer, "ColliderDisabled");
|
||||
}
|
||||
|
||||
private void Reappear(BasePlayer player)
|
||||
{
|
||||
if (Interface.CallHook("OnVanishReappear", player) != null) return;
|
||||
if (config.AntiFlyHack) player.ResetAntiHack();
|
||||
player._limitedNetworking = false;
|
||||
player.EnablePlayerCollider();
|
||||
player.SendNetworkUpdate();
|
||||
player.GetHeldEntity()?.SendNetworkUpdate();
|
||||
player.drownEffect.guid = "28ad47c8e6d313742a7a2740674a25b5";
|
||||
player.fallDamageEffect.guid = "ca14ed027d5924003b1c5d9e523a5fce";
|
||||
_hiddenPlayers.Remove(player);
|
||||
|
||||
if (_hiddenPlayers.Count == 0) UnSubscribeFromHooks();
|
||||
|
||||
if (config.EnableSound)
|
||||
{
|
||||
if (config.PublicSound)
|
||||
{
|
||||
Effect.server.Run(config.ReappearSoundEffect, player.transform.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendEffect(player, config.ReappearSoundEffect);
|
||||
}
|
||||
}
|
||||
|
||||
CuiHelper.DestroyUi(player, "VanishUI");
|
||||
|
||||
if (config.NoClipOnVanish && player.IsFlying) player.SendConsoleCommand("noclip");
|
||||
|
||||
if (config.EnableNotifications) Message(player.IPlayer, "Reappear");
|
||||
}
|
||||
|
||||
private void Disappear(BasePlayer player)
|
||||
{
|
||||
if (Interface.CallHook("OnVanishDisappear", player) != null) return;
|
||||
|
||||
if (config.AntiFlyHack) player.PauseFlyHackDetection();
|
||||
//Mute Player Effects
|
||||
player.fallDamageEffect = new GameObjectRef();
|
||||
player.drownEffect = new GameObjectRef();
|
||||
AntiHack.ShouldIgnore(player);
|
||||
if (_hiddenPlayers.Count == 0) SubscribeToHooks();
|
||||
player._limitedNetworking = true;
|
||||
player.DisablePlayerCollider();
|
||||
var connections = Net.sv.connections.Where(con => con.connected && con.isAuthenticated && con.player is BasePlayer && con.player != player).ToList();
|
||||
player.OnNetworkSubscribersLeave(connections);
|
||||
_hiddenPlayers.Add(player);
|
||||
|
||||
if (config.EnableSound)
|
||||
{
|
||||
if (config.PublicSound)
|
||||
{
|
||||
Effect.server.Run(config.VanishSoundEffect, player.transform.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendEffect(player, config.VanishSoundEffect);
|
||||
}
|
||||
}
|
||||
if (config.NoClipOnVanish && !player.IsFlying && !player.isMounted) player.SendConsoleCommand("noclip");
|
||||
|
||||
if (config.EnableGUI) CuiHelper.AddUi(player, cachedVanishUI);
|
||||
|
||||
if (config.EnableNotifications) Message(player.IPlayer, "Vanished");
|
||||
}
|
||||
|
||||
#endregion Commands
|
||||
|
||||
#region Hooks
|
||||
private void OnPlayerConnected(BasePlayer player)
|
||||
{
|
||||
if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot))
|
||||
{
|
||||
timer.In(3, () => OnPlayerConnected(player));
|
||||
return;
|
||||
}
|
||||
if (_hiddenOffline.Contains(player))
|
||||
{
|
||||
_hiddenOffline.Remove(player);
|
||||
if (HasPerm(player.UserIDString, permallow))
|
||||
Disappear(player);
|
||||
}
|
||||
if (HasPerm(player.UserIDString, permavanish))
|
||||
{
|
||||
Disappear(player);
|
||||
}
|
||||
}
|
||||
|
||||
private object OnNpcTarget(BaseEntity entity, BasePlayer target) => IsInvisible(target) ? (object)true : null;
|
||||
private object CanBeTargeted(BasePlayer player, MonoBehaviour behaviour) => IsInvisible(player) ? (object)false : null;
|
||||
private object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player) => IsInvisible(player) ? (object)false : null;
|
||||
private object CanHelicopterStrafeTarget(PatrolHelicopterAI heli, BasePlayer player) => IsInvisible(player) ? (object)false : null;
|
||||
private object CanBradleyApcTarget(BradleyAPC apc, BasePlayer player) => IsInvisible(player) ? (object)false : null;
|
||||
private object CanUseLockedEntity(BasePlayer player, BaseLock baseLock)
|
||||
{
|
||||
if (IsInvisible(player))
|
||||
{
|
||||
if (HasPerm(player.UserIDString, permunlock)) return true;
|
||||
if (config.EnableNotifications) Message(player.IPlayer, "NoPerms");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
|
||||
{
|
||||
var attacker = info?.InitiatorPlayer;
|
||||
var victim = entity?.ToPlayer();
|
||||
if (!IsInvisible(victim) && !IsInvisible(attacker)) return null;
|
||||
if (IsInvisible(attacker) && HasPerm(attacker.UserIDString, permdamage)) return null;
|
||||
if (info != null)
|
||||
{
|
||||
info.damageTypes = _EmptyDmgList;
|
||||
info.HitMaterial = 0;
|
||||
info.PointStart = Vector3.zero;
|
||||
info.HitEntity = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnPlayerDisconnected(BasePlayer player, string reason)
|
||||
{
|
||||
if (!IsInvisible(player)) return;
|
||||
|
||||
player._limitedNetworking = false;
|
||||
player.EnablePlayerCollider();
|
||||
player.SendNetworkUpdate();
|
||||
player.GetHeldEntity()?.SendNetworkUpdate();
|
||||
_hiddenPlayers.Remove(player);
|
||||
if (_hiddenPlayers.Count == 0) UnSubscribeFromHooks();
|
||||
if (config.HideOnDisconnect)
|
||||
{
|
||||
var pos = player.transform.position;
|
||||
var underTerrainPos = new Vector3(pos.x, TerrainMeta.HeightMap.GetHeight(pos) - 5, pos.z);
|
||||
player.Teleport(underTerrainPos);
|
||||
player.DisablePlayerCollider();
|
||||
}
|
||||
if (config.HideOnReconnect)
|
||||
_hiddenOffline.Add(player);
|
||||
CuiHelper.DestroyUi(player, "VanishUI");
|
||||
}
|
||||
#endregion Hooks
|
||||
|
||||
#region GUI
|
||||
|
||||
private CuiElementContainer CreateVanishUI()
|
||||
{
|
||||
CuiElementContainer elements = new CuiElementContainer();
|
||||
string panel = elements.Add(new CuiPanel
|
||||
{
|
||||
Image = { Color = "0.5 0.5 0.5 0.0" },
|
||||
RectTransform = { AnchorMin = config.ImageAnchorMin, AnchorMax = config.ImageAnchorMax }
|
||||
}, "Hud.Menu", "VanishUI");
|
||||
elements.Add(new CuiElement
|
||||
{
|
||||
Parent = panel,
|
||||
Components =
|
||||
{
|
||||
new CuiRawImageComponent {Color = config.ImageColor, Url = config.ImageUrlIcon},
|
||||
new CuiRectTransformComponent {AnchorMin = "0 0", AnchorMax = "1 1"}
|
||||
}
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
#endregion GUI
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddLocalizedCommand(string command)
|
||||
{
|
||||
foreach (string language in lang.GetLanguages(this))
|
||||
{
|
||||
Dictionary<string, string> messages = lang.GetMessages(language, this);
|
||||
foreach (KeyValuePair<string, string> message in messages)
|
||||
{
|
||||
if (!message.Key.Equals(command)) continue;
|
||||
|
||||
if (string.IsNullOrEmpty(message.Value)) continue;
|
||||
|
||||
AddCovalenceCommand(message.Value, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasPerm(string id, string perm) => permission.UserHasPermission(id, perm);
|
||||
|
||||
private string GetLang(string langKey, string playerId = null, params object[] args)
|
||||
{
|
||||
return string.Format(lang.GetMessage(langKey, this, playerId), args);
|
||||
}
|
||||
|
||||
private void Message(IPlayer player, string langKey, params object[] args)
|
||||
{
|
||||
if (player.IsConnected) player.Message(GetLang(langKey, player.Id, args));
|
||||
}
|
||||
|
||||
private bool IsInvisible(BasePlayer player) => player != null && _hiddenPlayers.Contains(player);
|
||||
|
||||
private void UnSubscribeFromHooks()
|
||||
{
|
||||
foreach (var hook in _registeredhooks)
|
||||
Unsubscribe(hook);
|
||||
}
|
||||
|
||||
private void SubscribeToHooks()
|
||||
{
|
||||
foreach (var hook in _registeredhooks)
|
||||
Subscribe(hook);
|
||||
}
|
||||
|
||||
private void SendEffect(BasePlayer player, string sound)
|
||||
{
|
||||
var effect = new Effect(sound, player, 0, Vector3.zero, Vector3.forward);
|
||||
EffectNetwork.Send(effect, player.net.connection);
|
||||
}
|
||||
|
||||
#endregion Helpers
|
||||
|
||||
#region Public Helpers
|
||||
public void _Disappear(BasePlayer basePlayer) => Disappear(basePlayer);
|
||||
public void _Reappear(BasePlayer basePlayer) => Reappear(basePlayer);
|
||||
public bool _IsInvisible(BasePlayer basePlayer) => IsInvisible(basePlayer);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user