C#:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins
{
[Info("Friends", "Mevent", "1.20.0")]
[Description("Adds a friends system with a visual interface for quick interaction")]
public class Friends : RustPlugin
{
#region Fields
[PluginReference] private Plugin ImageLibrary, Notifications, PlayerList, PlayerDatabase;
private const string Layer = "Com.Mevent.Main";
private static Friends _instance;
private readonly Dictionary<ulong, EntityEntry> _playerEntities = new Dictionary<ulong, EntityEntry>();
private class EntityEntry
{
public HashSet<AutoTurret> AutoTurrets = new HashSet<AutoTurret>();
public HashSet<BuildingPrivlidge> BuildingPrivileges = new HashSet<BuildingPrivlidge>();
}
private enum AutoAuthType
{
All,
Turret,
Cupboard
}
private enum BtnType
{
None,
Doors,
Cupboard,
Turrets,
Containers,
FriendlyFire,
Sams
}
#endregion
#region Config
private static Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Добавлять в команду | Add to team")]
public readonly bool AddTeam = true;
[JsonProperty(PropertyName = "Максимальное кол-во друзей | Max Friends")]
public readonly int MaxFriendsAmount = 3;
[JsonProperty(PropertyName = "Задержка между сообщениями FF | Delay between FF messages")]
public readonly float FFDelay = 1;
[JsonProperty(PropertyName =
"Закрывать интерфейс после нажатия на кнопку | Close the interface after clicking on the button")]
public bool AutoClose = true;
[JsonProperty(PropertyName = "Огонь по друзьям | Friendly Fire")]
public bool FriendlyFire;
[JsonProperty(PropertyName = "Двери | Doors")]
public readonly bool Doors = true;
[JsonProperty(PropertyName = "Турели | Turrets")]
public readonly bool Turrets = true;
[JsonProperty(PropertyName = "Шкаф | Cupboard")]
public readonly bool Cupboard = true;
[JsonProperty(PropertyName = "Ящики | Containers")]
public readonly bool Containers = true;
[JsonProperty(PropertyName = "ПВО | SAMs")]
public bool SAMs = true;
[JsonProperty(PropertyName = "Добавлять друга к остальным друзьям? | Add a friend to other friends?")]
public bool UseTeams = true;
[JsonProperty(PropertyName = "Включить логирование в консоль? | Enable logging to the console?")]
public readonly bool LogToConsole = true;
[JsonProperty(PropertyName = "Включить логирование в файл? | Enable logging to the file?")]
public readonly bool LogToFile = true;
[JsonProperty(PropertyName = "Фон | Background")]
public readonly IPanel Background = new IPanel
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "0 0", OffsetMax = "0 0",
Image = string.Empty,
Color = new IColor("#0D1F4E", 95),
isRaw = false,
Sprite = "Assets/Content/UI/UI.Background.Tile.psd",
Material = "Assets/Icons/IconMaterial.mat"
};
[JsonProperty(PropertyName = "Заглавие | Title")]
public readonly IText Title = new IText
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
OffsetMin = "-150 300", OffsetMax = "150 360",
Font = "robotocondensed-bold.ttf",
Align = TextAnchor.MiddleCenter,
FontSize = 38,
Color = new IColor("#FFFFFF", 100)
};
[JsonProperty(PropertyName = "Закрыть | Close")]
public readonly IText Close = new IText
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = "-35 -35", OffsetMax = "-5 -5",
Font = "robotocondensed-bold.ttf",
Align = TextAnchor.MiddleCenter,
FontSize = 24,
Color = new IColor("#FFFFFF", 100)
};
[JsonProperty(PropertyName = "Ошибка | Error")]
public readonly IText Error = new IText
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
OffsetMin = "-300 -150", OffsetMax = "300 150",
Font = "robotocondensed-bold.ttf",
Align = TextAnchor.MiddleCenter,
FontSize = 38,
Color = new IColor("#FFFFFF", 100)
};
[JsonProperty(PropertyName = "Назад | Back")]
public readonly IText Back = new IText
{
AnchorMin = "0 0.5", AnchorMax = "0 0.5",
OffsetMin = "0 -40", OffsetMax = "65 40",
Font = "robotocondensed-bold.ttf",
Align = TextAnchor.MiddleCenter,
FontSize = 60,
Color = new IColor("#FFFFFF", 100)
};
[JsonProperty(PropertyName = "Вперёд | Next")]
public readonly IText Next = new IText
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin = "-65 -40", OffsetMax = "0 40",
Font = "robotocondensed-bold.ttf",
Align = TextAnchor.MiddleCenter,
FontSize = 60,
Color = new IColor("#FFFFFF", 100)
};
[JsonProperty(PropertyName = "Настройка интерфейса | Interface Settings")]
public readonly IFriendPanel Panel = new IFriendPanel
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
Height = 100,
Width = 820,
Margin = 20,
Count = 4,
Color = new IColor("#1D3676", 100),
Avatar = new InterfacePosition
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "5 5", OffsetMax = "95 95"
},
Nickname = new NickName
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "100 40", OffsetMax = "500 100",
Align = TextAnchor.LowerLeft,
Font = "robotocondensed-regular.ttf",
Color = new IColor("#FFFFFF", 100),
FontSize = 38,
MaxLength = 30
},
Status = new SText
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "100 0", OffsetMax = "200 50",
Align = TextAnchor.UpperLeft,
Font = "robotocondensed-regular.ttf",
Color = new IColor("#B5FFC9", 100),
OfflineColor = new IColor("#B46292", 100),
FontSize = 16
},
Button = new IButton
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
Height = 35,
Width = 120,
Margin = 5
},
Buttons = new List<FButton>
{
new FButton
{
Type = BtnType.Doors,
Text = "Двери",
Command = "friend doors {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.Cupboard,
Text = "Шкаф",
Command = "friend cupboard {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.Containers,
Text = "Ящики",
Command = "friend containers {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.Turrets,
Text = "Турели",
Command = "friend turrets {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.None,
Text = "Исключить",
Command = "friend remove {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.FriendlyFire,
Text = "Урон",
Command = "ff {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.None,
Text = "ТП",
Command = "tpr {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
},
new FButton
{
Type = BtnType.Sams,
Text = "ПВО",
Command = "friend sams {user}",
ActiveColor = new IColor("#5D8FDF", 95),
DisactiveColor = new IColor("#5D8FDF", 35),
FontSize = 20,
Font = "robotocondensed-regular.ttf",
Align = TextAnchor.MiddleCenter,
TColor = new IColor("#1D3676", 100)
}
}
};
[JsonProperty(PropertyName = "Приглашение в друзья | Friend Invite")]
public readonly INotify FriendInvite = new INotify
{
Image = "friend",
Url = "https://i.imgur.com/qAxHQIn.png",
Delay = 30,
Buttons = new List<INotifyButton>
{
new INotifyButton
{
AnchorMin = "0.5 0", AnchorMax = "0.5 0",
OffsetMin = "-137.5 5", OffsetMax = "-2.5 25",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 14,
Color = new IColor("#FFFFFF", 95),
BColor = new IColor("#528A4E", 95),
Command = "friend accept",
Msg = "Accept"
},
new INotifyButton
{
AnchorMin = "0.5 0", AnchorMax = "0.5 0",
OffsetMin = "2.5 5", OffsetMax = "137.5 25",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 14,
Color = new IColor("#FFFFFF", 95),
BColor = new IColor("#50488A", 95),
Command = "friend cancel",
Msg = "Cancel"
}
}
};
[JsonProperty(PropertyName = "Оповещение | Notification")]
public readonly INotify Notify = new INotify
{
Image = "friend",
Url = "https://i.imgur.com/qAxHQIn.png",
Delay = 5,
Buttons = new List<INotifyButton>()
};
[JsonProperty(PropertyName = "Найти друга | Find a Friend")]
public readonly INotifyButton FindFriendBtn = new INotifyButton
{
AnchorMin = "0.5 0", AnchorMax = "0.5 0",
OffsetMin = "-150 25", OffsetMax = "150 60",
Align = TextAnchor.MiddleCenter,
FontSize = 14,
Font = "robotocondensed-regular.ttf",
Color = new IColor("#5D8FDF", 100),
BColor = new IColor("#1D3676", 100),
Command = "playerslist",
Msg = "FindFriend"
};
[JsonProperty(PropertyName = "PlayerDatabase")]
public readonly PlayerDatabaseConf PlayerDatabase =
new PlayerDatabaseConf(false, "Friends");
public VersionNumber Version;
}
private class PlayerDatabaseConf
{
[JsonProperty(PropertyName = "Включено")]
public readonly bool Enabled;
[JsonProperty(PropertyName = "Поле")] public readonly string Field;
public PlayerDatabaseConf(bool enabled, string field)
{
Enabled = enabled;
Field = field;
}
}
private class NickName : IText
{
[JsonProperty(PropertyName = "Максимальная длина | Max Lenght")]
public int MaxLength;
public new void Get(ref CuiElementContainer container, string parent = "Hud", string name = null,
string text = "")
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
text = text.Substring(0, Mathf.Min(text.Length, MaxLength));
container.Add(new CuiLabel
{
RectTransform =
{AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax},
Text =
{
Text = $"{text}", Align = Align, FontSize = FontSize, Color = Color.Get(),
Font = Font
}
}, parent, name);
}
}
private class INotify
{
[JsonProperty(PropertyName = "Ключ изображения | Image Key")]
public string Image;
[JsonProperty(PropertyName = "Ссылка на изображение | Image Url")]
public string Url;
[JsonProperty(PropertyName = "Время показа | Show Time")]
public float Delay;
[JsonProperty(PropertyName = "Кнопки | Buttons", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<INotifyButton> Buttons;
}
private class INotifyButton : IText
{
[JsonProperty(PropertyName = "Цвет | Color")]
public IColor BColor;
[JsonProperty(PropertyName = "Ключ языкового файла | Lang Key")]
public string Msg;
[JsonProperty(PropertyName = "Команда | Command")]
public string Command;
public void Get(ref CuiElementContainer container, BasePlayer player, string name = null,
string parent = "")
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
container.Add(new CuiButton
{
RectTransform =
{AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax},
Text =
{
Text = _instance.Msg(Msg, player.UserIDString), Align = Align, FontSize = FontSize,
Color = Color.Get(),
Font = Font
},
Button =
{
Color = BColor.Get(),
Command = Command
}
}, parent, name);
}
}
private abstract class IAnchors
{
public string AnchorMin;
public string AnchorMax;
}
private class InterfacePosition : IAnchors
{
public string OffsetMin;
public string OffsetMax;
}
private class IFriendPanel : IAnchors
{
[JsonProperty(PropertyName = "Высота | Height")]
public float Height;
[JsonProperty(PropertyName = "Ширина | Width")]
public float Width;
[JsonProperty(PropertyName = "Отступ | Margin")]
public float Margin;
[JsonProperty(PropertyName = "Количество на странице | Count On Page")]
public int Count;
[JsonProperty(PropertyName = "Цвет | Color")]
public IColor Color;
[JsonProperty(PropertyName = "Аватарка | Avatar")]
public InterfacePosition Avatar;
[JsonProperty(PropertyName = "Никнейм | Nickname")]
public NickName Nickname;
[JsonProperty(PropertyName = "Статус | Status")]
public SText Status;
[JsonProperty(PropertyName = "Кнопка | Button")]
public IButton Button;
[JsonProperty(PropertyName = "Кнопки | Buttons", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<FButton> Buttons;
public void Get(ref CuiElementContainer container, BasePlayer player, FriendData data, string parent,
string name,
string oMin, string oMax,
int page,
string mainParent)
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = AnchorMin, AnchorMax = AnchorMax,
OffsetMin = oMin, OffsetMax = oMax
},
Image = {Color = Color.Get()}
}, parent, name);
if (_instance.ImageLibrary && Avatar != null)
container.Add(new CuiElement
{
Parent = name,
Components =
{
new CuiRawImageComponent
{Png = _instance.ImageLibrary.Call<string>("GetImage", $"avatar_{data.UserId}")},
new CuiRectTransformComponent
{
AnchorMin = Avatar.AnchorMin, AnchorMax = Avatar.AnchorMax,
OffsetMin = Avatar.OffsetMin, OffsetMax = Avatar.OffsetMax
}
}
});
#region Name
var targetId = $"{data.UserId}";
var target = _instance.covalence.Players.FindPlayer(targetId);
var displayName = _instance.GetPlayerName(data.UserId);
var status = target != null && target.IsConnected;
Nickname?.Get(ref container, name, name + ".Nickname", displayName);
Status?.Get(ref container, status, name, name + ".Status",
_instance.Msg(status ? Online : Offline, player.UserIDString));
#endregion
#region Buttons
if (Buttons != null)
{
var xSwitch = -Button.Margin;
for (var i = 0; i < Buttons.Count; i++)
{
var button = Buttons[i];
var up = i < Buttons.Count / 2;
var ySwitch = up ? Button.Height + Button.Margin / 2f : -(Button.Margin / 2f);
button.Get(ref container, data, name, name + $".Btn.{i}", Button.AnchorMin, Button.AnchorMax,
$"{xSwitch - Button.Width} {ySwitch - Button.Height}",
$"{xSwitch} {ySwitch}",
page,
mainParent);
if (i + 1 == Buttons.Count / 2)
xSwitch = -Button.Margin;
else
xSwitch = xSwitch - Button.Margin - Button.Width;
}
}
#endregion
}
}
private class IPanel : InterfacePosition
{
[JsonProperty(PropertyName = "Изображение | Image")]
public string Image;
[JsonProperty(PropertyName = "Цвет | Color")]
public IColor Color;
[JsonProperty(PropertyName = "Сохранять цвет изображения? | Save Image Color")]
public bool isRaw;
[JsonProperty(PropertyName = "Sprite")]
public string Sprite;
[JsonProperty(PropertyName = "Material")]
public string Material;
public void Get(ref CuiElementContainer container, string parent = "Hud", string name = null,
bool cursor = false)
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
if (isRaw)
{
var element = new CuiElement
{
Name = name,
Parent = parent,
Components =
{
new CuiRawImageComponent
{
Png = !string.IsNullOrEmpty(Image)
? _instance.ImageLibrary.Call<string>("GetImage", Image)
: null,
Color = Color.Get(),
Material = Material,
Sprite = !string.IsNullOrEmpty(Sprite) ? Sprite : "Assets/Icons/rust.png"
},
new CuiRectTransformComponent
{
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin,
OffsetMax = OffsetMax
}
}
};
if (cursor) element.Components.Add(new CuiNeedsCursorComponent());
container.Add(element);
}
else
{
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax
},
Image =
{
Png = !string.IsNullOrEmpty(Image)
? _instance.ImageLibrary.Call<string>("GetImage", Image)
: null,
Color = Color.Get(),
Sprite =
!string.IsNullOrEmpty(Sprite) ? Sprite : "Assets/Content/UI/UI.Background.Tile.psd",
Material = !string.IsNullOrEmpty(Material) ? Material : "Assets/Icons/IconMaterial.mat"
},
CursorEnabled = cursor
}, parent, name);
}
}
}
private class FButton
{
[JsonProperty(PropertyName = "Тип | Type")] [JsonConverter(typeof(StringEnumConverter))]
public BtnType Type;
[JsonProperty(PropertyName = "Текст | Text")]
public string Text;
[JsonProperty(PropertyName = "Команда | Command")]
public string Command;
[JsonProperty(PropertyName = "Активный Цвет | Active Color")]
public IColor ActiveColor;
[JsonProperty(PropertyName = "Неактивный Цвет | Disactive Color")]
public IColor DisactiveColor;
[JsonProperty(PropertyName = "Font Size")]
public int FontSize;
[JsonProperty(PropertyName = "Font")] public string Font;
[JsonProperty(PropertyName = "Align")] [JsonConverter(typeof(StringEnumConverter))]
public TextAnchor Align;
[JsonProperty(PropertyName = "Text Color")]
public IColor TColor;
public void Get(ref CuiElementContainer container, FriendData data, string parent, string name, string aMin,
string aMax, string oMin, string oMax, int page,
string mainParent)
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
var color = ActiveColor;
switch (Type)
{
case BtnType.Doors:
color = data.Doors ? ActiveColor : DisactiveColor;
break;
case BtnType.Cupboard:
color = data.Cupboard ? ActiveColor : DisactiveColor;
break;
case BtnType.Turrets:
color = data.Turrets ? ActiveColor : DisactiveColor;
break;
case BtnType.FriendlyFire:
color = data.FriendlyFire ? ActiveColor : DisactiveColor;
break;
case BtnType.Containers:
color = data.Containers ? ActiveColor : DisactiveColor;
break;
case BtnType.Sams:
color = data.SAMs ? ActiveColor : DisactiveColor;
break;
}
var text = Text.Replace("{user}", data.UserId.ToString());
var command = Command.Replace("{user}", data.UserId.ToString());
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = aMin, AnchorMax = aMax,
OffsetMin = oMin, OffsetMax = oMax
},
Text =
{
Text = $"{text}",
Align = Align,
Font = Font,
FontSize = FontSize,
Color = TColor.Get()
},
Button =
{
Command =
$"UI_Friends sendcmd {page} {mainParent} {command}", // command.Contains("chat.say") ? $"friendssendcmd {command}" : $"{command}",
Color = color.Get(),
Close = _config.AutoClose ? Layer : string.Empty
}
}, parent, name);
}
}
private class IButton : IAnchors
{
[JsonProperty(PropertyName = "Высота | Height")]
public float Height;
[JsonProperty(PropertyName = "Ширина | Width")]
public float Width;
[JsonProperty(PropertyName = "Отступ | Margin")]
public float Margin;
}
private class SText : InterfacePosition
{
[JsonProperty(PropertyName = "Font Size")]
public int FontSize;
[JsonProperty(PropertyName = "Font")] public string Font;
[JsonProperty(PropertyName = "Align")] [JsonConverter(typeof(StringEnumConverter))]
public TextAnchor Align;
[JsonProperty(PropertyName = "Цвет игрока онлайн | Online Color")]
public IColor Color;
[JsonProperty(PropertyName = "Цвет игрока оффлайн | Offline Color")]
public IColor OfflineColor;
public void Get(ref CuiElementContainer container, bool online, string parent = "Hud", string name = null,
string text = "")
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
container.Add(new CuiLabel
{
RectTransform =
{AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax},
Text =
{
Text = $"{text}", Align = Align, FontSize = FontSize,
Color = online ? Color.Get() : OfflineColor.Get(),
Font = Font
}
}, parent, name);
}
}
private class IText : InterfacePosition
{
[JsonProperty(PropertyName = "Font Size")]
public int FontSize;
[JsonProperty(PropertyName = "Font")] public string Font;
[JsonProperty(PropertyName = "Align")] [JsonConverter(typeof(StringEnumConverter))]
public TextAnchor Align;
[JsonProperty(PropertyName = "Text Color")]
public IColor Color;
public void Get(ref CuiElementContainer container, string parent = "Hud", string name = null,
string text = "")
{
if (string.IsNullOrEmpty(name))
name = CuiHelper.GetGuid();
container.Add(new CuiLabel
{
RectTransform =
{AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax},
Text =
{
Text = $"{text}", Align = Align, FontSize = FontSize, Color = Color.Get(),
Font = Font
}
}, parent, name);
}
}
private class IColor
{
[JsonProperty(PropertyName = "HEX")] public string HEX;
[JsonProperty(PropertyName = "Непрозрачность | Opacity (0 - 100)")]
public readonly float Alpha;
public string Get()
{
if (string.IsNullOrEmpty(HEX)) HEX = "#FFFFFF";
var str = HEX.Trim('#');
if (str.Length != 6) throw new Exception(HEX);
var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);
return $"{(double) r / 255} {(double) g / 255} {(double) b / 255} {Alpha / 100}";
}
public IColor(string hex, float alpha)
{
HEX = hex;
Alpha = alpha;
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
if (_config.Version < Version)
UpdateConfigValues();
SaveConfig();
}
catch
{
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
}
}
private void UpdateConfigValues()
{
PrintWarning("Config update detected! Updating config values...");
var baseConfig = new Configuration();
if (_config.Version < new VersionNumber(1, 14, 0))
_config.AutoClose = baseConfig.AutoClose;
if (_config.Version < new VersionNumber(1, 15, 0))
{
_config.UseTeams = baseConfig.UseTeams;
_config.SAMs = baseConfig.SAMs;
}
_config.Version = Version;
PrintWarning("Config update completed!");
}
protected override void SaveConfig()
{
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig()
{
_config = new Configuration();
}
#endregion
#region Data
#region Fields
private static PluginData _data;
private Dictionary<ulong, PlayerData> _playersData = new Dictionary<ulong, PlayerData>();
#endregion
#region Save
private void SaveData()
{
if (_config.PlayerDatabase.Enabled && PlayerDatabase)
SaveDatabaseData();
else
SaveFilesData();
}
private void SaveDatabaseData()
{
foreach (var check in _playersData)
SaveData(check.Key, check.Value);
}
private void SaveFilesData()
{
_data.Players = _playersData;
Interface.Oxide.DataFileSystem.WriteObject(Name, _data);
}
private void SaveData(ulong userId, PlayerData data)
{
if (data == null) return;
var serializeObject = JsonConvert.SerializeObject(data);
if (serializeObject == null) return;
PlayerDatabase?.Call("SetPlayerData", userId.ToString(), _config.PlayerDatabase.Field, serializeObject);
}
#endregion
#region Load
private void LoadData()
{
if (!_config.PlayerDatabase.Enabled) LoadFilesData();
}
private void LoadFilesData()
{
try
{
_data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Name);
}
catch (Exception e)
{
PrintError(e.ToString());
}
if (_data == null) _data = new PluginData();
_playersData = _data.Players;
}
private void LoadPlayerData(ulong userId)
{
var success =
PlayerDatabase?.Call<string>("GetPlayerDataRaw", userId.ToString(), _config.PlayerDatabase.Field);
if (string.IsNullOrEmpty(success)) return;
var data = JsonConvert.DeserializeObject<PlayerData>(success);
if (data == null) return;
_playersData[userId] = data;
}
#endregion
#region Classes
private class PluginData
{
[JsonProperty(PropertyName = "Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, PlayerData> Players = new Dictionary<ulong, PlayerData>();
}
private class PlayerData
{
[JsonProperty(PropertyName = "Display Name")]
public string DisplayName;
[JsonProperty(PropertyName = "UserId")]
public ulong UserId;
[JsonProperty(PropertyName = "Friends", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly List<FriendData> Friends = new List<FriendData>();
[JsonProperty(PropertyName = "Removed Friends", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public readonly List<ulong> RemovedFriends = new List<ulong>();
public bool IsFriend(ulong friend)
{
return Friends.Exists(check => check.UserId == friend);
}
public FriendData GetFriend(ulong friend)
{
return Friends.Find(check => check.UserId == friend);
}
public void AddFriend(ulong friend)
{
if (!friend.IsSteamId() || IsFriend(friend)) return;
Friends.Add(new FriendData
{
UserId = friend,
FriendlyFire = _config.FriendlyFire,
Doors = _config.Doors,
Turrets = _config.Turrets,
Cupboard = _config.Cupboard,
Containers = _config.Containers,
SAMs = _config.SAMs
});
RemovedFriends.Remove(friend);
}
public void RemoveFriend(ulong friend)
{
Friends?.ToList().FindAll(f => f.UserId == friend).ForEach(f =>
{
if (!RemovedFriends.Contains(friend))
RemovedFriends.Add(friend);
Friends.Remove(f);
});
}
}
private class FriendData
{
[JsonProperty(PropertyName = "UserId")]
public ulong UserId;
[JsonProperty(PropertyName = "FriendlyFire")]
public bool FriendlyFire;
[JsonProperty(PropertyName = "Doors")] public bool Doors;
[JsonProperty(PropertyName = "Turrets")]
public bool Turrets;
[JsonProperty(PropertyName = "Cupboard")]
public bool Cupboard;
[JsonProperty(PropertyName = "Containers")]
public bool Containers;
[JsonProperty(PropertyName = "SAMs")] public bool SAMs;
}
#endregion
#region Utils
private static PlayerData GetPlayerData(BasePlayer player)
{
if (player == null || !player.userID.IsSteamId()) return null;
if (!_instance._playersData.ContainsKey(player.userID))
_instance._playersData.Add(player.userID, new PlayerData
{
DisplayName = player.displayName,
UserId = player.userID
});
return _instance._playersData[player.userID];
}
private static PlayerData GetPlayerData(ulong userId)
{
if (!userId.IsSteamId()) return null;
if (!_instance._playersData.ContainsKey(userId))
_instance._playersData.Add(userId, new PlayerData
{
UserId = userId
});
return _instance._playersData[userId];
}
private static PlayerData FindPlayerData(string user)
{
return _instance._playersData.FirstOrDefault(x =>
x.Key.ToString() == user ||
!string.IsNullOrEmpty(x.Value.DisplayName) &&
x.Value.DisplayName.StartsWith(user, StringComparison.CurrentCultureIgnoreCase)).Value;
}
#endregion
#endregion
#region Hooks
private void Init()
{
_instance = this;
LoadData();
AddCovalenceCommand(new[] {"ff", "friendlyfire", "friend", "friends", "f", "fmenu", "f.menu"},
nameof(CmdFriends));
if (!_config.AddTeam)
{
Unsubscribe(nameof(OnTeamLeave));
Unsubscribe(nameof(OnTeamAcceptInvite));
Unsubscribe(nameof(OnTeamKick));
Unsubscribe(nameof(OnTeamInvite));
Unsubscribe(nameof(OnTeamRejectInvite));
}
if (!_config.PlayerDatabase.Enabled)
Unsubscribe(nameof(OnPlayerDisconnected));
}
private void OnServerInitialized()
{
if (!ImageLibrary) PrintWarning("IMAGE LIBRARY IS NOT INSTALLED.");
#region Init
foreach (var player in BasePlayer.activePlayerList) OnPlayerConnected(player);
#endregion
#region Notifications
Notifications?.Call("AddImage", _config.FriendInvite.Image, _config.FriendInvite.Url);
Notifications?.Call("AddImage", _config.Notify.Image, _config.Notify.Url);
#endregion
#region Team
RelationshipManager.maxTeamSize = _config.MaxFriendsAmount + 1;
#endregion
#region Auth
foreach (var entity in BaseNetworkable.serverEntities.OfType<BaseEntity>()) CheckEntity(entity);
#endregion
timer.Every(1, TimeHandle);
}
private void OnServerSave()
{
timer.In(Random.Range(2f, 7f), SaveData);
}
private void Unload()
{
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Layer);
SaveData();
_instance = null;
_config = null;
_data = null;
}
private void OnPlayerConnected(BasePlayer player)
{
if (player == null || !player.userID.IsSteamId()) return;
var data = GetPlayerData(player);
if (data == null) return;
data.DisplayName = player.displayName;
GetAvatar(player.userID,
avatar => ImageLibrary?.Call("AddImage", avatar, $"avatar_{player.UserIDString}"));
if (_config.AddTeam && data.Friends.Count > 0)
{
RelationshipManager.PlayerTeam team;
var friend =
data.Friends.Find(x => RelationshipManager.ServerInstance.playerToTeam.ContainsKey(x.UserId));
if (friend == null)
{
team = RelationshipManager.ServerInstance.CreateTeam();
team.AddPlayer(player);
team.SetTeamLeader(player.userID);
var friendPlayer = FindPlayer(data.Friends);
if (friendPlayer != null) team.AddPlayer(friendPlayer);
}
else
{
team = RelationshipManager.ServerInstance.playerToTeam[friend.UserId];
if (team == null) return;
team.AddPlayer(player);
}
}
if (_config.PlayerDatabase.Enabled) LoadPlayerData(player.userID);
}
private void OnPlayerDisconnected(BasePlayer player)
{
if (player == null) return;
SaveData(player.userID, GetPlayerData(player.userID));
}
private void OnEntityTakeDamage(BasePlayer player, HitInfo info)
{
if (player == null || info == null) return;
var initiator = info.InitiatorPlayer;
if (initiator == null) return;
if (!IsFriend(player.userID, initiator.userID) || player.userID == initiator.userID)
return;
var data = GetPlayerData(initiator);
var friend = data?.Friends.Find(x => x.UserId == player.userID);
if (friend == null || friend.FriendlyFire) return;
info.damageTypes.ScaleAll(0);
if (IsCd(initiator.userID)) return;
Notify(initiator, _config.Notify.Delay, Msg(NotifyTitle, initiator.UserIDString),
Msg(FF, initiator.UserIDString, player.displayName), _config.Notify.Image);
SetCd(initiator.userID);
}
#region Team
private void OnTeamLeave(RelationshipManager.PlayerTeam playerTeam, BasePlayer player)
{
if (playerTeam == null || player == null) return;
playerTeam.members.ToList().ForEach(user =>
{
GetPlayerData(player)?.RemoveFriend(user);
GetPlayerData(user)?.RemoveFriend(player.userID);
});
UpdateAuthList(player.userID, AutoAuthType.All);
UpdateTeamAuthList(playerTeam.members);
}
private void OnTeamAcceptInvite(RelationshipManager.PlayerTeam playerTeam, BasePlayer player)
{
NextTick(() =>
{
if (playerTeam == null || player == null || !player.userID.IsSteamId()) return;
var invite = _invites.Find(x => x.Target == player);
if (invite != null && playerTeam.members.Exists(x => invite.Inviter.userID == x))
{
AcceptInvite(player);
return;
}
if (playerTeam.members.Contains(player.userID))
if (_config.UseTeams)
{
playerTeam.members.ToList().ForEach(user =>
{
if (user == player.userID) return;
GetPlayerData(player)?.AddFriend(user);
GetPlayerData(user)?.AddFriend(player.userID);
Log("friends", $"Player '{player}' added '{user}' as a friend");
});
UpdateTeamAuthList(playerTeam.members);
}
});
}
private void OnTeamKick(RelationshipManager.PlayerTeam playerTeam, BasePlayer player, ulong target)
{
NextTick(() =>
{
if (playerTeam == null) return;
if (!playerTeam.members.Contains(target))
{
playerTeam.members.ToList().ForEach(user =>
{
GetPlayerData(user)?.RemoveFriend(target);
GetPlayerData(target)?.RemoveFriend(user);
});
UpdateAuthList(target, AutoAuthType.All);
UpdateTeamAuthList(playerTeam.members);
}
});
}
private void OnTeamInvite(BasePlayer inviter, BasePlayer target)
{
SendInvite(inviter, target);
}
// ... [Code preview truncated due to length. Full source in attached file] ...