C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core.Plugins;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Oxide.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;
using System.Text;
using Oxide.Core.Libraries;
using Oxide.Game.Rust.Cui;
using System.Linq;
using System.Text.RegularExpressions;
namespace Oxide.Plugins {
[Info("Computers Plus", "mr01sam", "1.0.6")]
[Description("Adds new functionality to the computer stations.")]
partial class ComputersPlus : CovalencePlugin {
/*
* CHANGELOG
* - Fixed bug where players would not get emails if they were offline.* - Added message screen for players without permissions.* - Fixed broken images.*/
private static ComputersPlus PLUGIN;
[PluginReference]
private Plugin ImageLibrary;
/* Global Data */
private static Dictionary<string, string> Language = new Dictionary<string, string>();
private static Dictionary<string, ComputersPlusApp> RegisteredApps = new Dictionary<string, ComputersPlusApp>();
private static Dictionary<string, string> AppsInUse = new Dictionary<string, string>();
#region Properties
internal EZUI.Component AppComponent {
get;
private set;
}
= null;
private bool Success {
get;
set;
}
= true;
#endregion
#region Permissions
private const string PermissionAdmin = "computersplus.admin";
/* Additional permissions are registered for each App in the format computersplus.<app-name> */
#endregion
#region Initialization
void CreateApps() {
if (RegisteredApps == null) {
RegisteredApps = new Dictionary<string, ComputersPlusApp>();
}
RegisterApp(EMAIL_APP);
}
void Init() {
PLUGIN = this;
UnsubscribeAll();
}
void Unload() {
CleanupUI();
UnloadApps();
NullifyStaticVariables();
}
void OnServerSave() {
SaveApps();
}
void OnServerInitialized(bool initial) {
try {
ImageLibrary.Call("isLoaded", null);
}
catch (Exception) {
PrintWarning($"The required dependency ImageLibary is not installed, {Name} will not work properly without it.");
Success = false;
return;
}
EZUI.GenerateToken();
LoadImages();
InitApps();
SubscribeAll();
}
void UnsubscribeAll() {
Unsubscribe(nameof(OnEntityMounted));
Unsubscribe(nameof(OnEntityDismounted));
Unsubscribe(nameof(CanDismountEntity));
Unsubscribe(nameof(OnBookmarkControl));
Unsubscribe(nameof(OnBookmarkControlEnd));
}
void SubscribeAll() {
Subscribe(nameof(OnEntityMounted));
Subscribe(nameof(OnEntityDismounted));
Subscribe(nameof(CanDismountEntity));
Subscribe(nameof(OnBookmarkControl));
Subscribe(nameof(OnBookmarkControlEnd));
}
void NullifyStaticVariables() {
PLUGIN = null;
RegisteredApps = null;
AppsInUse = null;
Language = null;
}
void CleanupUI() {
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
EZUI.DestroyAll(BasePlayer.activePlayerList[i]);
}
}
void InitApps() {
foreach(ComputersPlusApp app in RegisteredApps.Values) {
ImageLibrary.Call<bool>("AddImage", app.IconUrl, $"{app.Id}Icon", 0UL);
Call(app.InitMethod);
}
}
void SaveApps() {
foreach (ComputersPlusApp app in RegisteredApps.Values) {
Call(app.SaveMethod);
}
}
void UnloadApps() {
foreach (ComputersPlusApp app in RegisteredApps.Values) {
Call(app.UnloadMethod);
}
}
#endregion
#region Oxide Hooks
void OnEntityMounted(ComputerStation entity, BasePlayer basePlayer) {
ShowHomeUi(basePlayer);
}
void OnEntityDismounted(ComputerStation entity, BasePlayer basePlayer) {
CloseUi(basePlayer);
NextTick(() => {
CloseUi(basePlayer);
// incase it doesn't close initally
}
);
}
object CanDismountEntity(BasePlayer player, ComputerStation computerStation) {
if (IsUsingApp(player)) {
return false;
}
return null;
}
object OnBookmarkControl(ComputerStation computerStation, BasePlayer basePlayer, string bookmarkName, IRemoteControllable remoteControllable) {
CloseUi(basePlayer);
return null;
}
object OnBookmarkControlEnd(ComputerStation computerStation, BasePlayer basePlayer, BaseEntity controlledEntity) {
ShowHomeUi(basePlayer);
return null;
}
#endregion
#region Helper Methods
void RegisterApp(ComputersPlusApp newApp) {
RegisteredApps.Add(newApp.Id, newApp);
if (!permission.PermissionExists(newApp.Permission)) {
permission.RegisterPermission(newApp.Permission, this);
}
Call(newApp.CreateMethod);
}
void LoadImages() {
ImageLibrary.Call<bool>("AddImage", "https://i.imgur.com/43ytxMa.png", $"App.Close", 0UL);
ImageLibrary.Call<bool>("AddImage", "https://i.imgur.com/oM0NEIP.png", $"PC.Denied", 0UL);
}
bool IsUsingComputer(BasePlayer basePlayer) => basePlayer.GetMounted() != null ? (basePlayer.GetMounted() is ComputerStation) : false;
bool IsUsingApp(BasePlayer player, string appId = null) {
if (appId != null) return AppsInUse.ContainsKey(player.UserIDString) && AppsInUse[player.UserIDString] == appId;
return AppsInUse.ContainsKey(player.UserIDString);
}
bool UserHasAnyPermission(BasePlayer basePlayer) {
return RegisteredApps.Values.Any(app => permission.UserHasPermission(basePlayer.UserIDString, app.Permission));
}
#endregion
#region UI
private readonly string BASE_UI_ID = "PC";
private readonly string HOME_UI_ID = "HOME";
private readonly string APP_UI_ID = "APP";
void CloseUi(BasePlayer basePlayer) {
AppsInUse.Remove(basePlayer.UserIDString);
var ui = EZUI.Find(basePlayer.UserIDString, BASE_UI_ID);
ui?.Destroy(basePlayer);
}
void CloseHomeUi(BasePlayer basePlayer) {
var ui = EZUI.Find(basePlayer.UserIDString, $"{BASE_UI_ID}.Content.{HOME_UI_ID}");
ui?.Destroy(basePlayer);
}
void CloseAppUi(BasePlayer basePlayer) {
var ui = EZUI.Find(basePlayer.UserIDString, $"{BASE_UI_ID}.Content.{HOME_UI_ID}.Content.{APP_UI_ID}");
ui?.Destroy(basePlayer);
AppsInUse.Remove(basePlayer.UserIDString);
}
EZUI.Component CreateAppGrid(EZUI.Component home, BasePlayer basePlayer) {
var grid = new EZUI.LayoutComponent("Apps") {
Transparent = true, RowCount = 8, ColCount = 15, PixelPadding = new EZUI.Dir<int>(5)
}
.Create(home);
foreach (ComputersPlusApp app in RegisteredApps.Values) {
if (app != null && permission.UserHasPermission(basePlayer.UserIDString, app.Permission)) {
var box = new EZUI.BoxComponent(app.Id) {
Transparent = true
}
.Create(grid);
var icon = new EZUI.ImageComponent("Icon") {
ImageKey = $"{app.Id}Icon", Size = 0.6f, AnchorTo = EZUI.Anchor.TopCenter
}
.Create(box);
var text = new EZUI.TextComponent("Title") {
Text = app.Name, TextAlign = TextAnchor.UpperCenter, FontSize = 10, PixelHeight = 25, FontColor = EZUI.StyleSheet.DEFAULT.FontColorLight1, AnchorTo = EZUI.Anchor.BottomCenter
}
.Create(box);
var button = new EZUI.ButtonComponent("Click") {
Transparent = true, Command = $"app.launch {app.Id}", ClickSfx = SFX_LAUNCH
}
.Create(box);
}
}
return grid;
}
void ShowHomeUi(BasePlayer basePlayer) {
if (Success) {
bool hasAccess = UserHasAnyPermission(basePlayer);
var ui = new EZUI.BoxComponent(BASE_UI_ID) {
Height = 0.75f, Centered = true, Width = 0.75f,
}
.Create();
var home = new EZUI.BoxComponent(HOME_UI_ID) {
OutlinePixelWeight = 5, BackgroundColor = hasAccess ? EZUI.StyleSheet.DEFAULT.HomeBackgroundColor : EZUI.Color.BLACK, Centered = true
}
.Create(ui);
if (hasAccess) {
var version = new EZUI.TextComponent("Version") {
AnchorTo = EZUI.Anchor.BottomRight, AutoSizeHeight = true, AutoSizeWidth = true, FontColor = EZUI.Color.WHITE, FontSize = 10, Up = 5, Left = 5, TextAlign = TextAnchor.LowerRight, Text = $"COBALT OS v{Version.Major}.{Version.Minor}.{Version.Patch}"
}
.Create(home);
var grid = CreateAppGrid(home, basePlayer);
}
else {
var denied = new EZUI.ImageComponent("Deny") {
ImageKey = "PC.Denied", ImageColor = EZUI.Color.RED, Size = 0.2f, AnchorTo = EZUI.Anchor.MiddleCenter, Up = 50
}
.Create(home);
var text = new EZUI.TextComponent("Text") {
Text = Lang("app.access.denied", basePlayer), FontColor = EZUI.Color.RED, TextAlign = TextAnchor.UpperCenter, FontSize = 28, TopAlign = denied.BottomSide.Pixels, Down = 20, PixelHeight = 100
}
.Create(home);
var reason = new EZUI.TextComponent("Reason") {
Text = Lang("app.access.reason", basePlayer), FontColor = EZUI.Color.WHITE, TextAlign = TextAnchor.LowerCenter, AnchorTo = EZUI.Anchor.BottomCenter, FontSize = 12, PixelHeight = 100
}
.Create(home);
}
ui.Render(basePlayer);
}
}
void ShowAppUi(BasePlayer basePlayer, ComputersPlusApp app) {
var home = EZUI.Find(basePlayer, $"{BASE_UI_ID}.{HOME_UI_ID}");
var window = new EZUI.WindowComponent(APP_UI_ID) {
HeaderText = app.Name, Scale = 0.85f, Centered = true, OnCloseCommand = "app.close"
}
.Create(home);
this.AppComponent = window;
window.Render(basePlayer);
if (!AppsInUse.ContainsKey(basePlayer.UserIDString)) {
AppsInUse.Add(basePlayer.UserIDString, app.Id);
}
}
#endregion
#region Commands
[Command("app.launch")]
private void cmd_app_launch(IPlayer player, string command, string[] args) {
BasePlayer basePlayer = player.Object as BasePlayer;
if (basePlayer != null && IsUsingComputer(basePlayer)) {
string appId = args[0];
ComputersPlusApp app = null;
if (RegisteredApps.TryGetValue(appId, out app) && permission.UserHasPermission(player.Id, app.Permission)) {
ShowAppUi(basePlayer, app);
Call(app.LaunchMethod, basePlayer.UserIDString);
}
else {
player.Reply(Lang("app.launch.error", basePlayer));
}
}
}
[Command("app.close")]
private void cmd_app_close(IPlayer player, string command, string[] args) {
BasePlayer basePlayer = player.Object as BasePlayer;
if (basePlayer != null) {
CloseAppUi(basePlayer);
}
}
[Command("pc.leave")]
private void cmd_pc_leave(IPlayer player, string command, string[] args) {
BasePlayer basePlayer = player.Object as BasePlayer;
if (basePlayer != null) {
EZUI.DestroyAll(basePlayer);
BaseMountable mountable = basePlayer.GetMounted();
if (mountable != null && mountable is ComputerStation) {
mountable.DismountPlayer(basePlayer);
}
}
}
#endregion
}
}
namespace Oxide.Plugins {
partial class ComputersPlus {
class ComputersPlusApp {
private string _id;
private string _name;
private string _iconUrl;
private string _permission;
public ComputersPlusApp(string id, string name, string iconUrl, string permission) {
this._id = id;
this._name = name;
this._iconUrl = iconUrl;
this._permission = permission;
}
public string Id {
get {
return _id;
}
}
public string Name {
get {
return _name;
}
}
public string IconUrl {
get {
return _iconUrl;
}
}
public string Permission {
get {
return _permission;
}
}
public string LaunchMethod {
get {
return $"Launch{Id.TitleCase()}App";
}
}
public string SaveMethod {
get {
return $"Save{Id.TitleCase()}App";
}
}
public string CreateMethod {
get {
return $"Create{Id.TitleCase()}App";
}
}
public string InitMethod {
get {
return $"Init{Id.TitleCase()}App";
}
}
public string UnloadMethod {
get {
return $"Unload{Id.TitleCase()}App";
}
}
public override string ToString() {
return Id.ToString();
}
}
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
private Configuration config;
private partial class Configuration {
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) throw new Exception();
}
catch {
PrintError("Your configuration file contains an error.Default configuration values will be used.It is recommended to backup your current configuration file and remove it to generate a fresh one.");
LoadDefaultConfig();
}
base.SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultConfig() => config = new Configuration();
}
}
namespace Oxide.Plugins {
partial class ComputersPlus {
class DoubleDictionary<TkeyA, TkeyB, Tvalue> {
private Dictionary<TkeyA, Dictionary<TkeyB, Tvalue>> a2b;
private Dictionary<TkeyB, Dictionary<TkeyA, Tvalue>> b2a;
public DoubleDictionary() {
a2b = new Dictionary<TkeyA, Dictionary<TkeyB, Tvalue>>();
b2a = new Dictionary<TkeyB, Dictionary<TkeyA, Tvalue>>();
}
public void Set(TkeyA keyA, TkeyB keyB, Tvalue value) {
if (!a2b.ContainsKey(keyA)) a2b.Add(keyA, new Dictionary<TkeyB, Tvalue>());
if (!b2a.ContainsKey(keyB)) b2a.Add(keyB, new Dictionary<TkeyA, Tvalue>());
if (!a2b[keyA].ContainsKey(keyB)) a2b[keyA].Add(keyB, value);
else a2b[keyA][keyB] = value;
if (!b2a[keyB].ContainsKey(keyA)) b2a[keyB].Add(keyA, value);
else b2a[keyB][keyA] = value;
}
public Tvalue Get(TkeyA keyA, TkeyB keyB) {
if (a2b.ContainsKey(keyA) && a2b[keyA].ContainsKey(keyB)) return a2b[keyA][keyB];
return default(Tvalue);
}
public Dictionary<TkeyB, Tvalue> GetA(TkeyA keyA) {
if (a2b.ContainsKey(keyA)) return a2b[keyA];
return new Dictionary<TkeyB, Tvalue>();
}
public Dictionary<TkeyA, Tvalue> GetB(TkeyB keyB) {
if (b2a.ContainsKey(keyB)) return b2a[keyB];
return new Dictionary<TkeyA, Tvalue>();
}
public bool ContainsKey(TkeyA keyA, TkeyB keyB) {
return a2b.ContainsKey(keyA) && a2b[keyA].ContainsKey(keyB);
}
public bool ContainsKey(TkeyA keyA) {
return a2b.ContainsKey(keyA);
}
public void Delete(TkeyA keyA, TkeyB keyB) {
if (a2b.ContainsKey(keyA) && a2b[keyA].ContainsKey(keyB)) a2b[keyA].Remove(keyB);
if (b2a.ContainsKey(keyB) && b2a[keyB].ContainsKey(keyA)) b2a[keyB].Remove(keyA);
}
public void DeleteA(TkeyA keyA) {
foreach (TkeyB keyB in b2a.Keys) if (b2a[keyB].ContainsKey(keyA)) b2a[keyB].Remove(keyA);
if (a2b.ContainsKey(keyA)) a2b.Remove(keyA);
}
public void DeleteB(TkeyB keyB) {
foreach (TkeyA keyA in a2b.Keys) if (a2b[keyA].ContainsKey(keyB)) a2b[keyA].Remove(keyB);
if (b2a.ContainsKey(keyB)) b2a.Remove(keyB);
}
public int Count(TkeyA keyA) {
return a2b[keyA].Count;
}
}
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
protected override void LoadDefaultMessages() {
Language = new Dictionary<string, string>();
CreateApps();
Language = Language.Concat(new Dictionary<string, string> {
["app.error.launch"]
= "That app is not registered or this player does not have permission to use it.", ["app.access.denied"] = "Access Denied", ["app.access.reason"] = "You do not have any app permissions for this plugin."
}
).ToDictionary(x => x.Key, y => y.Value);
lang.RegisterMessages(Language, this);
}
private string Lang(string key, string id, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private string Lang(string key, BasePlayer basePlayer, params object[] args) => string.Format(lang.GetMessage(key, this, basePlayer?.UserIDString), args);
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
public static readonly string SFX_LAUNCH = "assets/prefabs/tools/binoculars/sound/fovchange.prefab";
public static readonly string SFX_CLICK = "assets/prefabs/tools/detonator/effects/unpress.prefab";
public static readonly string SFX_SUBMIT = "assets/prefabs/tools/flashlight/effects/turn_on.prefab";
}
}
namespace Oxide.Plugins {
partial class ComputersPlus {
private T LoadDataFile<T>(string fileName) {
try {
return Interface.Oxide.DataFileSystem.ReadObject<T>($"{Name}/{fileName}");
}
catch (Exception) {
return default(T);
}
}
private void SaveDataFile<T>(string fileName, T data) {
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/{fileName}", data);
}
private void PlaySfx(BasePlayer player, string sound) => EffectNetwork.Send(new Effect(sound, player, 0, Vector3.zero, Vector3.forward), player.net.connection);
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
private readonly ComputersPlusApp EMAIL_APP = new ComputersPlusApp("email", "Email", "https://freeiconshop.com/wp-content/uploads/edd/mail-var-outline-filled.png", "computersplus.email");
#region App Hooks
void CreateEmailApp(string userIdString) {
RegisterEmailLanguage();
}
void InitEmailApp() {
EmailManager.MaxInboxSize = config.Email.MaxInboxSize;
LoadEmails();
AddEmailAppImages();
RegisterEmailFunctions();
}
void LaunchEmailApp(string userIdString) {
BasePlayer basePlayer = BasePlayer.FindByID(ulong.Parse(userIdString));
RenderEmailApp(basePlayer);
}
void SaveEmailApp() {
SaveEmails();
}
void UnloadEmailApp() {
SaveEmails();
}
#endregion
#region Config
private partial class Configuration {
[JsonProperty(PropertyName = "Email Config")]
public EmailConfiguration Email = new EmailConfiguration();
}
private class EmailConfiguration {
[JsonProperty(PropertyName = "Max Inbox Size")]
public int MaxInboxSize {
get;
set;
}
= 24;
}
#endregion
#region Helper Methods
private void AddEmailAppImages() {
ImageLibrary.Call<bool>("AddImage", "https://freeiconshop.com/wp-content/uploads/edd/mail-var-outline-filled.png", $"{EMAIL_APP.Id}Unread", 0UL);
ImageLibrary.Call<bool>("AddImage", "https://imgur.com/GYiA73s.png", $"{EMAIL_APP.Id}Read", 0UL);
ImageLibrary.Call<bool>("AddImage", "https://imgur.com/dUlC5Yf.png", $"{EMAIL_APP.Id}Compose", 0UL);
ImageLibrary.Call<bool>("AddImage", "https://i.imgur.com/HMcxb5Q.png", $"{EMAIL_APP.Id}Delete", 0UL);
ImageLibrary.Call<bool>("AddImage", "https://uxwing.com/wp-content/themes/uxwing/download/communication-chat-call/send-icon.png", $"{EMAIL_APP.Id}Send", 0UL);
}
private void RegisterEmailLanguage() {
Language = Language.Concat(new Dictionary<string, string> {
["email.compose"]
= "Compose", ["email.subject"] = "Subject", ["email.recipients"] = "Recipients", ["email.send"] = "Send", ["email.message"] = "Message", ["email.to"] = "To", ["email.from"] = "From", ["email.received"] = "Received", ["email.unread"] = "Unread", ["email.inbox"] = "Inbox", ["email.days"] = "days ago", ["email.hours"] = "hrs ago", ["email.minutes"] = "min ago", ["email.now"] = "just now", ["email.cleared"] = "Cleared inbox for {0}", ["email.success"] = "Successfully sent to {0} recipients", ["email.partial"] = "Successfully sent to {0} recipients.Failed to find {1} recipients.", ["email.fail"] = "Failed to find any recipients.No messages sent.", ["email.usage.clear"] = "Usage: email.clear <username>"
}
).ToDictionary(x => x.Key, x => x.Value);
}
private void RegisterEmailFunctions() {
EZUI.RegisterFunction(nameof(RenderEmailView));
EZUI.RegisterFunction(nameof(RenderEmailCompose));
EZUI.RegisterFunction(nameof(SendEmail));
EZUI.RegisterFunction(nameof(DeleteEmail));
}
private void LoadEmails() {
var existing = LoadDataFile<Dictionary<string, List<EmailMessage>>>("Emails");
if (existing != null) {
EmailManager.SetAllEmails(existing);
}
}
private void SaveEmails() {
var all = EmailManager.GetAllEmails();
SaveDataFile("Emails", all);
}
private void DeleteEmail(string userIdString, string emailGuid) {
BasePlayer basePlayer = BasePlayer.FindAwakeOrSleeping(userIdString);
if (basePlayer != null) {
EmailManager.DeleteEmail(userIdString, Guid.Parse(emailGuid));
var inbox = UpdateInbox(basePlayer);
inbox.Paginator?.UpdatePageAndRender(basePlayer);
}
}
private void SendEmail(string userIdString) {
BasePlayer basePlayer = BasePlayer.FindAwakeOrSleeping(userIdString);
var recipients = EZUI.Get(basePlayer, EMAIL_APP, "Recipients")?.As<EZUI.InputComponent>()?.Data;
var subject = EZUI.Get(basePlayer, EMAIL_APP, "Subject")?.As<EZUI.InputComponent>()?.Data;
var text = EZUI.Get(basePlayer, EMAIL_APP, "Message")?.As<EZUI.InputComponent>()?.Data;
var split = recipients.Split(',').Select(x => x.Trim()).Where(x => x.Length > 0).Distinct().ToList();
var recipientIds = split.Select(y => players.FindPlayer(y)?.Id).Distinct().Where(x => !string.IsNullOrEmpty(x)).ToList();
if (recipients != null && subject != null && text != null) {
int count = 0;
if (split.Count > 0) {
foreach (var id in recipientIds) {
var email = new EmailMessage(userIdString, id, subject, text);
EmailManager.SendEmail(email);
count++;
}
}
else {
UpdateInfoText(basePlayer, Lang("email.fail", basePlayer));
}
string status;
if (count == split.Count) {
status = Lang("email.success", basePlayer, count);
}
else if (count > 0) {
int fails = split.Count - count;
status = Lang("email.partial", basePlayer, count, fails);
}
else {
status = Lang("email.fail", basePlayer, count);
}
var window = EZUI.Get(basePlayer, EMAIL_APP, "Compose");
if (window != null) {
window.Destroy(basePlayer);
timer.In(0.5f, () => {
UpdateInfoText(basePlayer, status);
timer.In(4f, () => {
UpdateInfoText(basePlayer, string.Empty);
}
);
}
);
}
UpdateInbox(basePlayer).Render(basePlayer);
}
}
#endregion
#region UI
private void RenderEmailCompose(string userIdString) {
var basePlayer = BasePlayer.FindByID(ulong.Parse(userIdString));
if (basePlayer != null) {
var height = 45;
var width = 0.5f;
var window = new EZUI.WindowComponent("Compose") {
HeaderText = Lang("email.compose", basePlayer), Scale = 0.5f
}
.Tag(EMAIL_APP).Create();
var subject = new EZUI.InputComponent("Subject") {
Text = $"{Lang("email.subject", basePlayer)}:", CharsLimit = 55, AnchorTo = EZUI.Anchor.TopLeft, PixelMargin = new EZUI.Dir<int>(0, 0, 10, 0), PixelHeight = height, Width = width
}
.Tag(EMAIL_APP).Create(window);
var recipients = new EZUI.InputComponent("Recipients") {
Text = $"{Lang("email.recipients", basePlayer)}:", CharsLimit = 1024, TopAlign = subject.BottomSide.Pixels, PixelMargin = new EZUI.Dir<int>(0, 0, 10, 0), PixelHeight = height, Width = width
}
.Tag(EMAIL_APP).Create(window);
var send = new EZUI.ButtonComponent("Send") {
Text = Lang("email.send", basePlayer), AnchorTo = EZUI.Anchor.BottomRight, TextAlign = TextAnchor.MiddleCenter, BackgroundColor = EZUI.StyleSheet.DEFAULT.BackgroundColorDark1, OutlineColor = EZUI.StyleSheet.DEFAULT.BackgroundColorLight1, OutlinePixelWeight = 1, PixelWidth = 75, PixelHeight = 25, ClickSfx = SFX_SUBMIT, Command = $"ezui.call {EZUI.Token} SendEmail {basePlayer.UserIDString}", PixelMargin = new EZUI.Dir<int>(5, 0, 0, 0)
}
.Create(window);
var message = new EZUI.InputComponent("Message") {
Text = $"{Lang("email.message", basePlayer)}:", CharsLimit = 2048, TextAlign = TextAnchor.UpperLeft, TopAlign = recipients.BottomSide.Pixels, BottomAlign = send.TopSide.Pixels
}
.Tag(EMAIL_APP).Create(window);
window.Render(basePlayer);
}
}
private void RenderEmailView(string userIdString, string emailGuid) {
var basePlayer = BasePlayer.FindByID(ulong.Parse(userIdString));
if (basePlayer != null) {
var email = EmailManager.GetEmail(userIdString, Guid.Parse(emailGuid));
email.MarkAsRead();
UpdateInbox(basePlayer).Render(basePlayer);
var window = new EZUI.WindowComponent("View") {
HeaderText = email.Subject, Scale = 0.5f,
}
.Create();
var height = 20;
var width = 100;
var to = new EZUI.LayoutComponent("To") {
AnchorTo = EZUI.Anchor.TopLeft, PixelHeight = height, PixelWidth = width, ColCount = 2, Entries = new List<EZUI.Component>() {
new EZUI.TextComponent("Label") {
Text = $"{Lang("email.to", basePlayer)}:"
}
, new EZUI.TextComponent("Value") {
Text = $"{email.RecipientDisplayName}"
}
,
}
}
.Create(window);
var from = new EZUI.LayoutComponent("From") {
TopAlign = to.BottomSide.Pixels, PixelHeight = height, PixelWidth = width, ColCount = 2, Entries = new List<EZUI.Component>() {
new EZUI.TextComponent("Label") {
Text = $"{Lang("email.from", basePlayer)}:"
}
, new EZUI.TextComponent("Value") {
Text = $"{email.ComposerDisplayName}"
}
,
}
}
.Create(window);
var received = new EZUI.LayoutComponent("Received") {
TopAlign = from.BottomSide.Pixels, PixelHeight = height, PixelWidth = width, ColCount = 2, Entries = new List<EZUI.Component>() {
new EZUI.TextComponent("Label") {
Text = $"{Lang("email.received", basePlayer)}:"
}
, new EZUI.TextComponent("Value") {
Text = $"{email.ElapsedTimeString(basePlayer)}"
}
,
}
}
.Create(window);
var subject = new EZUI.LayoutComponent("Subject") {
TopAlign = received.BottomSide.Pixels, PixelHeight = height, PixelWidth = width, ColCount = 2, PixelMargin = new EZUI.Dir<int>(0, 0, 5, 0), Entries = new List<EZUI.Component>() {
new EZUI.TextComponent("Label") {
Text = $"{Lang("email.subject", basePlayer)}:"
}
, new EZUI.TextComponent("Value") {
Text = $"{email.Subject}"
}
,
}
}
.Create(window);
var text = new EZUI.TextComponent("Message") {
TopAlign = subject.BottomSide.Pixels, TextAlign = TextAnchor.UpperLeft, PixelPadding = new EZUI.Dir<int>(5), Text = email.Text, BackgroundColor = EZUI.Color.WHITE
}
.Create(window);
window.Render(basePlayer);
}
}
private EZUI.Component CreateEmailEntryComponent(BasePlayer basePlayer, EmailMessage email, EZUI.Component list) {
var box = new EZUI.BoxComponent("Item") {
BackgroundColor = email.Unread ? EZUI.StyleSheet.DEFAULT.BackgroundColorHighlight1 : EZUI.StyleSheet.DEFAULT.BackgroundColorLight2, PixelPadding = new EZUI.Dir<int>(5),
}
.Create(list);
var img = new EZUI.ImageComponent("Icon") {
Transparent = true, Height = 0.8f, PixelWidth = 18, //PixelHeight = 36,
ImageKey = $"{EMAIL_APP.Id}Unread", ImageHidden = !email.Unread, CenterY = true, AnchorTo = EZUI.Anchor.Left
}
.Create(box);
var from = new EZUI.TextComponent("From") {
Text = email.ComposerDisplayName, PixelWidth = 100, Right = 100
}
.Create(box);
var subject = new EZUI.TextComponent("Subject") {
Text = email.Subject, PixelWidth = 250, Right = 250
}
.Create(box);
var received = new EZUI.TextComponent("Received") {
Text = email.ElapsedTimeString(basePlayer), PixelWidth = 100, Right = 550
}
.Create(box);
var btn = new EZUI.ButtonComponent("Clickable") {
Transparent = true, Command = $"ezui.call {EZUI.Token} RenderEmailView {basePlayer.UserIDString} {email.Guid}", Width = 0.97f
}
.Create(box);
var delete = new EZUI.ButtonComponent("Delete") {
Transparent = true, ImageKey = $"{EMAIL_APP.Id}Delete", Command = $"ezui.call {EZUI.Token} DeleteEmail {basePlayer.UserIDString} {email.Guid}", Size = 0.5f, CenterY = true, AnchorTo = EZUI.Anchor.MiddleRight, Left = 5
}
.Create(box);
return box;
}
EZUI.LayoutComponent UpdateInbox(BasePlayer basePlayer, EZUI.Component inbox = null) {
if (inbox == null) {
inbox = EZUI.Get(basePlayer, EMAIL_APP, "Inbox");
}
var layout = inbox.As<EZUI.LayoutComponent>();
layout.ClearEntries();
var emails = EmailManager.GetPlayerInbox(basePlayer.UserIDString);
foreach (var email in emails) {
var entry = CreateEmailEntryComponent(basePlayer, email, layout);
}
UpdateStatusText(basePlayer);
return layout;
}
private string StatusText(BasePlayer basePlayer) {
return $"{Lang("email.inbox", basePlayer)} ({EmailManager.GetPlayerInboxCount(basePlayer.UserIDString)}/{EmailManager.MaxInboxSize})";
}
void UpdateStatusText(BasePlayer basePlayer) {
var status = EZUI.Get(basePlayer, EMAIL_APP, "Status")?.As<EZUI.TextComponent>();
if (status != null) {
status.Text = StatusText(basePlayer);
status.Create().Render(basePlayer);
}
}
void UpdateInfoText(BasePlayer basePlayer, string newText) {
var info = EZUI.Get(basePlayer, EMAIL_APP, "Info")?.As<EZUI.TextComponent>();
if (info != null) {
info.Text = newText;
info.Create().Render(basePlayer);
}
}
void RenderEmailApp(BasePlayer basePlayer) {
var main = new EZUI.BoxComponent("Container") {
Transparent = true
}
.Tag(EMAIL_APP.Id).Create(AppComponent);
var button = new EZUI.ButtonComponent("Compose") {
Text = $"{Lang("email.compose", basePlayer)}", PixelHeight = 15, PixelWidth = 70, TextAlign = TextAnchor.MiddleCenter, AnchorTo = EZUI.Anchor.TopLeft, BackgroundColor = EZUI.StyleSheet.DEFAULT.BackgroundColorDark1, Command = $"ezui.call {EZUI.Token} RenderEmailCompose {basePlayer.UserIDString}", PixelMargin = new EZUI.Dir<int>(0, 0, 5, 0), OutlinePixelWeight = 1
}
.Create(main);
var header = new EZUI.BoxComponent("Header") {
PixelHeight = 30, TopAlign = button.BottomSide.Pixels, PixelPadding = new EZUI.Dir<int>(5), PixelMargin = new EZUI.Dir<int>(0, 0, 5, 0)
}
.Create(main);
var h1 = new EZUI.TextComponent("H1") {
Text = $"{Lang("email.unread", basePlayer)}", AutoSizeWidth = true, Right = 0
}
.Create(header);
var h2 = new EZUI.TextComponent("H2") {
Text = $"{Lang("email.from", basePlayer)}", AutoSizeWidth = true, Right = 100
}
.Create(header);
var h3 = new EZUI.TextComponent("H3") {
Text = $"{Lang("email.subject", basePlayer)}", AutoSizeWidth = true, Right = 250
}
.Create(header);
var h4 = new EZUI.TextComponent("H4") {
Text = $"{Lang("email.received", basePlayer)}", AutoSizeWidth = true, Right = 550
}
.Create(header);
var pag = new EZUI.PaginatorComponent("Paginator") {
AnchorTo = EZUI.Anchor.BottomLeft, PixelHeight = 25, OutlinePixelWeight = 1, PixelMargin = new EZUI.Dir<int>(5, 0, 0, 0)
}
.Create(main).As<EZUI.PaginatorComponent>();
var body = new EZUI.BoxComponent("Body") {
TopAlign = header.BottomSide.Pixels, BottomAlign = pag.TopSide.Pixels, OutlinePixelWeight = 1, BackgroundColor = EZUI.Color.WHITE
}
.Create(main);
var status = new EZUI.TextComponent("Status") {
AnchorTo = EZUI.Anchor.BottomLeft, PixelPadding = new EZUI.Dir<int>(5), FontSize = 10, Text = StatusText(basePlayer), Width = 0.5f, PixelHeight = 25
}
.Tag(EMAIL_APP).Create(body);
var info = new EZUI.TextComponent("Info") {
AnchorTo = EZUI.Anchor.BottomRight, PixelPadding = new EZUI.Dir<int>(5), FontSize = 10, Text = string.Empty, TextAlign = TextAnchor.MiddleRight, PixelHeight = 25, Width = 0.5f,
}
.Tag(EMAIL_APP).Create(body);
var inbox = new EZUI.LayoutComponent("Inbox") {
RowCount = 8, ColCount = 1, EntryPixelPadding = new EZUI.Dir<int>(5), BottomAlign = status.TopSide.Pixels
}
.Tag(EMAIL_APP.Id).As<EZUI.LayoutComponent>().SetPaginator(pag).Create(body).As<EZUI.LayoutComponent>();
inbox = UpdateInbox(basePlayer, inbox);
main.Render(basePlayer);
pag.UpdatePageAndRender(basePlayer, 1);
}
#endregion
#region Commands
[Command("email.clear"), Permission(PermissionAdmin)]
// email.clear <username>
private void cmd_email_clear(IPlayer player, string command, string[] args) {
if (args.Length == 1) {
var username = args[0];
var target = players.FindPlayer(username);
if (target != null) {
EmailManager.ClearPlayerInbox(target.Id);
player.Reply(Lang("email.cleared", player.Id, target.Name));
return;
}
}
player.Reply(Lang("email.usage.clear", player.Id));
}
#endregion
}
}
namespace Oxide.Plugins {
partial class ComputersPlus {
private static class EmailManager {
private static Dictionary<string, List<EmailMessage>> EmailMessages = new Dictionary<string, List<EmailMessage>>();
public static int MaxInboxSize {
get;
set;
}
= 24;
public static int SendEmail(EmailMessage email) {
if (EmailMessages.ContainsKey(email.RecipientStringId)) {
if (EmailMessages[email.RecipientStringId].Count < MaxInboxSize) {
EmailMessages[email.RecipientStringId].Add(email);
return 1;
}
}
else {
EmailMessages.Add(email.RecipientStringId, new List<EmailMessage>() {
email
}
);
return 1;
}
return 0;
}
public static void SetAllEmails(Dictionary<string, List<EmailMessage>> emailMessages) {
EmailMessages = emailMessages;
}
public static Dictionary<string, List<EmailMessage>> GetAllEmails() {
return EmailMessages;
}
public static EmailMessage[] GetPlayerInbox(string userIdString) {
if (EmailMessages.ContainsKey(userIdString)) {
return EmailMessages[userIdString].Reverse<EmailMessage>().ToArray();
}
else {
return new EmailMessage[] {
}
;
}
}
public static int GetPlayerInboxCount(string userIdString) {
if (EmailMessages.ContainsKey(userIdString)) {
return EmailMessages[userIdString].Count;
}
else {
return 0;
}
}
public static void ClearPlayerInbox(string userIdString) {
if (EmailMessages.ContainsKey(userIdString)) {
EmailMessages.Remove(userIdString);
}
}
public static void DeleteEmail(string userIdString, Guid emailGuid) {
if (EmailMessages.ContainsKey(userIdString)) {
EmailMessages[userIdString].RemoveAll(x => x.Guid == emailGuid);
}
}
public static EmailMessage GetEmail(string userIdString, Guid emailGuid) {
if (EmailMessages.ContainsKey(userIdString)) {
return EmailMessages[userIdString].Where(x => x.Guid == emailGuid).FirstOrDefault();
}
else {
return null;
}
}
}
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
[Serializable]
private class EmailMessage {
public EmailMessage(string composerStringId, string recipientStringId, string subject, string text) {
Guid = Guid.NewGuid();
Unread = true;
Subject = subject;
ComposerStringId = composerStringId;
RecipientStringId = recipientStringId;
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Text = text;
}
public Guid Guid {
get;
set;
}
public bool Unread {
get;
set;
}
public string Subject {
get;
set;
}
public string ComposerStringId {
get;
set;
}
public string RecipientStringId {
get;
set;
}
public long Timestamp {
get;
set;
}
public string Text {
get;
set;
}
[JsonIgnore]
public string ComposerDisplayName {
get {
return BasePlayer.FindAwakeOrSleeping(ComposerStringId)?.displayName;
}
}
[JsonIgnore]
public string RecipientDisplayName {
get {
return BasePlayer.FindAwakeOrSleeping(RecipientStringId)?.displayName;
}
}
public void MarkAsRead() {
this.Unread = false;
}
public string ElapsedTimeString(BasePlayer basePlayer) {
var elapsed = TimeSpan.FromSeconds(DateTimeOffset.Now.ToUnixTimeSeconds() - Timestamp);
if (elapsed.TotalDays >= 1) {
return $"{(int)Math.Floor(elapsed.TotalDays)} {PLUGIN.Lang("email.days", basePlayer)}";
}
else if (elapsed.TotalHours >= 1) {
return $"{(int)Math.Floor(elapsed.TotalHours)} {PLUGIN.Lang("email.hours", basePlayer)}";
}
else if (elapsed.TotalMinutes >= 1) {
return $"{(int)Math.Floor(elapsed.TotalMinutes)} {PLUGIN.Lang("email.minutes", basePlayer)}";
}
else {
return $"{PLUGIN.Lang("email.now", basePlayer)}";
}
}
}
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
public static partial class EZUI {
public class BasicComponent : Component {
public BasicComponent(string id) : base(id) {
}
protected override Component CreateHelper() {
return this;
}
public override Component Inherit(Component from, bool recursive = false) {
this.BackgroundColor = from.BackgroundColor;
this.PixelHeight = from.PixelHeight;
this.PixelWidth = from.PixelWidth;
this.PixelX = from.PixelX;
this.PixelY = from.PixelY;
this.PixelPadding = from.PixelPadding;
this.PixelMargin = from.PixelMargin;
return recursive ? base.Inherit(from) : this;
}
}
}
}
}
namespace Oxide.Plugins {
partial class ComputersPlus : CovalencePlugin {
public static partial class EZUI {
private interface IBoxComponent {
Color OutlineColor {
get;
set;
}
int OutlinePixelWeight {
get;
set;
}
}
public class BoxComponent : Component, IBoxComponent {
public BoxComponent(string id) : base(id) {
}
public override Color BackgroundColor {
get;
set;
}
= StyleSheet.DEFAULT.BackgroundColorLight1;
public Color Outl
// ... [Code preview truncated due to length. Full source in attached file] ...